Spec-Zone.ru › Ruby 4.0
  1. SyntaxSuggest::
  2. CodeLine

class SyntaxSuggest::CodeLine

Родительский класс:
Object

Представляет одну строку кода заданного исходного файла

Этот объект содержит метаданные о строке, такие как уровень отступа, пуста она или нет, а также лексические данные, например, содержит ли она `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

Атрибуты

indent [R]
index [R]
lex [R]
line [R]
line_number [R]
number [R]
original [R]

Когда строка кода помечена как невидимая, сохраняется её исходное значение. Это полезно для отладки и отображения дополнительного контекста.

DisplayCodeWithLineNumbers отображает все переданные ему строки, а не только видимые; для их получения он использует метод original.

Общедоступные методы класса

from_source (source, lines: nil) Показать исходный код
# 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 из исходной строки

new (line:, index:, lex:) Показать исходный код
# 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

Общедоступные методы экземпляра

<=> (other) Показать исходный код
# 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

Строка `empty?` — это строка, изначально оставленная пустой в исходном коде, тогда как «скрытая» строка — это строка, которую мы позднее пометили как «невидимую».

hidden? () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 108
def hidden?
  !visible?
end

Противоположное `visible?` (примечание: отличается от `empty?`)

ignore_newline_not_beg? () Показать исходный код
# 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.

indent_index () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 72
def indent_index
  @indent_index ||= [indent, index]
end

Используется для стабильной сортировки по уровню отступа

Сортировка в Ruby не является «стабильной»: если несколько элементов имеют одинаковое значение, не гарантируется, что они будут возвращены в том же порядке, в котором были добавлены.

Поэтому, если у нескольких строк кода одинаковый уровень отступа, они сортируются по значению index, которое уникально и неизменно.

Это нужно главным образом для единообразия набора тестов.

is_end? () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 87
def is_end?
  @is_end
end

Возвращает true, если установлено, что строка кода содержит ключевое слово `end`.

is_kw? () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 81
def is_kw?
  @is_kw
end

Возвращает true, если установлено, что строка кода содержит ключевое слово, которому соответствует `end`.

Например: `def`, `do`, `begin`, `ensure` и т. д.

mark_invisible () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 96
def mark_invisible
  @line = ""
end

Используется для скрытия строк

Алгоритм поиска группирует строки в блоки, а затем скрывает блоки, которые, как установлено, представляют собой корректный код.

not_empty? () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 120
def not_empty?
  !empty?
end

Противоположное `empty?` (примечание: отличается от `visible?`)

to_s () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 133
def to_s
  line
end

Возвращает заданную строку в виде текста

Также позволяет представлять исходный код как массив строк кода.

Если вызвать `join` для массива элементов строк кода, для каждого элемента будет вызван `to_s`, что фактически преобразует массив обратно в исходную строку.

trailing_slash? () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 184
def trailing_slash?
  last = @lex.last
  last&.type == :on_tstring_end
end
visible? () Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 103
def visible?
  !line.empty?
end

Означает, что строка не была помечена как «невидимая». Как ни странно, «пустые» строки видимы… в них просто нет исходного кода, кроме символа новой строки («n»).

Приватные методы экземпляра

set_kw_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

Обнаружение методов без тела

Из 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.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API