Spec-Zone.ru › Ruby 3.4

класс SyntaxSuggest::CaptureCodeContext

Родитель:
Объект

Преобразует «некорректный(ые) блок(и)» в полезный контекст

В алгоритме есть три основные фазы:

  1. Сантизация/форматирование исходного кода

  2. Поиск некорректных блоков

  3. Форматирование некорректных блоков в осмысленную форму

Этот класс обрабатывает третью часть.

Алгоритм хорошо справляется с захватом всей ошибки синтаксиса в одном блоке в пункте 2, однако результаты могут содержать неоднозначности. Люди хорошо умеют распознавать закономерности и фильтровать, и могут мысленно удалять ненужные данные, но они не могут добавлять дополнительные данные, которых нет.

В случае известных неоднозначных случаев, этот класс добавляет контекст к неоднозначности, чтобы программист имел полную информацию.

Помимо обработки этих неоднозначностей, он также захватывает информацию о контексте окружающего кода:

puts block.to_s # => "def bark"

context = CaptureCodeContext.new(
  blocks: block,
  code_lines: code_lines
)

lines = context.call.map(&:original)
puts lines.join
# =>
  class Dog
    def bark
  end

Атрибуты

code_lines [R]

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

new (blocks:, code_lines:)
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 51
def initialize(blocks:, code_lines:)
  @blocks = Array(blocks)
  @code_lines = code_lines
  @visible_lines = @blocks.map(&:visible_lines).flatten
  @lines_to_output = @visible_lines.dup
end

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

call ()
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 58
def call
  @blocks.each do |block|
    capture_first_kw_end_same_indent(block)
    capture_last_end_same_indent(block)
    capture_before_after_kws(block)
    capture_falling_indent(block)
  end

  sorted_lines
end
capture_before_after_kws (block)
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 127
def capture_before_after_kws(block)
  return unless block.visible_lines.count == 1

  around_lines = Capture::BeforeAfterKeywordEnds.new(
    code_lines: @code_lines,
    block: block
  ).call

  around_lines -= block.lines

  @lines_to_output.concat(around_lines)
end

Отображает окружающие пары ключевых слов/end

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

Например:

1  class Dog
2    def bark
4    def eat
5    end
6  end

В этом случае либо в строке 2 отсутствует ‘end`, либо в строке 4 была добавлена лишняя строка (это случается).

Когда мы обнаруживаем указанную выше проблему, отображается информация о проблеме, как будто она только в строке 2

2    def bark

Отображение пар ключевых слов «соседних» пар обеспечивает дополнительный контекст:

2    def bark
4    def eat
5    end
capture_falling_indent (block)
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 91
def capture_falling_indent(block)
  Capture::FallingIndentLines.new(
    block: block,
    code_lines: @code_lines
  ).call do |line|
    @lines_to_output << line
  end
end

Отображает контекст вокруг кода, предоставленного «падающим» отступом

Преобразует:

it "foo" do

в:

class OH
  def hello
    it "foo" do
  end
end
capture_first_kw_end_same_indent (block)
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 221
def capture_first_kw_end_same_indent(block)
  return if block.visible_lines.length != 1
  return unless block.visible_lines.first.is_end?

  visible_line = block.visible_lines.first
  lines = @code_lines[block.lines.first.index..visible_line.index]
  matching_kw = lines.reverse.detect { |line| line.indent == block.current_indent && line.is_kw? }
  return unless matching_kw

  @lines_to_output << matching_kw

  kw_count = 0
  end_count = 0
  orphan_end = @code_lines[matching_kw.index..visible_line.index].detect do |line|
    kw_count += 1 if line.is_kw?
    end_count += 1 if line.is_end?

    end_count >= kw_count
  end

  return unless orphan_end
  @lines_to_output << orphan_end
end

Логическое обратное значение ‘capture_last_end_same_indent`

Когда в некорректном блоке отсутствует ключевое слово «end» сразу после другого `end`, неясно, какое end отсутствует ключевое слово.

Рассмотрим этот пример:

class Dog       # 1
    puts "woof" # 2
  end           # 3
end             # 4

Проблемная строка будет распознана как:

> end            # 4

Это происходит потому, что строки 1, 2 и 3 являются технически корректным кодом и расширяются в первую очередь, считаются корректными и скрываются. Нам нужно отобразить соответствующее ключевое слово в строке 1. Также необходимо работать в обратном направлении и, если есть несоответствие end, отобразить его тоже

capture_last_end_same_indent (block)
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 161
def capture_last_end_same_indent(block)
  return if block.visible_lines.length != 1
  return unless block.visible_lines.first.is_kw?

  visible_line = block.visible_lines.first
  lines = @code_lines[visible_line.index..block.lines.last.index]

  # Find first end with same indent
  # (this would return line 4)
  #
  #   end             # 4
  matching_end = lines.detect { |line| line.indent == block.current_indent && line.is_end? }
  return unless matching_end

  @lines_to_output << matching_end

  # Work backwards from the end to
  # see if there are mis-matched
  # keyword/end pairs
  #
  # Return the first mis-matched keyword
  # this would find line 2
  #
  #     def bark      # 2
  #       puts "woof" # 3
  #   end             # 4
  end_count = 0
  kw_count = 0
  kw_line = @code_lines[visible_line.index..matching_end.index].reverse.detect do |line|
    end_count += 1 if line.is_end?
    kw_count += 1 if line.is_kw?

    !kw_count.zero? && kw_count >= end_count
  end
  return unless kw_line
  @lines_to_output << kw_line
end

Когда в некорректном блоке отсутствует ключевое слово, за которым сразу следует end, неясно, какое ключевое слово отсутствует.

Рассмотрим этот пример:

class Dog       # 1
  def bark      # 2
    puts "woof" # 3
end             # 4

Однако из-за github.com/ruby/syntax_suggest/issues/32 проблемная строка будет распознана как:

> class Dog       # 1

Потому что строки 2, 3 и 4 являются технически корректным кодом и расширяются в первую очередь, считаются корректными и скрываются. Нам нужно отобразить соответствующий конец в строке 4. Также необходимо работать в обратном направлении и, если есть несоответствие ключевого слова, отобразить его тоже

sorted_lines ()
Исходный код
# File lib/syntax_suggest/capture_code_context.rb, line 69
def sorted_lines
  @lines_to_output.select!(&:not_empty?)
  @lines_to_output.uniq!
  @lines_to_output.sort!

  @lines_to_output
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