Spec-Zone.ru › Ruby 3.3

класс 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[R]
index[R]
lex[R]
line[R]
line_number[R]
number[R]
original[R]

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

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

Публичные Классовые Методы

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

Spec-Zone.ru

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