Class: HeadMusic::Content::Flow::Deserializer
- Inherits:
-
Object
- Object
- HeadMusic::Content::Flow::Deserializer
- Defined in:
- lib/head_music/content/flow/deserializer.rb
Overview
What every schema version's reader does the same way: check the version, build the base flow, and replay placements, repeat flags, and comments through the public builder API. A subclass names its SCHEMA_VERSION, says where the opening timeline values live, and walks its own containers.
Raw values are validated at the boundary by SchemaValues, so corrupted input raises ArgumentError with path context instead of silently deserializing wrong.
Direct Known Subclasses
Instance Attribute Summary collapse
-
#hash ⇒ Object
readonly
private
Returns the value of attribute hash.
Instance Method Summary collapse
- #add_comments(flow) ⇒ Object private
- #apply_repeat_flags(flow) ⇒ Object private
- #bar_hashes ⇒ Object private
- #build_base_flow ⇒ Object private
- #build_placements(voice, voice_hash, voice_path) ⇒ Object private
-
#each_change(list, base) ⇒ Object
private
A list of bar-keyed changes, each yielded with its validated bar number and its path for error messages.
- #flow ⇒ Object
-
#initialize(hash) ⇒ Deserializer
constructor
A new instance of Deserializer.
- #unsupported_version_message(version) ⇒ Object private
- #validate_schema_version ⇒ Object private
- #values ⇒ Object private
Constructor Details
#initialize(hash) ⇒ Deserializer
Returns a new instance of Deserializer.
11 12 13 14 15 16 |
# File 'lib/head_music/content/flow/deserializer.rb', line 11 def initialize(hash) raise ArgumentError, "expected a Hash, got #{hash.class}" unless hash.is_a?(Hash) @hash = hash.deep_transform_keys(&:to_s) validate_schema_version end |
Instance Attribute Details
#hash ⇒ Object (readonly, private)
Returns the value of attribute hash.
24 25 26 |
# File 'lib/head_music/content/flow/deserializer.rb', line 24 def hash @hash end |
Instance Method Details
#add_comments(flow) ⇒ Object (private)
90 91 92 93 94 95 96 |
# File 'lib/head_music/content/flow/deserializer.rb', line 90 def add_comments(flow) Array(hash["comments"]).each_with_index do |comment_hash, index| raw_position = comment_hash["position"] position = values.position(raw_position, "comments[#{index}]") if raw_position flow.add_comment(comment_hash["text"], position) end end |
#apply_repeat_flags(flow) ⇒ Object (private)
79 80 81 82 83 84 85 86 87 88 |
# File 'lib/head_music/content/flow/deserializer.rb', line 79 def apply_repeat_flags(flow) each_change(, "bars") do |, , _path| = flow.().last .starts_repeat = true if ["starts_repeat"] ends_repeat = ["ends_repeat_after_num_plays"] .ends_repeat_after_num_plays = ends_repeat if ends_repeat plays_on_passes = ["plays_on_passes"] .plays_on_passes = plays_on_passes if plays_on_passes end end |
#bar_hashes ⇒ Object (private)
52 53 54 |
# File 'lib/head_music/content/flow/deserializer.rb', line 52 def @bar_hashes ||= Array(hash["bars"]) end |
#build_base_flow ⇒ Object (private)
41 42 43 44 45 46 47 48 49 50 |
# File 'lib/head_music/content/flow/deserializer.rb', line 41 def build_base_flow HeadMusic::Content::Flow.new( name: hash["name"], key_signature: values.key_signature(timeline_hash["key_signature"], timeline_path("key_signature")), meter: values.meter(timeline_hash["meter"], timeline_path("meter")), tempo: values.tempo(timeline_hash["tempo"], timeline_path("tempo")), composer: hash["composer"], origin: hash["origin"] ) end |
#build_placements(voice, voice_hash, voice_path) ⇒ Object (private)
64 65 66 67 68 69 70 71 72 73 74 75 76 77 |
# File 'lib/head_music/content/flow/deserializer.rb', line 64 def build_placements(voice, voice_hash, voice_path) Array(voice_hash["placements"]).each_with_index do |placement_hash, placement_index| path = "#{voice_path}.placements[#{placement_index}]" placement = voice.place( values.position(placement_hash["position"], path), values.rhythmic_value(placement_hash["rhythmic_value"], path), values.placement_sounds(placement_hash, path) ) placement.beam_break_before = placement_hash["beam_break_before"] if placement_hash.key?("beam_break_before") values.placement_syllables(placement_hash, path).each do |syllable| placement.sing(syllable.text, verse: syllable.verse, hyphen_after: syllable.hyphen_after) end end end |
#each_change(list, base) ⇒ Object (private)
A list of bar-keyed changes, each yielded with its validated bar number and its path for error messages.
58 59 60 61 62 |
# File 'lib/head_music/content/flow/deserializer.rb', line 58 def each_change(list, base) Array(list).each_with_index do |change, index| yield values.(change, index, base), change, "#{base}[#{index}]" end end |
#flow ⇒ Object
18 19 20 |
# File 'lib/head_music/content/flow/deserializer.rb', line 18 def flow @flow ||= build_base_flow.tap { |flow| build(flow) } end |
#unsupported_version_message(version) ⇒ Object (private)
37 38 39 |
# File 'lib/head_music/content/flow/deserializer.rb', line 37 def (version) "unsupported schema_version: #{version.inspect} (supported: #{self.class::SCHEMA_VERSION})" end |
#validate_schema_version ⇒ Object (private)
30 31 32 33 34 35 |
# File 'lib/head_music/content/flow/deserializer.rb', line 30 def validate_schema_version version = hash["schema_version"] return if version.is_a?(Integer) && version == self.class::SCHEMA_VERSION raise ArgumentError, (version) end |
#values ⇒ Object (private)
26 27 28 |
# File 'lib/head_music/content/flow/deserializer.rb', line 26 def values @values ||= SchemaValues.new end |