Spec-Zone.ru › Ruby 3.2

class SyntaxSuggest::CodeLine

Parent:
Объект

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

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

  if strip_line.empty?
    @empty = true
    @indent = 0
  else
    @empty = false
    @indent = line.length - strip_line.length
  end

  set_kw_end
end

Публичные Методы Объектов

<=>(other) Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 152
def <=>(other)
  index <=> other.index
end

Оператор сравнения, необходимый для проверки на равенство и сортировки

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

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

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

Обратный или «visible?» (отличие от `empty?`)

ignore_newline_not_beg?() Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 174
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 74
def indent_index
  @indent_index ||= [indent, index]
end

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

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

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

Это в основном нужно для стабильности набора тестов

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

Возвращает true, если строка кода содержит ключевое слово «end»

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

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

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

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

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

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

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

Обратное значение `empty?` (отличие от `visible?`)

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

Отображает заданную строку

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

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

trailing_slash?() Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 185
def trailing_slash?
  last = @lex.last
  return false unless last
  return false unless last.type == :on_sp

  last.token == TRAILING_SLASH
end

Определяет, содержит ли заданная строка конечный слэш

lines = CodeLine.from_source(<<~EOM)
  it "foo" \
EOM
expect(lines.first.trailing_slash?).to eq(true)
visible?() Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 105
def visible?
  !line.empty?
end

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

Приватные Методы Объектов

set_kw_end() Показать исходный код
# File lib/syntax_suggest/code_line.rb, line 201
        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