Class: HeadMusic::Notation::ABC::ChordScanner
- Inherits:
-
Object
- Object
- HeadMusic::Notation::ABC::ChordScanner
- Defined in:
- lib/head_music/notation/abc/chord_scanner.rb
Overview
Scans one bracket chord — “[CEG]2” — from the position of its opening bracket.
Non-note content inside the brackets (ties, rests, spaces, decorations) makes the whole group one unsupported token, matching how those constructs surface outside a chord.
Defined Under Namespace
Classes: ChordNote
Constant Summary collapse
- START_PATTERN =
Matches a bracket whose first content is a note, distinguishing a chord from the other things a “[” can open.
/\[(\^\^|\^|__|_|=)?[A-Ga-g]/- NOTE_PATTERN =
%r{(\^\^|\^|__|_|=)?([A-Ga-g])([',]*)([\d/]*)}
Instance Attribute Summary collapse
-
#column ⇒ Object
readonly
private
Returns the value of attribute column.
-
#line_number ⇒ Object
readonly
private
Returns the value of attribute line_number.
-
#scanner ⇒ Object
readonly
private
Returns the value of attribute scanner.
-
#start_pos ⇒ Object
readonly
private
Returns the value of attribute start_pos.
Instance Method Summary collapse
-
#collect_notes ⇒ Object
private
Collects the notes between the brackets, or nil when a non-note is hit (leaving the scanner where it stopped so the fallback can react).
-
#ensure_terminated ⇒ Object
private
-
#fallback_token ⇒ Object
private
-
#initialize(scanner, line_number, column) ⇒ ChordScanner
constructor
A new instance of ChordScanner.
-
#new_token(**attributes) ⇒ Object
private
-
#token ⇒ Object
The :chord token, or the :unsupported token the whole group falls back to.
Constructor Details
#initialize(scanner, line_number, column) ⇒ ChordScanner
Returns a new instance of ChordScanner.
21 22 23 24 25 26 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 21 def initialize(scanner, line_number, column) @scanner = scanner @line_number = line_number @column = column @start_pos = scanner.pos end |
Instance Attribute Details
#column ⇒ Object (readonly, private)
Returns the value of attribute column.
40 41 42 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 40 def column @column end |
#line_number ⇒ Object (readonly, private)
Returns the value of attribute line_number.
40 41 42 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 40 def line_number @line_number end |
#scanner ⇒ Object (readonly, private)
Returns the value of attribute scanner.
40 41 42 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 40 def scanner @scanner end |
#start_pos ⇒ Object (readonly, private)
Returns the value of attribute start_pos.
40 41 42 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 40 def start_pos @start_pos end |
Instance Method Details
#collect_notes ⇒ Object (private)
Collects the notes between the brackets, or nil when a non-note is hit (leaving the scanner where it stopped so the fallback can react).
44 45 46 47 48 49 50 51 52 53 54 55 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 44 def collect_notes notes = [] until scanner.skip(/\]/) return nil unless scanner.scan(NOTE_PATTERN) notes << ChordNote.new( accidental: scanner[1], letter: scanner[2], octave_marks: scanner[3], length: scanner[4] ) end notes end |
#ensure_terminated ⇒ Object (private)
64 65 66 67 68 69 70 71 72 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 64 def ensure_terminated return unless scanner.eos? raise ParseError.new( 'Unterminated chord; expected "]"', line_number: line_number, snippet: scanner.string[start_pos, BodyLexer::SNIPPET_LENGTH] ) end |
#fallback_token ⇒ Object (private)
57 58 59 60 61 62 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 57 def fallback_token ensure_terminated scanner.pos = start_pos lexeme = scanner.scan(/\[[^\]]*\]/) || scanner.scan(/\[[^\]]*/) new_token(type: :unsupported, lexeme: lexeme) end |
#new_token(**attributes) ⇒ Object (private)
74 75 76 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 74 def new_token(**attributes) Token.new(line: line_number, column: column, **attributes) end |
#token ⇒ Object
The :chord token, or the :unsupported token the whole group falls back to. Raises when the brackets never close.
30 31 32 33 34 35 36 |
# File 'lib/head_music/notation/abc/chord_scanner.rb', line 30 def token scanner.skip(/\[/) notes = collect_notes return fallback_token unless notes new_token(type: :chord, notes: notes, length: scanner.scan(%r{[\d/]*})) end |