Class: Tailor::LexedLine
- Inherits:
-
Array
- Object
- Array
- Tailor::LexedLine
- Includes:
- LexerConstants
- Defined in:
- lib/tailor/lexed_line.rb
Overview
This class provides methods for finding info about the current line. It works off the format that results from Lexer.
Constant Summary
Constants included from LexerConstants
Tailor::LexerConstants::CONTINUATION_KEYWORDS, Tailor::LexerConstants::KEYWORDS_AND_MODIFIERS, Tailor::LexerConstants::KEYWORDS_TO_INDENT, Tailor::LexerConstants::LOOP_KEYWORDS, Tailor::LexerConstants::MODIFIERS, Tailor::LexerConstants::MULTILINE_OPERATORS
Instance Method Summary collapse
- #comment_line? ⇒ Boolean
-
#contains_keyword_to_indent? ⇒ Boolean
true
if the line contains an keyword and it is in +KEYWORDS_TO_INDENT. - #current_line_lex(lexed_output, lineno) ⇒ Array
- #does_line_end_with(event, exclude_newlines = true) ⇒ Boolean
-
#end_of_multi_line_string? ⇒ Boolean
Determines if the current lexed line is just the end of a tstring.
-
#ends_with_modifier_kw? ⇒ Boolean
Checks to see if the line ends with a keyword, and that the keyword is used as a modifier.
-
#ends_with_op? ⇒ Boolean
Checks to see if the current line ends with an operator (not counting the newline that might come after it).
-
#event_at(column) ⇒ Array
The event at the given column.
-
#event_index(column) ⇒ Fixnum
Useful for inspecting events relevant to this one.
-
#first_non_space_element ⇒ Array
Gets the first non-space element from a line of lexed output.
-
#initialize(lexed_file, lineno) ⇒ LexedLine
constructor
A new instance of LexedLine.
-
#is_line_only_a(event) ⇒ Boolean
Checks to see if the line contains only
event
(where it may or may not be preceded by spaces, and is proceeded by a newline). -
#keyword_is_symbol? ⇒ Boolean
When Ripper lexes a Symbol, it generates one event for :on_symbeg, which is the ‘:’ token, and one for the name of the Symbol.
-
#last_non_line_feed_event ⇒ Array
The lexed event that represents the last event in the line that’s not a line-feed.
-
#line_length ⇒ Fixnum
The length of the line minus the
\n
. -
#loop_with_do? ⇒ Boolean
Checks to see if the current line is a keyword loop (for, while, until) that uses the optional ‘do’ at the end of the statement.
-
#method_missing(meth, *args, &blk) ⇒ Object
Allows for calling a couple styles of methods: * #ends_with_(.+)? - Allows for checking if the line ends with (.+) * #only_(.+)? - Allows for checking if the line is only spaces and (.+).
-
#only_spaces? ⇒ Boolean
Looks at self and determines if it’ s a line of just space characters: spaces, newlines.
-
#remove_trailing_comment(file_text) ⇒ LexedLine
If a trailing comment exists in the line, remove it and the spaces that come before it.
-
#to_s ⇒ String
The string reassembled from self’s tokens.
Constructor Details
#initialize(lexed_file, lineno) ⇒ LexedLine
Returns a new instance of LexedLine.
13 14 15 16 |
# File 'lib/tailor/lexed_line.rb', line 13 def initialize(lexed_file, lineno) @lineno = lineno super(current_line_lex(lexed_file, lineno)) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(meth, *args, &blk) ⇒ Object
Allows for calling a couple styles of methods:
-
#ends_with_(.+)? - Allows for checking if the line ends with (.+)
-
#only_(.+)? - Allows for checking if the line is only spaces and (.+)
106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 |
# File 'lib/tailor/lexed_line.rb', line 106 def method_missing(meth, *args, &blk) if meth.to_s =~ /^ends_with_(.+)\?$/ event = "on_#{$1}".to_sym if event == :on_ignored_nl || event == :on_nl does_line_end_with(event, false) else does_line_end_with event end elsif meth.to_s =~ /^only_(.+)\?$/ event = "on_#{$1}".to_sym is_line_only_a(event) else super(meth, *args, &blk) end end |
Instance Method Details
#comment_line? ⇒ Boolean
35 36 37 |
# File 'lib/tailor/lexed_line.rb', line 35 def comment_line? first_non_space_element[1] == :on_comment end |
#contains_keyword_to_indent? ⇒ Boolean
Returns true
if the line contains an keyword and it is in +KEYWORDS_TO_INDENT.
147 148 149 150 151 |
# File 'lib/tailor/lexed_line.rb', line 147 def contains_keyword_to_indent? self.any? do |e| e[1] == :on_kw && KEYWORDS_TO_INDENT.include?(e[2]) end end |
#current_line_lex(lexed_output, lineno) ⇒ Array
20 21 22 |
# File 'lib/tailor/lexed_line.rb', line 20 def current_line_lex(lexed_output, lineno) lexed_output.find_all { |token| token.first.first == lineno }.uniq end |
#does_line_end_with(event, exclude_newlines = true) ⇒ Boolean
76 77 78 79 80 81 82 83 84 85 86 |
# File 'lib/tailor/lexed_line.rb', line 76 def does_line_end_with(event, exclude_newlines=true) if exclude_newlines if last_non_line_feed_event.first.empty? false else last_non_line_feed_event[1] == event end else self.last[1] == :on_ignored_nl || self.last[1] == :on_nl end end |
#end_of_multi_line_string? ⇒ Boolean
Determines if the current lexed line is just the end of a tstring.
239 240 241 242 |
# File 'lib/tailor/lexed_line.rb', line 239 def end_of_multi_line_string? self.any? { |e| e[1] == :on_tstring_end } && self.none? { |e| e[1] == :on_tstring_beg } end |
#ends_with_modifier_kw? ⇒ Boolean
Checks to see if the line ends with a keyword, and that the keyword is used as a modifier.
66 67 68 69 70 71 72 73 |
# File 'lib/tailor/lexed_line.rb', line 66 def ends_with_modifier_kw? return false unless ends_with_kw? token = Tailor::Lexer::Token.new(last.last, { full_line_of_text: to_s }) token.modifier_keyword? end |
#ends_with_op? ⇒ Boolean
Checks to see if the current line ends with an operator (not counting the newline that might come after it).
43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 |
# File 'lib/tailor/lexed_line.rb', line 43 def ends_with_op? lexed_line = self.dup tokens_in_line = lexed_line.map { |e| e[1] } until tokens_in_line.last != (:on_ignored_nl || :on_nl) tokens_in_line.pop lexed_line.pop end return false if lexed_line.empty? if MULTILINE_OPERATORS.include?(lexed_line.last.last) && tokens_in_line.last == :on_op true else false end end |
#event_at(column) ⇒ Array
Returns The event at the given column.
177 178 179 |
# File 'lib/tailor/lexed_line.rb', line 177 def event_at(column) self.find { |e| e.first.last == column } end |
#event_index(column) ⇒ Fixnum
Useful for inspecting events relevant to this one.
189 190 191 192 |
# File 'lib/tailor/lexed_line.rb', line 189 def event_index(column) column_event = self.event_at column self.index(column_event) end |
#first_non_space_element ⇒ Array
Gets the first non-space element from a line of lexed output.
126 127 128 129 130 |
# File 'lib/tailor/lexed_line.rb', line 126 def first_non_space_element self.find do |e| e[1] != :on_sp && e[1] != :on_nl && e[1] != :on_ignored_nl end end |
#is_line_only_a(event) ⇒ Boolean
Checks to see if the line contains only event
(where it may or may not be preceded by spaces, and is proceeded by a newline).
93 94 95 96 97 98 99 100 101 |
# File 'lib/tailor/lexed_line.rb', line 93 def is_line_only_a(event) last_event = last_non_line_feed_event return false if last_event[1] != event index = event_index(last_event.first.last) previous_event = self.at(index - 1) previous_event.first.last.zero? || previous_event.first.last.nil? end |
#keyword_is_symbol? ⇒ Boolean
When Ripper lexes a Symbol, it generates one event for :on_symbeg, which is the ‘:’ token, and one for the name of the Symbol. Since your Symbol name can be anything, the second event could be something like “class”, in which case :on_kw will get called and probably result in unexpected behavior.
This assumes the keyword in question is the last event in the line.
253 254 255 256 257 258 259 260 261 262 |
# File 'lib/tailor/lexed_line.rb', line 253 def keyword_is_symbol? current_index = self.index(self.last) previous_event = self.at(current_index - 1) return false if previous_event.nil? return false unless self.last[1] == :on_kw return false unless previous_event[1] == :on_symbeg true end |
#last_non_line_feed_event ⇒ Array
Returns The lexed event that represents the last event in the line that’s not a line-feed. Line-feed events are signified by :on_nl
and on_ignored_nl
events, and by :on_sp
events when they equal +“\n” (which occurs when a line is broken by a backslash).
157 158 159 160 161 162 163 164 165 |
# File 'lib/tailor/lexed_line.rb', line 157 def last_non_line_feed_event events = self.find_all do |e| e[1] != :on_nl && e[1] != :on_ignored_nl && e.last != "\\\n" end events.last || [[]] end |
#line_length ⇒ Fixnum
Returns The length of the line minus the \n
.
168 169 170 171 172 173 |
# File 'lib/tailor/lexed_line.rb', line 168 def line_length event = last_non_line_feed_event return 0 if event.first.empty? event.first.last + event.last.size end |
#loop_with_do? ⇒ Boolean
Checks to see if the current line is a keyword loop (for, while, until) that uses the optional ‘do’ at the end of the statement.
136 137 138 139 140 141 142 143 |
# File 'lib/tailor/lexed_line.rb', line 136 def loop_with_do? keyword_elements = self.find_all { |e| e[1] == :on_kw } keyword_tokens = keyword_elements.map { |e| e.last } loop_start = keyword_tokens.any? { |t| LOOP_KEYWORDS.include? t } with_do = keyword_tokens.any? { |t| t == 'do' } loop_start && with_do end |
#only_spaces? ⇒ Boolean
Looks at self and determines if it’ s a line of just space characters: spaces, newlines.
28 29 30 31 32 |
# File 'lib/tailor/lexed_line.rb', line 28 def only_spaces? element = first_non_space_element log "first non-space element '#{element}'" element.nil? || element.empty? end |
#remove_trailing_comment(file_text) ⇒ LexedLine
If a trailing comment exists in the line, remove it and the spaces that come before it. This is necessary, as Ripper
doesn’t trigger an event for the end of the line when the line ends with a comment. Without this observers that key off ending the line will never get triggered, and thus style won’t get checked for that line.
209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 |
# File 'lib/tailor/lexed_line.rb', line 209 def remove_trailing_comment(file_text) file_lines = file_text.split("\n") lineno = self.last.first.first column = self.last.first.last log "Removing comment event at #{lineno}:#{column}." comment_index = event_index(column) self.delete_at(comment_index) self.insert(comment_index, [[lineno, column], :on_nl, "\n"]) log "Inserted newline for comma; self is now #{self.inspect}" if self.at(comment_index - 1)[1] == :on_sp self.delete_at(comment_index - 1) end new_text = self.to_s log "New line as text: '#{new_text}'" file_lines.delete_at(lineno - 1) file_lines.insert(lineno - 1, new_text) file_lines = file_lines.join("\n") ripped_output = ::Ripper.lex(file_lines) LexedLine.new(ripped_output, lineno) end |
#to_s ⇒ String
Returns The string reassembled from self’s tokens.
195 196 197 |
# File 'lib/tailor/lexed_line.rb', line 195 def to_s self.inject('') { |new_string, e| new_string << e.last } end |