Class: HeadMusic::Rudiment::RhythmicUnit::Parser

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/rudiment/rhythmic_unit/parser.rb

Constant Summary collapse

RHYTHMIC_UNITS_DATA =
HeadMusic::Rudiment::RhythmicUnit::RHYTHMIC_UNITS_DATA
TEMPO_SHORTHAND_PATTERN =
RHYTHMIC_UNITS_DATA.map { |unit| unit["tempo_shorthand"] }.compact.uniq.sort_by { |s| -s.length }.join("|")

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(identifier) ⇒ Parser

Returns a new instance of Parser.



13
14
15
16
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 13

def initialize(identifier)
  @identifier = identifier.to_s.strip
  parse
end

Instance Attribute Details

#identifierObject (readonly)

Returns the value of attribute identifier.



2
3
4
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 2

def identifier
  @identifier
end

#rhythmic_unitObject (readonly)

Returns the value of attribute rhythmic_unit.



2
3
4
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 2

def rhythmic_unit
  @rhythmic_unit
end

Class Method Details

.parse(identifier) ⇒ Object



8
9
10
11
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 8

def self.parse(identifier)
  return nil if identifier.nil? || identifier.to_s.strip.empty?
  new(identifier).parsed_name
end

Instance Method Details

#american_nameObject



35
36
37
38
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 35

def american_name
  # Always return the American name if a unit was found
  @unit_data&.fetch("american_name", nil)
end

#duration_matches?(unit) ⇒ Boolean (private)

Returns:

  • (Boolean)


70
71
72
73
74
75
76
77
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 70

def duration_matches?(unit)
  # Match decimal duration (e.g., "0.25")
  return true if unit["duration"].to_s == identifier.strip

  # Match fraction notation (e.g., "1/4" = 0.25)
  duration = fraction_duration
  duration && (duration - unit["duration"]).abs < 0.0001
end

#fraction_durationObject (private)



79
80
81
82
83
84
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 79

def fraction_duration
  return nil unless identifier.match?(%r{^\d+/\d+$})

  numerator, denominator = identifier.split("/").map(&:to_f)
  numerator / denominator
end

#from_american_nameObject



44
45
46
47
48
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 44

def from_american_name
  RHYTHMIC_UNITS_DATA.find do |unit|
    normalize_name(unit["american_name"]) == normalized_identifier
  end
end

#from_british_nameObject



50
51
52
53
54
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 50

def from_british_name
  RHYTHMIC_UNITS_DATA.find do |unit|
    normalize_name(unit["british_name"]) == normalized_identifier
  end
end

#from_durationObject



64
65
66
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 64

def from_duration
  RHYTHMIC_UNITS_DATA.find { |unit| duration_matches?(unit) }
end

#from_tempo_shorthandObject



56
57
58
59
60
61
62
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 56

def from_tempo_shorthand
  # Handle shorthand with dots (e.g., "q." should match "q")
  clean_identifier = identifier.downcase.strip.gsub(/\.*$/, "")
  RHYTHMIC_UNITS_DATA.find do |unit|
    unit["tempo_shorthand"] && unit["tempo_shorthand"].downcase == clean_identifier
  end
end

#normalize_name(name) ⇒ Object (private)



86
87
88
89
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 86

def normalize_name(name)
  return nil if name.nil?
  HeadMusic::Utilities::Case.to_snake_case(name)
end

#normalized_identifierObject



40
41
42
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 40

def normalized_identifier
  @normalized_identifier ||= HeadMusic::Utilities::Case.to_snake_case(identifier)
end

#parseObject



18
19
20
21
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 18

def parse
  @unit_data = from_american_name || from_british_name || from_tempo_shorthand || from_duration
  @rhythmic_unit = @unit_data ? HeadMusic::Rudiment::RhythmicUnit.get_by_name(@unit_data["american_name"]) : nil
end

#parsed_nameObject



23
24
25
26
27
28
29
30
31
32
33
# File 'lib/head_music/rudiment/rhythmic_unit/parser.rb', line 23

def parsed_name
  # Return the name format that was used in input
  return nil unless @unit_data

  # Check which type matched
  if from_british_name == @unit_data && @unit_data["british_name"]
    @unit_data["british_name"]
  else
    @unit_data["american_name"]
  end
end