class SyntaxSuggest::AroundBlockScan
Diese Klasse ist nützlich, um Inhalte vor und nach einem Block zu untersuchen.
Sie durchsucht den übergebenen Block von oben und unten, um ihn mit den von Ihnen vorgegebenen Kriterien abzugleichen.
Beispiel
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
Öffentliche Klassenmethoden
Source
# 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
Öffentliche Instanzmethoden
Source
# File lib/syntax_suggest/around_block_scan.rb, line 217 def code_block CodeBlock.new(lines: lines) end
Gibt die aktuell übereinstimmenden Zeilen als ‘CodeBlock` zurück.
Wenn ein ‘CodeBlock` erstellt wird, sammelt er Metadaten über sich selbst, daher ist dies keine kostenlose Konvertierung. Vermeiden Sie die Erstellung von mehr CodeBlocks als nötig.
Source
# File lib/syntax_suggest/around_block_scan.rb, line 60 def force_add_empty @force_add_empty = true self end
Wenn dieses Flag verwendet wird, umgeht ‘scan_while` den ihm übergebenen Block und fügt immer eine Zeile hinzu, die wahrheitsgemäß auf ‘CodeLine#empty?` reagiert.
Leere Zeilen enthalten keinen Code, nur Whitespace wie führende Leerzeichen und einen Zeilenumbruch.
Source
# File lib/syntax_suggest/around_block_scan.rb, line 228 def inspect "#<#{self.class}:0x0000123843lol >" end
Verwaltbare rspec-Fehler
Source
# File lib/syntax_suggest/around_block_scan.rb, line 223 def lines @scanner.lines end
Gibt die vom aktuellen Scan gefundenen Zeilen als Array von CodeLines zurück.
Source
# 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
Das Scannen ist bewusst konservativ, da wir keine Möglichkeit haben, einen aggressiven Block zurückzurollen (derzeit).
Wenn ein Block aus einem trivialen Grund gestoppt wurde (z. B. eine leere Zeile), aber die nächste Zeile ihn ausgeglichen hätte, können wir diesen Zustand prüfen und entweder oben oder unten eine weitere Zeile aufnehmen.
Zum Beispiel: Wenn wir im obigen Beispiel nach oben scannen, könnte Zeile 2 den Scan stoppen. Das liegt daran, dass leere Zeilen logische Brüche anzeigen können, bei denen der Benutzer beabsichtigt hat, Code zu gruppieren, was ein guter Ort zum Stoppen und Überprüfen der Gültigkeit ist. Leider bedeutet dies auch, dass wir ein "hängendes" Schlüsselwort oder Ende haben könnten.
1 def bark 2 3 end
Wenn die Zeilen 2 und 3 im Block enthalten sind, dann würde diese Methode beim Ausführen feststellen, dass sie unausgeglichen ist, aber die Aufnahme von Zeile 1 sie ausgleichen würde, also tut sie das.
Source
# 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
Scannt Blöcke basierend auf der Einrückung der nächsten Zeile oberhalb/unterhalb des Blocks.
Ermittelt die Einrückung der nächsten Zeile oberhalb/unterhalb des aktuellen Blocks.
Normalerweise wird dies aufgerufen, wenn ein Block erweitert wurde, um alle "Nachbarn" mit der gleichen (oder größeren) Einrückung zu erfassen und sich nach außen ausdehnen muss. Zum Beispiel die 'def/end'-Zeilen, die eine Methode umgeben.
Source
# 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
Findet Codezeilen mit gleicher oder größerer Einrückung und fügt sie dem Block hinzu.
Source
# 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
Hauptarbeitsmethode.
Die Methode scan_while nimmt einen Block entgegen, der Zeilen oberhalb und unterhalb des Blocks liefert. Wenn die Auswertung wahr zurückgibt, werden @before_index oder @after_index angepasst, um die übereinstimmende Zeile einzuschließen.
Zusätzlich zur Übergabe einzelner Zeilen bieten die internen Mechanismen dieses Objekts eine Mini-DSL, um gängige Situationen zu bewältigen, wie z. B. das Stoppen, wenn wir einen Fehler bei Schlüsselwörtern/Enden in der einen oder anderen Richtung gefunden haben.
Source
# File lib/syntax_suggest/around_block_scan.rb, line 73 def stop_after_kw @stop_after_kw = true self end
Weist ‘scan_while` an, nach nicht übereinstimmenden Schlüsselwörtern/Enden zu suchen.
Beim Scannen nach oben, wenn wir mehr Schlüsselwörter als Enden sehen, wird gestoppt. Dies kann passieren, wenn außerhalb eines Methodenrumpfes gescannt wird. Die erste Scan-Zeile nach oben wäre ein Schlüsselwort und diese Einstellung würde einen Stopp auslösen.
Beim Scannen nach unten stoppt es, wenn mehr Enden als Schlüsselwörter vorhanden sind.