class 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 отображает все переданные ему строки, а не только видимые; для их получения он использует метод original.
Общедоступные методы класса
# 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 Возвращает массив объектов CodeLine из исходной строки
# 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
Оператор сравнения, необходимый для проверки равенства и сортировки
# File lib/syntax_suggest/code_line.rb, line 115 def empty? @empty end
Строка `empty?` — это строка, изначально оставленная пустой в исходном коде, тогда как «скрытая» строка — это строка, которую мы позднее пометили как «невидимую».
Противоположное `visible?` (примечание: отличается от `empty?`)
# File lib/syntax_suggest/code_line.rb, line 172 def ignore_newline_not_beg? @ignore_newline_not_beg 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 72 def indent_index @indent_index ||= [indent, index] end
Используется для стабильной сортировки по уровню отступа
Сортировка в Ruby не является «стабильной»: если несколько элементов имеют одинаковое значение, не гарантируется, что они будут возвращены в том же порядке, в котором были добавлены.
Поэтому, если у нескольких строк кода одинаковый уровень отступа, они сортируются по значению index, которое уникально и неизменно.
Это нужно главным образом для единообразия набора тестов.
# File lib/syntax_suggest/code_line.rb, line 87 def is_end? @is_end end
Возвращает true, если установлено, что строка кода содержит ключевое слово `end`.
# File lib/syntax_suggest/code_line.rb, line 81 def is_kw? @is_kw end
Возвращает true, если установлено, что строка кода содержит ключевое слово, которому соответствует `end`.
Например: `def`, `do`, `begin`, `ensure` и т. д.
# File lib/syntax_suggest/code_line.rb, line 96 def mark_invisible @line = "" end
Используется для скрытия строк
Алгоритм поиска группирует строки в блоки, а затем скрывает блоки, которые, как установлено, представляют собой корректный код.
# File lib/syntax_suggest/code_line.rb, line 120 def not_empty? !empty? end
Противоположное `empty?` (примечание: отличается от `visible?`)
# File lib/syntax_suggest/code_line.rb, line 133 def to_s line end
Возвращает заданную строку в виде текста
Также позволяет представлять исходный код как массив строк кода.
Если вызвать `join` для массива элементов строк кода, для каждого элемента будет вызван `to_s`, что фактически преобразует массив обратно в исходную строку.
# File lib/syntax_suggest/code_line.rb, line 184 def trailing_slash? last = @lex.last last&.type == :on_tstring_end end
# File lib/syntax_suggest/code_line.rb, line 103 def visible? !line.empty? end
Означает, что строка не была помечена как «невидимая». Как ни странно, «пустые» строки видимы… в них просто нет исходного кода, кроме символа новой строки («n»).
Приватные методы экземпляра
# 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 Обнаружение методов без тела
Из github.com/ruby/irb/commit/826ae909c9c93a2ddca6f9cfcd9c94dbf53d44ab. Для обнаружения «однострочного выражения», по-видимому, требуется конечный автомат. В основном это можно сделать, анализируя «состояние» (последнее значение):
ENDFN -> BEG (token = '=' ) -> END
Ruby Core © 1993–2025 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.