Class: SeeingIsBelieving::SyntaxAnalyzer

Inherits:
Ripper::SexpBuilder
  • Object
show all
Defined in:
lib/seeing_is_believing/syntax_analyzer.rb

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.begin_and_end_comments_are_complete?(code) ⇒ Boolean

Returns:

  • (Boolean)


63
64
65
66
67
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 63

def self.begin_and_end_comments_are_complete?(code)
  code.scan(/^=(?:begin|end)$/)
      .each_slice(2)
      .all? { |b, e| b == '=begin' && e == '=end' }
end

.begins_data_segment?(line) ⇒ Boolean

MISC

Returns:

  • (Boolean)


79
80
81
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 79

def self.begins_data_segment?(line)
  line == '__END__'
end

.begins_multiline_comment?(line) ⇒ Boolean

Returns:

  • (Boolean)


55
56
57
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 55

def self.begins_multiline_comment?(line)
  line == '=begin'
end

.ends_in_comment?(code) ⇒ Boolean

Returns:

  • (Boolean)


141
142
143
144
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 141

def self.ends_in_comment?(code)
  # must do the newline hack or it totally fucks up on comments like "# Transfer-Encoding: chunked"
  code =~ /^=end\Z/ || parsed("\n#{code.lines.to_a.last.to_s}").has_comment?
end

.ends_multiline_comment?(line) ⇒ Boolean

Returns:

  • (Boolean)


59
60
61
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 59

def self.ends_multiline_comment?(line)
  line == '=end'
end

.here_doc?(code) ⇒ Boolean

HERE DOCS

Returns:

  • (Boolean)


181
182
183
184
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 181

def self.here_doc?(code)
  instance = parsed code
  instance.has_heredoc? && code.scan("\n").size.next <= instance.here_doc_last_line_number
end

.line_is_comment?(line) ⇒ Boolean

COMMENTS

Returns:

  • (Boolean)


137
138
139
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 137

def self.line_is_comment?(line)
  line =~ /^\s*#/
end

.next_line_modifies_current?(line) ⇒ Boolean

Returns:

  • (Boolean)


83
84
85
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 83

def self.next_line_modifies_current?(line)
  line =~ /^\s*\./
end

.parsed(code) ⇒ Object

HELPERS



9
10
11
12
13
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 9

def self.parsed(code)
  instance = new code
  instance.parse
  instance
end

.unclosed_comment?(code) ⇒ Boolean

Returns:

  • (Boolean)


146
147
148
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 146

def self.unclosed_comment?(code)
  !begin_and_end_comments_are_complete?(code)
end

.unclosed_regexp?(code) ⇒ Boolean

REGEXPS

Returns:

  • (Boolean)


113
114
115
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 113

def self.unclosed_regexp?(code)
  parsed(code).unclosed_regexp?
end

.unclosed_string?(code) ⇒ Boolean

STRINGS

Returns:

  • (Boolean)


89
90
91
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 89

def self.unclosed_string?(code)
  parsed(code).unclosed_string?
end

.unfinished_here_doc?(code) ⇒ Boolean

Returns:

  • (Boolean)


186
187
188
189
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 186

def self.unfinished_here_doc?(code)
  instance = parsed code
  instance.heredocs.any? { |heredoc| heredoc.size == 1 }
end

.valid_ruby?(code) ⇒ Boolean

Returns:

  • (Boolean)


51
52
53
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 51

def self.valid_ruby?(code)
  parsed(code).valid_ruby? && begin_and_end_comments_are_complete?(code)
end

.void_value_expression?(code_or_ast) ⇒ Boolean

RETURNS

Returns:

  • (Boolean)


161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 161

def self.void_value_expression?(code_or_ast)
  ast = code_or_ast
  ast = Parser::CurrentRuby.parse(code_or_ast) if code_or_ast.kind_of? String

  case ast && ast.type
  when :begin, :kwbegin, :resbody # begin and kwbegin should be the same thing, but it changed in parser 1.4.1 to 2.0.0, so just adding them both for safety
    void_value_expression?(ast.children[-1])
  when :rescue, :ensure
    ast.children.any? { |child| void_value_expression? child }
  when :if
    void_value_expression?(ast.children[1]) || void_value_expression?(ast.children[2])
  when :return, :next, :redo, :retry, :break
    true
  else
    false
  end
end

Instance Method Details

#ends_match?(beginning, ending) ⇒ Boolean

We have to do this b/c Ripper sometimes calls on_tstring_end even when the string doesn’t get ended e.g. SyntaxAnalyzer.new(‘“a’).parse

Returns:

  • (Boolean)


17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 17

def ends_match?(beginning, ending)
  return false unless beginning && ending
  return beginning == ending if beginning.size == 1 && ending.size == 1
  case beginning[-1]
  when '<' then '>' == ending
  when '(' then ')' == ending
  when '[' then ']' == ending
  when '{' then '}' == ending
  when '/' then ending =~ /\A\// # example: /a/x
  else
    # example: %Q.a. %_a_ %r|a| ...
    beginning.start_with?('%') && beginning.end_with?(ending)
  end
end

#has_comment?Boolean

Returns:

  • (Boolean)


150
151
152
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 150

def has_comment?
  @has_comment
end

#has_heredoc?Boolean

Returns:

  • (Boolean)


208
209
210
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 208

def has_heredoc?
  heredocs.any?
end

#here_doc_last_line_numberObject



212
213
214
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 212

def here_doc_last_line_number
  heredocs.last.last
end

#heredocsObject



191
192
193
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 191

def heredocs
  @heredocs ||= []
end

#invalid_ruby?Boolean

Returns:

  • (Boolean)


73
74
75
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 73

def invalid_ruby?
  @has_error || unclosed_string? || unclosed_regexp?
end

#on_commentObject



154
155
156
157
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 154

def on_comment(*)
  @has_comment = true
  super
end

#on_heredoc_beg(beginning) ⇒ Object



195
196
197
198
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 195

def on_heredoc_beg(beginning)
  heredocs << [beginning]
  super
end

#on_heredoc_end(ending) ⇒ Object



200
201
202
203
204
205
206
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 200

def on_heredoc_end(ending)
  result      = super
  line_number = result.last.first
  doc = heredocs.find { |(beginning)| beginning.include? ending.strip }
  doc << ending << line_number
  result
end

#on_regexp_beg(beginning) ⇒ Object



121
122
123
124
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 121

def on_regexp_beg(beginning)
  regexp_opens.push beginning
  super
end

#on_regexp_end(ending) ⇒ Object



126
127
128
129
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 126

def on_regexp_end(ending)
  regexp_opens.pop if ends_match? regexp_opens.last, ending
  super
end

#on_tstring_beg(beginning) ⇒ Object



97
98
99
100
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 97

def on_tstring_beg(beginning)
  string_opens.push beginning
  super
end

#on_tstring_end(ending) ⇒ Object



102
103
104
105
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 102

def on_tstring_end(ending)
  string_opens.pop if ends_match? string_opens.last, ending
  super
end

#regexp_opensObject



117
118
119
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 117

def regexp_opens
  @regexp_opens ||= []
end

#string_opensObject



93
94
95
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 93

def string_opens
  @string_opens ||= []
end

#unclosed_regexp?Boolean

Returns:

  • (Boolean)


131
132
133
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 131

def unclosed_regexp?
  regexp_opens.any?
end

#unclosed_string?Boolean

Returns:

  • (Boolean)


107
108
109
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 107

def unclosed_string?
  string_opens.any?
end

#valid_ruby?Boolean

Returns:

  • (Boolean)


69
70
71
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 69

def valid_ruby?
  !invalid_ruby?
end