Spec-Zone.ru › Ruby 3.4

класс 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

Атрибуты

indent [Только для чтения]
index [Только для чтения]
lex [Только для чтения]
line [Только для чтения]
line_number [Только для чтения]
number [Только для чтения]
original [Только для чтения]

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

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

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

hidden? ()
Исходный код
# File lib/syntax_suggest/code_line.rb, line 108
def hidden?
  !visible?
end

Противоположность или «видимая?» (примечание: отличается от `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 не является «стабильной», что означает, что когда несколько элементов имеют одинаковое значение, они не гарантированно возвращаются в том же порядке, в котором они были вставлены.

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

Это в основном необходимо для согласованности набора тестов

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–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

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