Class: SeeingIsBelieving::SyntaxAnalyzer
- Inherits:
-
Ripper::SexpBuilder
- Object
- Ripper::SexpBuilder
- SeeingIsBelieving::SyntaxAnalyzer
- Defined in:
- lib/seeing_is_believing/syntax_analyzer.rb
Class Method Summary collapse
- .begin_and_end_comments_are_complete?(code) ⇒ Boolean
-
.begins_data_segment?(line) ⇒ Boolean
MISC.
- .begins_multiline_comment?(line) ⇒ Boolean
- .ends_in_comment?(code) ⇒ Boolean
- .ends_multiline_comment?(line) ⇒ Boolean
-
.here_doc?(code) ⇒ Boolean
HERE DOCS.
-
.line_is_comment?(line) ⇒ Boolean
COMMENTS.
- .next_line_modifies_current?(line) ⇒ Boolean
-
.parsed(code) ⇒ Object
HELPERS.
- .unclosed_comment?(code) ⇒ Boolean
-
.unclosed_regexp?(code) ⇒ Boolean
REGEXPS.
-
.unclosed_string?(code) ⇒ Boolean
STRINGS.
- .unfinished_here_doc?(code) ⇒ Boolean
- .valid_ruby?(code) ⇒ Boolean
-
.void_value_expression?(code_or_ast) ⇒ Boolean
RETURNS.
Instance Method Summary collapse
-
#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.
- #has_comment? ⇒ Boolean
- #has_heredoc? ⇒ Boolean
- #here_doc_last_line_number ⇒ Object
- #heredocs ⇒ Object
- #invalid_ruby? ⇒ Boolean
- #on_comment ⇒ Object
- #on_heredoc_beg(beginning) ⇒ Object
- #on_heredoc_end(ending) ⇒ Object
- #on_regexp_beg(beginning) ⇒ Object
- #on_regexp_end(ending) ⇒ Object
- #on_tstring_beg(beginning) ⇒ Object
- #on_tstring_end(ending) ⇒ Object
- #regexp_opens ⇒ Object
- #string_opens ⇒ Object
- #unclosed_regexp? ⇒ Boolean
- #unclosed_string? ⇒ Boolean
- #valid_ruby? ⇒ Boolean
Class Method Details
.begin_and_end_comments_are_complete?(code) ⇒ 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
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
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
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
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
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
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
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
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
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
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
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
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
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
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
150 151 152 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 150 def has_comment? @has_comment end |
#has_heredoc? ⇒ Boolean
208 209 210 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 208 def has_heredoc? heredocs.any? end |
#here_doc_last_line_number ⇒ Object
212 213 214 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 212 def here_doc_last_line_number heredocs.last.last end |
#heredocs ⇒ Object
191 192 193 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 191 def heredocs @heredocs ||= [] end |
#invalid_ruby? ⇒ 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_comment ⇒ Object
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_opens ⇒ Object
117 118 119 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 117 def regexp_opens @regexp_opens ||= [] end |
#string_opens ⇒ Object
93 94 95 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 93 def string_opens @string_opens ||= [] end |
#unclosed_regexp? ⇒ Boolean
131 132 133 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 131 def unclosed_regexp? regexp_opens.any? end |
#unclosed_string? ⇒ Boolean
107 108 109 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 107 def unclosed_string? string_opens.any? end |
#valid_ruby? ⇒ Boolean
69 70 71 |
# File 'lib/seeing_is_believing/syntax_analyzer.rb', line 69 def valid_ruby? !invalid_ruby? end |