類別 SyntaxSuggest::CodeLine
表示給定原始檔單一程式碼行
此物件包含有關該行的元資料,例如縮排量、是否為空行,以及詞彙資料,例如是否包含「end」或關鍵字。
可以切換行的可見性。將行標記為不可見表示不應將其用於語法檢查。這在功能上與將其註解掉相同。
範例
line = CodeLine.from_source("def foo\n").first line.number => 1 line.empty? # => false line.visible? # => true line.mark_invisible line.visible? # => false
常數
- TRAILING_SLASH
屬性
當程式碼行標記為不可見時,我們會保留其行的原始值,這對於偵錯和顯示額外內容很有用
DisplayCodeWithLineNumbers
會呈現給它的所有行,不只是可見行,它使用原始方法來取得這些行。
公開類別方法
從原始碼字串傳回 CodeLine
物件陣列
# File lib/syntax_suggest/code_line.rb, line 29 def self.from_source(source, lines: nil) lines ||= source.lines lex_array_for_line = LexAll.new(source: source, source_lines: lines).each_with_object(Hash.new { |h, k| h[k] = [] }) { |lex, hash| hash[lex.line] << lex } lines.map.with_index do |line, index| CodeLine.new( line: line, index: index, lex: lex_array_for_line[index + 1] ) end end
# File lib/syntax_suggest/code_line.rb, line 42 def initialize(line:, index:, lex:) @lex = lex @line = line @index = index @original = line @line_number = @index + 1 strip_line = line.dup strip_line.lstrip! @indent = if (@empty = strip_line.empty?) line.length - 1 # Newline removed from strip_line is not "whitespace" else line.length - strip_line.length end set_kw_end end
公開實例方法
比較運算子,等號和排序需要
# File lib/syntax_suggest/code_line.rb, line 150 def <=>(other) index <=> other.index end
「empty?」列是原始程式碼中原本留空的列,而「隱藏」列則是我们標記為「不可見」的列
# File lib/syntax_suggest/code_line.rb, line 115 def empty? @empty end
- 不穩定的 API
-
具有「on_ignored_nl」類型標記且沒有「BEG」類型的列,似乎可以很好地作為將多個列合併為一列的功能代理。
此謂詞方法用於確定是否已符合這兩個條件。
已知無法處理的一個案例是
Ripper.lex <<~EOM a && b || c EOM
由於某種原因,這會引入「on_ignore_newline」,但類型為 BEG
# File lib/syntax_suggest/code_line.rb, line 172 def ignore_newline_not_beg? @ignore_newline_not_beg end
用於透過縮排層級進行穩定排序
Ruby 的排序並不「穩定」,表示當多個元素具有相同值時,無法保證它們會以放入的順序返回。
因此,當多個程式碼列具有相同的縮排層級時,它們會按其唯一且一致的索引值排序。
這主要是為了測試套件的一致性
# File lib/syntax_suggest/code_line.rb, line 72 def indent_index @indent_index ||= [indent, index] end
如果確定程式碼列包含「end」關鍵字,則傳回 true
# File lib/syntax_suggest/code_line.rb, line 87 def is_end? @is_end end
如果確定程式碼列包含與「end」相符的關鍵字,則傳回 true
例如:「def」、「do」、「begin」、「ensure」等。
# File lib/syntax_suggest/code_line.rb, line 81 def is_kw? @is_kw end
用於隱藏行
搜尋演算法會將行分組成區塊,然後如果判定這些區塊代表有效的程式碼,就會將它們隱藏
# File lib/syntax_suggest/code_line.rb, line 96 def mark_invisible @line = "" end
與「empty?」相反(注意:與「visible?」不同)
# File lib/syntax_suggest/code_line.rb, line 120 def not_empty? !empty? end
呈現指定的行
也允許我們將原始碼表示為程式碼行的陣列。
當我們有一個程式碼行元素的陣列時,在陣列上呼叫「join」會在每個元素上呼叫「to_s」,這基本上將它轉換回其原始來源字串。
# File lib/syntax_suggest/code_line.rb, line 133 def to_s line end
# File lib/syntax_suggest/code_line.rb, line 184 def trailing_slash? last = @lex.last last&.type == :on_tstring_end end
表示該行已標記為「invisible」。令人困惑的是,「empty」行是可見的…它們只是不包含任何原始碼,只包含換行符號(「n」)。
# File lib/syntax_suggest/code_line.rb, line 103 def visible? !line.empty? end
私有實例方法
無限方法偵測
來自 github.com/ruby/irb/commit/826ae909c9c93a2ddca6f9cfcd9c94dbf53d44ab 偵測「oneliner」似乎需要一個狀態機。這可以透過主要查看「狀態」(最後一個值)來完成
ENDFN -> BEG (token = '=' ) -> END
# File lib/syntax_suggest/code_line.rb, line 206 def set_kw_end oneliner_count = 0 in_oneliner_def = nil kw_count = 0 end_count = 0 @ignore_newline_not_beg = false @lex.each do |lex| kw_count += 1 if lex.is_kw? end_count += 1 if lex.is_end? if lex.type == :on_ignored_nl @ignore_newline_not_beg = !lex.expr_beg? end if in_oneliner_def.nil? in_oneliner_def = :ENDFN if lex.state.allbits?(Ripper::EXPR_ENDFN) elsif lex.state.allbits?(Ripper::EXPR_ENDFN) # Continue elsif lex.state.allbits?(Ripper::EXPR_BEG) in_oneliner_def = :BODY if lex.token == "=" elsif lex.state.allbits?(Ripper::EXPR_END) # We found an endless method, count it oneliner_count += 1 if in_oneliner_def == :BODY in_oneliner_def = nil else in_oneliner_def = nil end end kw_count -= oneliner_count @is_kw = (kw_count - end_count) > 0 @is_end = (end_count - kw_count) > 0 end