Class: DeadEnd::ExplainSyntax

Inherits:
Object
  • Object
show all
Defined in:
lib/dead_end/explain_syntax.rb

Overview

Explains syntax errors based on their source

example:

source = "def foo; puts 'lol'" # Note missing end
explain ExplainSyntax.new(
  code_lines: CodeLine.from_source(source)
).call
explain.errors.first
# => "Unmatched keyword, missing `end' ?"

When the error cannot be determined by lexical counting then ripper is run against the input and the raw ripper errors returned.

Example:

source = "1 * " # Note missing a second number
explain ExplainSyntax.new(
  code_lines: CodeLine.from_source(source)
).call
explain.errors.first
# => "syntax error, unexpected end-of-input"

Constant Summary collapse

INVERSE =
{
  "{" => "}",
  "}" => "{",
  "[" => "]",
  "]" => "[",
  "(" => ")",
  ")" => "(",
  "|" => "|"
}.freeze

Instance Method Summary collapse

Constructor Details

#initialize(code_lines:) ⇒ ExplainSyntax

Returns a new instance of ExplainSyntax.



40
41
42
43
44
# File 'lib/dead_end/explain_syntax.rb', line 40

def initialize(code_lines:)
  @code_lines = code_lines
  @left_right = LeftRightLexCount.new
  @missing = nil
end

Instance Method Details

#callObject



46
47
48
49
50
51
52
53
54
# File 'lib/dead_end/explain_syntax.rb', line 46

def call
  @code_lines.each do |line|
    line.lex.each do |lex|
      @left_right.count_lex(lex)
    end
  end

  self
end

#errorsObject

Returns an array of syntax error messages

If no missing pairs are found it falls back on the original ripper error messages



95
96
97
98
99
100
101
# File 'lib/dead_end/explain_syntax.rb', line 95

def errors
  if missing.empty?
    return RipperErrors.new(@code_lines.map(&:original).join).call.errors
  end

  missing.map { |miss| why(miss) }
end

#missingObject

Returns an array of missing elements

For example this:

ExplainSyntax.new(code_lines: lines).missing
# => ["}"]

Would indicate that the source is missing a ‘}` character in the source code



65
66
67
# File 'lib/dead_end/explain_syntax.rb', line 65

def missing
  @missing ||= @left_right.missing
end

#why(miss) ⇒ Object

Converts a missing string to an human understandable explanation.

Example:

explain.why("}")
# => "Unmatched `{', missing `}' ?"


77
78
79
80
81
82
83
84
85
86
87
88
89
# File 'lib/dead_end/explain_syntax.rb', line 77

def why(miss)
  case miss
  when "keyword"
    "Unmatched `end', missing keyword (`do', `def`, `if`, etc.) ?"
  when "end"
    "Unmatched keyword, missing `end' ?"
  else
    inverse = INVERSE.fetch(miss) {
      raise "Unknown explain syntax char or key: #{miss.inspect}"
    }
    "Unmatched `#{inverse}', missing `#{miss}' ?"
  end
end