Class: HeadMusic::Style::GuideItem
- Inherits:
-
Object
- Object
- HeadMusic::Style::GuideItem
- Defined in:
- lib/head_music/style/guide_item.rb
Overview
A guideline plus the configuration one guide gives it, so the same guideline configured two ways is two items.
Tier is deliberately absent: an item is shared between guides and has no single standing, so tier is stamped onto the assessment instead. Strength is present, because a rule’s severity does not change between guides – the override exists only for the tradition-dependent case, where ApproachPerfectionContrarily is prohibited in Fux and merely cautioned later.
Constant Summary collapse
- REMOVED_OPTIONS =
Removed options, mapped to what replaces them. An unrecognized key rides along in config and is dropped at render, so a consumer who kept passing message: would watch their sentence vanish without a word.
{message: :violation_key}.freeze
Instance Attribute Summary collapse
-
#config ⇒ Object
readonly
Returns the value of attribute config.
-
#guideline ⇒ Object
readonly
Returns the value of attribute guideline.
-
#strength ⇒ Object
readonly
Returns the value of attribute strength.
Class Method Summary collapse
Instance Method Summary collapse
-
#==(other) ⇒ Object
(also: #eql?)
By value: identity matching is what made
CORE - [Guideline]silently remove nothing. -
#assess(voice, tier) ⇒ Object
-
#deep_freeze(value) ⇒ Object
private
Deep, because items are shared between guides: a mutable array inside config lets one caller corrupt every guide reusing a core, and changes the hash that value equality and duplicate rejection rest on.
-
#hash ⇒ Object
-
#initialize(guideline, config = {}, strength: nil) ⇒ GuideItem
constructor
Strength is resolved eagerly, before the freeze: asking the guideline for it lazily during grading would write a class ivar mid-assessment.
-
#inspect ⇒ Object
(also: #to_s)
Distinguishes two configurations of one guideline, which the class name could not.
-
#instruction ⇒ Object
-
#name ⇒ Object
-
#reject_removed_options!(config) ⇒ Object
private
At declaration time, so this fails on require rather than rendering the wrong sentence for the life of the process.
-
#resolve_strength(guideline, override) ⇒ Object
private
-
#violation_preview ⇒ Object
An assessment says nothing when adherent, so this is the only way to read the sentence an item carries without a voice that breaks it.
-
#violation_previews ⇒ Object
Every sentence the item can produce, including the branches an analysis chooses between.
Constructor Details
#initialize(guideline, config = {}, strength: nil) ⇒ GuideItem
Strength is resolved eagerly, before the freeze: asking the guideline for it lazily during grading would write a class ivar mid-assessment.
26 27 28 29 30 31 32 |
# File 'lib/head_music/style/guide_item.rb', line 26 def initialize(guideline, config = {}, strength: nil) (config) @guideline = guideline @config = deep_freeze(config) @strength = resolve_strength(guideline, strength) freeze end |
Instance Attribute Details
#config ⇒ Object (readonly)
Returns the value of attribute config.
13 14 15 |
# File 'lib/head_music/style/guide_item.rb', line 13 def config @config end |
#guideline ⇒ Object (readonly)
Returns the value of attribute guideline.
13 14 15 |
# File 'lib/head_music/style/guide_item.rb', line 13 def guideline @guideline end |
#strength ⇒ Object (readonly)
Returns the value of attribute strength.
13 14 15 |
# File 'lib/head_music/style/guide_item.rb', line 13 def strength @strength end |
Class Method Details
.wrap(entry) ⇒ Object
15 16 17 |
# File 'lib/head_music/style/guide_item.rb', line 15 def self.wrap(entry) entry.is_a?(self) ? entry : new(entry) end |
Instance Method Details
#==(other) ⇒ Object Also known as: eql?
By value: identity matching is what made CORE - [Guideline] silently
remove nothing.
Strength is deliberately omitted from both == and hash. reject_duplicates asks one question – is this rule graded twice – and strength cannot change the answer. Were it part of equality, declaring a rule primary-strong and secondary-weak would slip past the guard and be double-counted.
57 58 59 |
# File 'lib/head_music/style/guide_item.rb', line 57 def ==(other) other.is_a?(self.class) && guideline == other.guideline && config == other.config end |
#assess(voice, tier) ⇒ Object
46 47 48 |
# File 'lib/head_music/style/guide_item.rb', line 46 def assess(voice, tier) guideline.assess(voice, self, tier) end |
#deep_freeze(value) ⇒ Object (private)
Deep, because items are shared between guides: a mutable array inside config lets one caller corrupt every guide reusing a core, and changes the hash that value equality and duplicate rejection rest on.
Containers and strings only. A config value can be a rudiment, and those memoize lazily, so freezing one breaks it the first time it is asked.
110 111 112 113 114 115 116 117 |
# File 'lib/head_music/style/guide_item.rb', line 110 def deep_freeze(value) case value when Hash then value.each_value { |nested| deep_freeze(nested) }.freeze when Array then value.each { |nested| deep_freeze(nested) }.freeze when String then value.freeze else value end end |
#hash ⇒ Object
62 63 64 |
# File 'lib/head_music/style/guide_item.rb', line 62 def hash [guideline, config].hash end |
#inspect ⇒ Object Also known as: to_s
Distinguishes two configurations of one guideline, which the class name could not. Strength shows only when it differs from the declaration, so the common case stays readable.
77 78 79 80 81 82 |
# File 'lib/head_music/style/guide_item.rb', line 77 def inspect overridden = (strength == guideline.strength) ? "" : "<#{strength}>" return "#{guideline.name}#{overridden}" if config.empty? "#{guideline.name}#{overridden}#{config.inspect}" end |
#instruction ⇒ Object
70 71 72 |
# File 'lib/head_music/style/guide_item.rb', line 70 def instruction guideline.render_instruction(config) end |
#name ⇒ Object
66 67 68 |
# File 'lib/head_music/style/guide_item.rb', line 66 def name guideline.render_name(config) end |
#reject_removed_options!(config) ⇒ Object (private)
At declaration time, so this fails on require rather than rendering the wrong sentence for the life of the process.
95 96 97 98 99 100 101 102 |
# File 'lib/head_music/style/guide_item.rb', line 95 def (config) removed = config.keys & REMOVED_OPTIONS.keys return if removed.empty? raise ArgumentError, removed.map { |option| "#{option}: is no longer a guideline option -- name a locale entry with #{REMOVED_OPTIONS[option]}:" }.join(" ") end |
#resolve_strength(guideline, override) ⇒ Object (private)
87 88 89 90 91 |
# File 'lib/head_music/style/guide_item.rb', line 87 def resolve_strength(guideline, override) return guideline.strength if override.nil? HeadMusic::Style::Guideline::Strength.normalized(override, guideline.name) end |
#violation_preview ⇒ Object
An assessment says nothing when adherent, so this is the only way to read the sentence an item carries without a voice that breaks it.
36 37 38 |
# File 'lib/head_music/style/guide_item.rb', line 36 def violation_preview guideline.render_violation(config) end |
#violation_previews ⇒ Object
Every sentence the item can produce, including the branches an analysis chooses between. What load-time verification sweeps.
42 43 44 |
# File 'lib/head_music/style/guide_item.rb', line 42 def violation_previews guideline.render_violations(config) end |