Class: HeadMusic::Notation::LilyPond::AssignmentReader
- Inherits:
-
Object
- Object
- HeadMusic::Notation::LilyPond::AssignmentReader
- Defined in:
- lib/head_music/notation/lily_pond/assignment_reader.rb
Overview
Reads a block of name = value assignments — a \header or a \with — up
to its closing brace, yielding the fields the caller named. A field the
caller did not name carries no musical meaning and is commonly Scheme
(tagline = ##f), so its value is skipped by balance; a field the caller
reads must be a quoted string.
Instance Attribute Summary collapse
-
#block_name ⇒ Object
readonly
private
Returns the value of attribute block_name.
-
#cursor ⇒ Object
readonly
private
Returns the value of attribute cursor.
-
#fields ⇒ Object
readonly
private
Returns the value of attribute fields.
Instance Method Summary collapse
-
#initialize(cursor, block_name, fields) ⇒ AssignmentReader
constructor
A new instance of AssignmentReader.
- #message ⇒ Object private
- #next_assignment? ⇒ Boolean private
- #read ⇒ Object
-
#skip_value(name) ⇒ Object
private
The value runs to the next assignment or the closing brace, whichever comes first at the outermost level.
- #string_value(name) ⇒ Object private
Constructor Details
#initialize(cursor, block_name, fields) ⇒ AssignmentReader
Returns a new instance of AssignmentReader.
9 10 11 12 13 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 9 def initialize(cursor, block_name, fields) @cursor = cursor @block_name = block_name @fields = fields end |
Instance Attribute Details
#block_name ⇒ Object (readonly, private)
Returns the value of attribute block_name.
30 31 32 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 30 def block_name @block_name end |
#cursor ⇒ Object (readonly, private)
Returns the value of attribute cursor.
30 31 32 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 30 def cursor @cursor end |
#fields ⇒ Object (readonly, private)
Returns the value of attribute fields.
30 31 32 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 30 def fields @fields end |
Instance Method Details
#message ⇒ Object (private)
32 33 34 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 32 def "#{block_name} expects name = \"value\" assignments" end |
#next_assignment? ⇒ Boolean (private)
61 62 63 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 61 def next_assignment? cursor.peek&.type == :word && cursor.peek(1)&.type == :equals end |
#read ⇒ Object
15 16 17 18 19 20 21 22 23 24 25 26 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 15 def read until cursor.peek.type == :close_brace name = cursor.expect(:word, , unsupported: true) cursor.expect(:equals, , unsupported: true) if fields.include?(name.lexeme) yield name.lexeme, string_value(name) else skip_value(name) end end cursor.advance end |
#skip_value(name) ⇒ Object (private)
The value runs to the next assignment or the closing brace, whichever comes first at the outermost level. A value of no tokens is a malformed assignment rather than an empty one.
46 47 48 49 50 51 52 53 54 55 56 57 58 59 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 46 def skip_value(name) depth = 0 consumed = 0 until cursor.eos? token = cursor.peek break if depth.zero? && (next_assignment? || token.type == :close_brace) depth += 1 if token.type == :open_brace depth -= 1 if token.type == :close_brace cursor.advance consumed += 1 end raise cursor.unsupported(, name) if consumed.zero? end |
#string_value(name) ⇒ Object (private)
36 37 38 39 40 41 |
# File 'lib/head_music/notation/lily_pond/assignment_reader.rb', line 36 def string_value(name) value = cursor.advance return value.lexeme if value&.type == :string raise cursor.unsupported("#{block_name} values other than quoted strings are not supported", value || name) end |