класс SyntaxSuggest::AroundBlockScan
Этот класс полезен для исследования содержимого до и после блока.
Он ищет выше и ниже переданного блока, чтобы соответствовать заданным критериям:
Пример:
def dog # 1
puts "bark" # 2
puts "bark" # 3
end # 4
scan = AroundBlockScan.new(
code_lines: code_lines
block: CodeBlock.new(lines: code_lines[1])
)
scan.scan_while { true }
puts scan.before_index # => 0
puts scan.after_index # => 3 Общедоступные методы класса
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 30 def initialize(code_lines:, block:) @code_lines = code_lines @orig_indent = block.current_indent @stop_after_kw = false @force_add_empty = false @force_add_hidden = false @target_indent = nil @scanner = ScanHistory.new(code_lines: code_lines, block: block) end
Общедоступные методы экземпляра
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 217 def code_block CodeBlock.new(lines: lines) end
Возвращает текущие сопоставленные строки в виде ‘CodeBlock`
При создании ‘CodeBlock` он собирает метаданные о себе, поэтому это не простое преобразование. Избегайте выделения большего количества ‘CodeBlock` объектов, чем необходимо.
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 60 def force_add_empty @force_add_empty = true self end
При использовании этого флага ‘scan_while` пропустит переданный блок и всегда добавит строку, которая соответствует условию ‘CodeLine#empty?`
Пустые строки не содержат кода, только пробелы, такие как начальные пробелы и новая строка.
Исходный код
При использовании этого флага ‘scan_while` пропустит переданный блок и всегда добавит строку, которая соответствует условию ‘CodeLine#hidden?`
Строки скрыты, когда они были оценены анализатором как часть блока и содержат допустимый код.
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 228
def inspect
"#<#{self.class}:0x0000123843lol >"
end Управление ошибками rspec
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 223 def lines @scanner.lines end
Возвращает строки, соответствующие текущему сканированию, в виде массива CodeLines
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 141
def lookahead_balance_one_line
kw_count = 0
end_count = 0
lines.each do |line|
kw_count += 1 if line.is_kw?
end_count += 1 if line.is_end?
end
return self if kw_count == end_count # nothing to balance
@scanner.commit_if_changed # Rollback point if we don't find anything to optimize
# Try to eat up empty lines
@scanner.scan(
up: ->(line, _, _) { line.hidden? || line.empty? },
down: ->(line, _, _) { line.hidden? || line.empty? }
)
# More ends than keywords, check if we can balance expanding up
next_up = @scanner.next_up
next_down = @scanner.next_down
case end_count - kw_count
when 1
if next_up&.is_kw? && next_up.indent >= @target_indent
@scanner.scan(
up: ->(line, _, _) { line == next_up },
down: ->(line, _, _) { false }
)
@scanner.commit_if_changed
end
when -1
if next_down&.is_end? && next_down.indent >= @target_indent
@scanner.scan(
up: ->(line, _, _) { false },
down: ->(line, _, _) { line == next_down }
)
@scanner.commit_if_changed
end
end
# Rollback any uncommitted changes
@scanner.stash_changes
self
end Сканирование намеренно консервативное, так как у нас нет возможности отменить агрессивный блок (на данный момент)
Если блок был остановлен по какой-то незначительной причине (например, пустая строка), но следующая строка могла бы привести к балансировке, то мы можем проверить это условие и получить ещё одну строку вверх или вниз.
Например, ниже, если мы сканируем вверх, строка 2 может привести к остановке сканирования. Это происходит потому, что пустые строки могут обозначать логические разрывы, где пользователь намеревался разбить код на части, что является хорошим местом для остановки и проверки валидности. К сожалению, это также означает, что у нас может быть «висящий» ключевой символ или конец.
1 def bark 2 3 end
Если строки 2 и 3 находятся в блоке, то при выполнении этого метода он увидит, что он несбалансирован, но что приобретение строки 1 сделает его сбалансированным, поэтому он это и делает.
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 200
def scan_adjacent_indent
before_after_indent = []
before_after_indent << (@scanner.next_up&.indent || 0)
before_after_indent << (@scanner.next_down&.indent || 0)
@target_indent = before_after_indent.min
scan_while { |line| line.not_empty? && line.indent >= @target_indent }
self
end Сканирование блоков на основе отступа следующей строки выше/ниже блока
Определяет отступ следующей строки выше/ниже текущего блока.
Обычно это вызывается, когда блок расширился, чтобы захватить всех «соседей» с тем же (или большим) отступом, и ему нужно расшириться. Например, строки ‘def/end` вокруг метода.
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 188
def scan_neighbors_not_empty
@target_indent = @orig_indent
scan_while { |line| line.not_empty? && line.indent >= @target_indent }
end Находит строки кода с тем же или большим отступом и добавляет их в блок
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 88
def scan_while
stop_next_up = false
stop_next_down = false
@scanner.scan(
up: ->(line, kw_count, end_count) {
next false if stop_next_up
next true if @force_add_hidden && line.hidden?
next true if @force_add_empty && line.empty?
if @stop_after_kw && kw_count > end_count
stop_next_up = true
end
yield line
},
down: ->(line, kw_count, end_count) {
next false if stop_next_down
next true if @force_add_hidden && line.hidden?
next true if @force_add_empty && line.empty?
if @stop_after_kw && end_count > kw_count
stop_next_down = true
end
yield line
}
)
self
end Основной рабочий метод
Метод scan_while принимает блок, который возвращает строки выше и ниже блока. Если возвращаемое значение истинно, @before_index или @after_index изменяются, чтобы включить сопоставленную строку.
Помимо возвращения отдельных строк, внутренние компоненты этого объекта предоставляют мини-DSL для обработки распространённых ситуаций, таких как остановка, если мы обнаружили несоответствие ключевого слова/end в одном направлении или другом.
Исходный код
# File lib/syntax_suggest/around_block_scan.rb, line 73 def stop_after_kw @stop_after_kw = true self end
Указывает ‘scan_while` искать несоответствия ключевых слов/end
При сканировании вверх, если мы видим больше ключевых слов, чем end, это остановит сканирование. Это может произойти при сканировании за пределами тела метода. Первой сканируемой строкой вверх будет ключевое слово, и эта настройка вызовет остановку.
При сканировании вниз, останавливаться, если есть больше end, чем ключевых слов.
Ruby Core © 1993–2024 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.