Class: HeadMusic::Instruments::ScoreOrder
- Inherits:
-
Object
- Object
- HeadMusic::Instruments::ScoreOrder
- Includes:
- Named
- Defined in:
- lib/head_music/instruments/score_order.rb
Constant Summary collapse
- SCORE_ORDERS =
YAML.load_file(File.("score_orders.yml", __dir__)).freeze
- DEFAULT_ENSEMBLE_TYPE_KEY =
:orchestral
Instance Attribute Summary collapse
-
#alias_name_keys ⇒ Object
included
from Named
readonly
Returns the value of attribute alias_name_keys.
-
#ensemble_type_key ⇒ Object
readonly
Returns the value of attribute ensemble_type_key.
-
#name_key ⇒ Object
included
from Named
readonly
Returns the value of attribute name_key.
-
#sections ⇒ Object
readonly
Returns the value of attribute sections.
Class Method Summary collapse
-
.get(ensemble_type) ⇒ Object
Factory method to get a ScoreOrder instance for a specific ensemble type.
-
.in_band_order(instruments) ⇒ Object
Convenience method to order instruments in concert band order.
-
.in_orchestral_order(instruments) ⇒ Object
Convenience method to order instruments in orchestral order.
Instance Method Summary collapse
-
#build_ordering_index ⇒ Object
private
Builds an index mapping instrument names to their position in the order.
-
#ensure_localized_name(name:, locale_code: Locale::DEFAULT_CODE, abbreviation: nil) ⇒ Object
included
from Named
-
#find_position(instrument, ordering_index) ⇒ Object
private
Finds the position of an instrument in the ordering.
-
#find_position_with_transposition(instrument, ordering_index) ⇒ Object
private
Finds the position and transposition information for an instrument.
-
#initialize(ensemble_type_key = DEFAULT_ENSEMBLE_TYPE_KEY) ⇒ ScoreOrder
constructor
private
A new instance of ScoreOrder.
-
#localized_name(locale_code: Locale::DEFAULT_CODE) ⇒ Object
included
from Named
-
#localized_name_in_default_locale ⇒ Object
included
from Named
private
-
#localized_name_in_locale_matching_language(locale) ⇒ Object
included
from Named
private
-
#localized_name_in_matching_locale(locale) ⇒ Object
included
from Named
private
-
#localized_names ⇒ Object
included
from Named
Returns an array of LocalizedName instances that are synonymous with the name.
-
#name(locale_code: Locale::DEFAULT_CODE) ⇒ Object
included
from Named
-
#name=(name) ⇒ Object
included
from Named
-
#normalize_inputs(instruments) ⇒ Object
private
Discards blank inputs and converts the rest to Instrument objects.
-
#normalize_to_instrument(input) ⇒ Object
private
-
#order(instruments) ⇒ Object
Accepts a list of instruments and orders them according to this ensemble type’s conventions.
-
#partition_by_known_position(instrument_objects, ordering_index) ⇒ Object
private
Splits instruments into those with a known score position and those without.
-
#position_by_family(instrument, ordering_index) ⇒ Object
private
Match a family variant (e.g., alto_saxophone -> saxophone family).
-
#position_by_name_key(instrument, ordering_index) ⇒ Object
private
Exact match on the instrument’s name_key.
-
#position_by_normalized_name(instrument, ordering_index) ⇒ Object
private
Match the normalized (lowercase, underscored) display name.
-
#sort_known(known) ⇒ Object
private
Sorts known instruments by position (primary) and transposition (secondary).
Constructor Details
#initialize(ensemble_type_key = DEFAULT_ENSEMBLE_TYPE_KEY) ⇒ ScoreOrder (private)
Returns a new instance of ScoreOrder.
42 43 44 45 46 47 48 |
# File 'lib/head_music/instruments/score_order.rb', line 42 def initialize(ensemble_type_key = DEFAULT_ENSEMBLE_TYPE_KEY) @ensemble_type_key = ensemble_type_key.to_sym data = SCORE_ORDERS[ensemble_type_key.to_s] @sections = data["sections"] || [] self.name = data["name"] || ensemble_type_key.to_s.tr("_", " ").capitalize end |
Instance Attribute Details
#alias_name_keys ⇒ Object (readonly) Originally defined in module Named
Returns the value of attribute alias_name_keys.
#ensemble_type_key ⇒ Object (readonly)
Returns the value of attribute ensemble_type_key.
10 11 12 |
# File 'lib/head_music/instruments/score_order.rb', line 10 def ensemble_type_key @ensemble_type_key end |
#name_key ⇒ Object (readonly) Originally defined in module Named
Returns the value of attribute name_key.
#sections ⇒ Object (readonly)
Returns the value of attribute sections.
10 11 12 |
# File 'lib/head_music/instruments/score_order.rb', line 10 def sections @sections end |
Class Method Details
.get(ensemble_type) ⇒ Object
Factory method to get a ScoreOrder instance for a specific ensemble type
13 14 15 16 17 18 19 |
# File 'lib/head_music/instruments/score_order.rb', line 13 def self.get(ensemble_type) @instances ||= {} key = HeadMusic::Utilities::HashKey.for(ensemble_type) return unless SCORE_ORDERS.key?(key.to_s) @instances[key] ||= new(key) end |
.in_band_order(instruments) ⇒ Object
Convenience method to order instruments in concert band order
27 28 29 |
# File 'lib/head_music/instruments/score_order.rb', line 27 def self.in_band_order(instruments) get(:band).order(instruments) end |
.in_orchestral_order(instruments) ⇒ Object
Convenience method to order instruments in orchestral order
22 23 24 |
# File 'lib/head_music/instruments/score_order.rb', line 22 def self.in_orchestral_order(instruments) get(:orchestral).order(instruments) end |
Instance Method Details
#build_ordering_index ⇒ Object (private)
Builds an index mapping instrument names to their position in the order
88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/head_music/instruments/score_order.rb', line 88 def build_ordering_index index = {} position = 0 sections.each do |section| instruments = section["instruments"] || [] instruments.each do |instrument_key| # Store position for this instrument key index[instrument_key.to_s] = position position += 1 end end index end |
#ensure_localized_name(name:, locale_code: Locale::DEFAULT_CODE, abbreviation: nil) ⇒ Object Originally defined in module Named
#find_position(instrument, ordering_index) ⇒ Object (private)
Finds the position of an instrument in the ordering. Positions are non-negative integers, so a nil lookup safely means “absent”.
106 107 108 109 110 |
# File 'lib/head_music/instruments/score_order.rb', line 106 def find_position(instrument, ordering_index) position_by_name_key(instrument, ordering_index) || position_by_family(instrument, ordering_index) || position_by_normalized_name(instrument, ordering_index) end |
#find_position_with_transposition(instrument, ordering_index) ⇒ Object (private)
Finds the position and transposition information for an instrument
137 138 139 140 141 142 143 144 145 |
# File 'lib/head_music/instruments/score_order.rb', line 137 def find_position_with_transposition(instrument, ordering_index) position = find_position(instrument, ordering_index) return nil unless position # Get the sounding transposition for secondary sorting transposition = instrument.default_sounding_transposition || 0 {position: position, transposition: transposition} end |
#localized_name(locale_code: Locale::DEFAULT_CODE) ⇒ Object Originally defined in module Named
#localized_name_in_default_locale ⇒ Object (private) Originally defined in module Named
#localized_name_in_locale_matching_language(locale) ⇒ Object (private) Originally defined in module Named
#localized_name_in_matching_locale(locale) ⇒ Object (private) Originally defined in module Named
#localized_names ⇒ Object Originally defined in module Named
Returns an array of LocalizedName instances that are synonymous with the name.
#name(locale_code: Locale::DEFAULT_CODE) ⇒ Object Originally defined in module Named
#name=(name) ⇒ Object Originally defined in module Named
#normalize_inputs(instruments) ⇒ Object (private)
Discards blank inputs and converts the rest to Instrument objects
51 52 53 54 |
# File 'lib/head_music/instruments/score_order.rb', line 51 def normalize_inputs(instruments) valid_inputs = instruments.compact.reject { |i| i.respond_to?(:empty?) && i.empty? } valid_inputs.map { |i| normalize_to_instrument(i) }.compact end |
#normalize_to_instrument(input) ⇒ Object (private)
76 77 78 79 80 81 82 83 84 85 |
# File 'lib/head_music/instruments/score_order.rb', line 76 def normalize_to_instrument(input) # Return if already an Instrument instance return input if input.is_a?(HeadMusic::Instruments::Instrument) # Return other objects that respond to required methods (mock objects, etc.) return input if input.respond_to?(:name_key) && input.respond_to?(:family_key) # Create an Instrument instance for string inputs HeadMusic::Instruments::Instrument.get(input) end |
#order(instruments) ⇒ Object
Accepts a list of instruments and orders them according to this ensemble type’s conventions
32 33 34 35 36 |
# File 'lib/head_music/instruments/score_order.rb', line 32 def order(instruments) ordering_index = build_ordering_index known, unknown = partition_by_known_position(normalize_inputs(instruments), ordering_index) sort_known(known) + unknown.sort_by(&:to_s) end |
#partition_by_known_position(instrument_objects, ordering_index) ⇒ Object (private)
Splits instruments into those with a known score position and those without
57 58 59 60 61 62 63 64 65 66 67 68 69 |
# File 'lib/head_music/instruments/score_order.rb', line 57 def partition_by_known_position(instrument_objects, ordering_index) known = [] unknown = [] instrument_objects.each do |instrument| position_info = find_position_with_transposition(instrument, ordering_index) if position_info known << [instrument, position_info] else unknown << instrument end end [known, unknown] end |
#position_by_family(instrument, ordering_index) ⇒ Object (private)
Match a family variant (e.g., alto_saxophone -> saxophone family)
120 121 122 123 124 125 126 127 128 129 |
# File 'lib/head_music/instruments/score_order.rb', line 120 def position_by_family(instrument, ordering_index) return nil unless instrument.family_key family_base = instrument.family_key.to_s instrument_key = instrument.name_key.to_s return nil unless instrument_key.include?(family_base) # Prefer the specific variant, then fall back to the generic family instrument ordering_index[instrument_key] || ordering_index[family_base] end |
#position_by_name_key(instrument, ordering_index) ⇒ Object (private)
Exact match on the instrument’s name_key
113 114 115 116 117 |
# File 'lib/head_music/instruments/score_order.rb', line 113 def position_by_name_key(instrument, ordering_index) return nil unless instrument.name_key ordering_index[instrument.name_key.to_s] end |
#position_by_normalized_name(instrument, ordering_index) ⇒ Object (private)
Match the normalized (lowercase, underscored) display name
132 133 134 |
# File 'lib/head_music/instruments/score_order.rb', line 132 def position_by_normalized_name(instrument, ordering_index) ordering_index[HeadMusic::Utilities::Case.to_snake_case(instrument.name)] end |
#sort_known(known) ⇒ Object (private)
Sorts known instruments by position (primary) and transposition (secondary)
72 73 74 |
# File 'lib/head_music/instruments/score_order.rb', line 72 def sort_known(known) known.sort_by { |_, pos_info| [pos_info[:position], -pos_info[:transposition]] }.map(&:first) end |