Class: HeadMusic::Style::Analysis

Inherits:
Object
  • Object
show all
Defined in:
lib/head_music/style/analysis.rb

Overview

An analysis of music according to a style guide.

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(guide, voice) ⇒ Analysis

Any object answering analyze(voice) is a guide here – a guide class, a Guides::Configured, or a test double. Checking at construction keeps a missed Guide.get lookup from surfacing as NoMethodError on nil far away.



11
12
13
14
15
16
17
18
# File 'lib/head_music/style/analysis.rb', line 11

def initialize(guide, voice)
  unless guide.respond_to?(:analyze)
    raise ArgumentError, "guide must respond to #analyze (got #{guide.inspect})"
  end

  @guide = guide
  @voice = voice
end

Instance Attribute Details

#guideObject (readonly)

Returns the value of attribute guide.



6
7
8
# File 'lib/head_music/style/analysis.rb', line 6

def guide
  @guide
end

#voiceObject (readonly)

Returns the value of attribute voice.



6
7
8
# File 'lib/head_music/style/analysis.rb', line 6

def voice
  @voice
end

Instance Method Details

#adherent?Boolean

Returns:

  • (Boolean)


38
39
40
# File 'lib/head_music/style/analysis.rb', line 38

def adherent?
  annotations.all?(&:adherent?)
end

#annotationsObject



25
26
27
# File 'lib/head_music/style/analysis.rb', line 25

def annotations
  @annotations ||= @guide.analyze(voice)
end

#fitnessObject

The grade: sufficiency gates multiply against a weighted average of the rubric rules, so an insufficient exercise scales the whole grade down while ordinary rules trade off against each other by weight.



32
33
34
35
36
# File 'lib/head_music/style/analysis.rb', line 32

def fitness
  return 1.0 if annotations.empty?

  @fitness ||= gate_factor * rubric_fitness
end

#gate_factorObject (private)



44
45
46
# File 'lib/head_music/style/analysis.rb', line 44

def gate_factor
  gates.map(&:fitness).reduce(1, :*)
end

#gatesObject (private)



56
57
58
# File 'lib/head_music/style/analysis.rb', line 56

def gates
  annotations.select(&:gate?)
end

#messagesObject Also known as: annotation_messages



20
21
22
# File 'lib/head_music/style/analysis.rb', line 20

def messages
  annotations.reject(&:adherent?).map(&:message)
end

#rubric_fitnessObject (private)



48
49
50
51
52
53
54
# File 'lib/head_music/style/analysis.rb', line 48

def rubric_fitness
  rubric = annotations.reject(&:gate?)
  total_weight = rubric.sum(&:weight)
  return 1.0 if rubric.empty? || total_weight.zero?

  rubric.sum { |annotation| annotation.weight * annotation.fitness } / total_weight
end