musicality 0.3.0 → 0.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (89) hide show
  1. checksums.yaml +4 -4
  2. data/ChangeLog.md +8 -1
  3. data/bin/midify +3 -4
  4. data/examples/composition/auto_counterpoint.rb +53 -0
  5. data/examples/composition/part_generator.rb +51 -0
  6. data/examples/composition/scale_exercise.rb +41 -0
  7. data/examples/{hip.rb → notation/hip.rb} +1 -1
  8. data/examples/{missed_connection.rb → notation/missed_connection.rb} +1 -1
  9. data/examples/{song1.rb → notation/song1.rb} +1 -1
  10. data/examples/{song2.rb → notation/song2.rb} +1 -1
  11. data/lib/musicality.rb +34 -4
  12. data/lib/musicality/composition/generation/counterpoint_generator.rb +153 -0
  13. data/lib/musicality/composition/generation/random_rhythm_generator.rb +39 -0
  14. data/lib/musicality/composition/model/pitch_class.rb +33 -0
  15. data/lib/musicality/composition/model/pitch_classes.rb +22 -0
  16. data/lib/musicality/composition/model/scale.rb +34 -0
  17. data/lib/musicality/composition/model/scale_class.rb +37 -0
  18. data/lib/musicality/composition/model/scale_classes.rb +91 -0
  19. data/lib/musicality/composition/note_generation.rb +31 -0
  20. data/lib/musicality/composition/transposition.rb +8 -0
  21. data/lib/musicality/composition/util/adding_sequence.rb +24 -0
  22. data/lib/musicality/composition/util/biinfinite_sequence.rb +130 -0
  23. data/lib/musicality/composition/util/compound_sequence.rb +44 -0
  24. data/lib/musicality/composition/util/probabilities.rb +20 -0
  25. data/lib/musicality/composition/util/random_sampler.rb +26 -0
  26. data/lib/musicality/composition/util/repeating_sequence.rb +24 -0
  27. data/lib/musicality/errors.rb +2 -0
  28. data/lib/musicality/notation/conversion/score_conversion.rb +1 -1
  29. data/lib/musicality/notation/conversion/score_converter.rb +3 -3
  30. data/lib/musicality/notation/model/link.rb +26 -24
  31. data/lib/musicality/notation/model/links.rb +11 -0
  32. data/lib/musicality/notation/model/note.rb +14 -15
  33. data/lib/musicality/notation/model/part.rb +3 -3
  34. data/lib/musicality/notation/model/pitch.rb +8 -0
  35. data/lib/musicality/notation/model/score.rb +70 -44
  36. data/lib/musicality/notation/model/symbols.rb +22 -0
  37. data/lib/musicality/notation/packing/score_packing.rb +2 -3
  38. data/lib/musicality/notation/parsing/articulation_parsing.rb +4 -4
  39. data/lib/musicality/notation/parsing/articulation_parsing.treetop +2 -2
  40. data/lib/musicality/notation/parsing/link_nodes.rb +2 -14
  41. data/lib/musicality/notation/parsing/link_parsing.rb +9 -107
  42. data/lib/musicality/notation/parsing/link_parsing.treetop +4 -12
  43. data/lib/musicality/notation/parsing/note_node.rb +23 -21
  44. data/lib/musicality/notation/parsing/note_parsing.rb +70 -70
  45. data/lib/musicality/notation/parsing/note_parsing.treetop +6 -3
  46. data/lib/musicality/notation/parsing/pitch_node.rb +4 -2
  47. data/lib/musicality/performance/conversion/score_collator.rb +3 -3
  48. data/lib/musicality/performance/midi/midi_util.rb +13 -6
  49. data/lib/musicality/performance/midi/score_sequencing.rb +17 -0
  50. data/lib/musicality/printing/lilypond/errors.rb +5 -0
  51. data/lib/musicality/printing/lilypond/meter_engraving.rb +11 -0
  52. data/lib/musicality/printing/lilypond/note_engraving.rb +53 -0
  53. data/lib/musicality/printing/lilypond/part_engraver.rb +12 -0
  54. data/lib/musicality/printing/lilypond/pitch_engraving.rb +30 -0
  55. data/lib/musicality/printing/lilypond/score_engraver.rb +78 -0
  56. data/lib/musicality/version.rb +1 -1
  57. data/spec/composition/generation/random_rhythm_generator_spec.rb +50 -0
  58. data/spec/composition/model/pitch_class_spec.rb +75 -0
  59. data/spec/composition/model/pitch_classes_spec.rb +24 -0
  60. data/spec/composition/model/scale_class_spec.rb +98 -0
  61. data/spec/composition/model/scale_spec.rb +110 -0
  62. data/spec/composition/note_generation_spec.rb +113 -0
  63. data/spec/composition/transposition_spec.rb +17 -0
  64. data/spec/composition/util/adding_sequence_spec.rb +176 -0
  65. data/spec/composition/util/compound_sequence_spec.rb +50 -0
  66. data/spec/composition/util/probabilities_spec.rb +39 -0
  67. data/spec/composition/util/random_sampler_spec.rb +47 -0
  68. data/spec/composition/util/repeating_sequence_spec.rb +151 -0
  69. data/spec/notation/conversion/score_conversion_spec.rb +3 -3
  70. data/spec/notation/conversion/score_converter_spec.rb +24 -24
  71. data/spec/notation/model/link_spec.rb +27 -25
  72. data/spec/notation/model/note_spec.rb +9 -6
  73. data/spec/notation/model/pitch_spec.rb +24 -1
  74. data/spec/notation/model/score_spec.rb +57 -16
  75. data/spec/notation/packing/score_packing_spec.rb +134 -206
  76. data/spec/notation/parsing/articulation_parsing_spec.rb +1 -8
  77. data/spec/notation/parsing/convenience_methods_spec.rb +1 -1
  78. data/spec/notation/parsing/link_nodes_spec.rb +3 -4
  79. data/spec/notation/parsing/link_parsing_spec.rb +10 -4
  80. data/spec/notation/parsing/note_node_spec.rb +8 -7
  81. data/spec/notation/parsing/note_parsing_spec.rb +9 -12
  82. data/spec/performance/conversion/score_collator_spec.rb +14 -14
  83. data/spec/performance/midi/midi_util_spec.rb +26 -0
  84. data/spec/performance/midi/score_sequencer_spec.rb +1 -1
  85. metadata +57 -12
  86. data/lib/musicality/notation/model/program.rb +0 -53
  87. data/lib/musicality/notation/packing/program_packing.rb +0 -16
  88. data/spec/notation/model/program_spec.rb +0 -50
  89. data/spec/notation/packing/program_packing_spec.rb +0 -33
@@ -0,0 +1,50 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe CompoundSequence do
4
+ seqs = [ AddingSequence.new([1,1,0,2,-1]),
5
+ RepeatingSequence.new([0,1,0,5,-13]) ]
6
+
7
+ describe "#at" do
8
+ context 'given single offset' do
9
+ [ :+, :* ].each do |sym|
10
+ cseq = CompoundSequence.new(sym,seqs)
11
+ context "given #{sym} as combine method" do
12
+ it "should get a value from each sequence using #at and combine using #{sym}" do
13
+ [0, 1, -5, 33].each do |offset|
14
+ vals = seqs.map {|s| s.at(offset) }
15
+ val = vals[1..-1].inject(vals.first,sym)
16
+ val2 = cseq.send(:at,offset)
17
+ val2.should eq(val)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
24
+
25
+ { :at => [[-5,1,33,2,0,-11], [-3,-2,-1,0,1,2,-3,-2,-1]],
26
+ :take => [ 0, 5, 10, 13 ],
27
+ :take_back => [ 0, 2, 6, 15 ],
28
+ :over => [ 0..12, -3...5, -10..-3 ]
29
+ }.each do |method,args|
30
+ describe "##{method}" do
31
+ [ :+, :* ].each do |sym|
32
+ cseq = CompoundSequence.new(sym,seqs)
33
+ context "given #{sym} as combine method" do
34
+ it "should get values from each sequence using #{method} and combine each set of values using #{sym}" do
35
+ args.each do |arg|
36
+ enums = seqs.map {|s| s.send(method,arg) }
37
+ n = arg.is_a?(Fixnum) ? arg : arg.size
38
+ vals = Array.new(n) do |i|
39
+ _vals = enums.map {|e| e.next }
40
+ _vals[1..-1].inject(_vals.first,sym)
41
+ end
42
+ vals2 = cseq.send(method,arg).to_a
43
+ vals2.should eq(vals)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,39 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ require 'set'
4
+
5
+ describe Probabilities do
6
+ [:random,:uniform].each do |class_method|
7
+ describe ".#{class_method}" do
8
+ it 'should return array of given size, with sum of 1' do
9
+ (1..10).step(2) do |n|
10
+ 5.times do
11
+ x = Probabilities.send(class_method,n)
12
+ x.size.should eq(n)
13
+ x.inject(0,:+).should eq(1)
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+
20
+ describe '.random' do
21
+ it 'should return array of all-different values' do
22
+ x = Probabilities.random(100)
23
+ Set.new(x).size.should eq(100)
24
+ end
25
+ end
26
+
27
+ describe '.uniform' do
28
+ it 'should return array of all (or all-but-one) same values' do
29
+ [2,6,10,33,78,100].each do |n|
30
+ x = Probabilities.uniform(n)
31
+ y = Set.new(x)
32
+ (y.size == 1 || y.size == 2).should eq(true)
33
+ if y.size == 2
34
+ y.entries[0].should be_within(1e-9).of(y.entries[1])
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,47 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe RandomSampler do
4
+ describe '#initialize' do
5
+ context 'given probabilities that do not add up to 1' do
6
+ it 'should raise ArgumentError' do
7
+ [ [[1,2],[0.4,0.59]],
8
+ [[1/2.to_r, 1/4.to_r],[0.5,0.5001]] ].each do |vals,probs|
9
+ expect { RandomSampler.new(vals,probs) }.to raise_error(ArgumentError)
10
+ end
11
+ end
12
+ end
13
+ end
14
+
15
+ before :all do
16
+ @samplers = [
17
+ [[ 1/8.to_r, 1/4.to_r, 1/2.to_r ], [0.25, 0.5, 0.25 ]],
18
+ [[ 1/6.to_r, 1/4.to_r, 1/3.to_r, 1/12.to_r], [0.25,0.25,0.25,0.25]]
19
+ ].map {|vals,probs| RandomSampler.new(vals,probs) }
20
+ end
21
+
22
+ describe '#sample' do
23
+ context 'given no arg' do
24
+ it 'should return a random value, according to the probabilities given at initialization' do
25
+ @samplers.each do |sampler|
26
+ counts = Hash[ sampler.values.map {|val| [val,0] } ]
27
+ 1000.times { counts[sampler.sample] += 1 }
28
+ sampler.values.each_with_index do |val,i|
29
+ count = counts[val]
30
+ tgt_prob = sampler.probabilities[i]
31
+ (count / 1000.to_f).should be_within(0.05).of(tgt_prob)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
37
+ context 'given number of samples to take' do
38
+ it 'should return array with the given number of samples' do
39
+ @samplers.each do |sampler|
40
+ [1,2,5,10].each do |n|
41
+ sampler.sample(n).size.should eq(n)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,151 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
+
3
+ describe RepeatingSequence do
4
+ describe '#initialize' do
5
+ context 'given an empty pattern' do
6
+ it 'should raise EmptyError' do
7
+ expect do
8
+ RepeatingSequence.new([])
9
+ end.to raise_error(EmptyError)
10
+ end
11
+ end
12
+ end
13
+
14
+ describe '#pattern_size' do
15
+ it 'should return the pattern size' do
16
+ RepeatingSequence.new([1,2,3,4,5]).pattern_size.should eq(5)
17
+ end
18
+ end
19
+
20
+ before :all do
21
+ @pattern = [2,1,5,4,3]
22
+ @seq = RepeatingSequence.new(@pattern)
23
+ end
24
+
25
+ describe '#at' do
26
+ context 'given single offset' do
27
+ it 'should module index into pattern using given offset' do
28
+ n = @pattern.size
29
+ (0..n*2).each do |i|
30
+ @seq.at(i).should eq(@pattern[i%n])
31
+ end
32
+ end
33
+ end
34
+
35
+ context 'given array of offsets' do
36
+ context 'not given block' do
37
+ it 'should return enumerator' do
38
+ @seq.at([1,2,3]).should be_a Enumerator
39
+ end
40
+ end
41
+
42
+ context 'given block' do
43
+ it 'should yield sequence value for each offset' do
44
+ [ (0..@seq.pattern_size).to_a, (-@seq.pattern_size..0).to_a,
45
+ [-5,11,0,-33,2,15,-8] ].each do |offsets|
46
+ @seq.at(offsets).each_with_index do |val,i|
47
+ val.should eq(@seq.at(offsets[i]))
48
+ end
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+
55
+ describe '#take' do
56
+ context 'given negative integer' do
57
+ it 'should raise NegativeError' do
58
+ expect { @seq.take(-1) }.to raise_error(NegativeError)
59
+ expect { @seq.take(-10) }.to raise_error(NegativeError)
60
+ end
61
+ end
62
+
63
+ context 'given 0' do
64
+ it 'should return empty array' do
65
+ @seq.take(0).to_a.should eq([])
66
+ end
67
+ end
68
+
69
+ context 'given positive integer' do
70
+ context 'given block' do
71
+ it 'should yield the given number of pattern elements in forward direction (repeating as necessary)' do
72
+ i = 0
73
+ @seq.take(@pattern.size*2+3) do |n|
74
+ n.should eq(@seq.at(i))
75
+ i += 1
76
+ end
77
+ end
78
+ end
79
+
80
+ context 'no block given' do
81
+ it 'should return an enumerator' do
82
+ @seq.take(20).should be_a Enumerator
83
+ end
84
+ end
85
+ end
86
+ end
87
+
88
+ describe '#take_back' do
89
+ context 'given negative integer' do
90
+ it 'should raise NegativeError' do
91
+ expect { @seq.take_back(-1) }.to raise_error(NegativeError)
92
+ expect { @seq.take_back(-10) }.to raise_error(NegativeError)
93
+ end
94
+ end
95
+
96
+ context 'given 0' do
97
+ it 'should return empty array' do
98
+ @seq.take_back(0).to_a.should eq([])
99
+ end
100
+ end
101
+
102
+ context 'given positive integer' do
103
+ context 'given block' do
104
+ it 'should yield the given number of pattern elements in backward direction (repeating as necessary)' do
105
+ i, m = 0, @pattern.size*2+3
106
+ @seq.take_back(m) do |n|
107
+ n.should eq(@seq.at(i-1))
108
+ i -= 1
109
+ end
110
+ (-i).should eq(m)
111
+ end
112
+ end
113
+
114
+ context 'no block given' do
115
+ it 'should return an enumerator' do
116
+ @seq.take_back(20).should be_a Enumerator
117
+ end
118
+ end
119
+ end
120
+ end
121
+
122
+ describe '#over' do
123
+ context 'given empty (invalid) range' do
124
+ it 'should raise EmptyError' do
125
+ [ 3...-2, 0...0, 5..2, -3..-5 ].each do |range|
126
+ expect { @seq.over(range) }.to raise_error(EmptyError)
127
+ end
128
+ end
129
+ end
130
+
131
+ context 'given range over positive indices' do
132
+ it 'should return seq values at all offsets in range' do
133
+ [ 0..0, 0..2, 1...10, 4..17 ].each do |range|
134
+ vals = @seq.over(range).to_a
135
+ vals2 = range.map {|i| @seq.at(i) }
136
+ vals.should eq(vals2)
137
+ end
138
+ end
139
+ end
140
+
141
+ context 'given negative min and/or max' do
142
+ it 'should return seq values at all offsets in range' do
143
+ [ -5..2, -10..-7, -1...1 ].each do |range|
144
+ vals = @seq.over(range).to_a
145
+ vals2 = range.map {|i| @seq.at(i) }
146
+ vals.should eq(vals2)
147
+ end
148
+ end
149
+ end
150
+ end
151
+ end
@@ -13,7 +13,7 @@ describe Score::Measured do
13
13
  }
14
14
  )
15
15
  }
16
- @prog = Program.new([0...3,4...7,1...20,17..."45/2".to_r])
16
+ @prog = [0...3,4...7,1...20,17..."45/2".to_r]
17
17
  tcs = {
18
18
  0 => Change::Immediate.new(120),
19
19
  4 => Change::Gradual.linear(60,2),
@@ -63,7 +63,7 @@ describe Score::Measured do
63
63
  end
64
64
 
65
65
  it 'should include offsets from program segments' do
66
- @score.program.segments.each do |seg|
66
+ @score.program.each do |seg|
67
67
  @moffs.should include(seg.first)
68
68
  @moffs.should include(seg.last)
69
69
  end
@@ -153,7 +153,7 @@ describe Score::Unmeasured do
153
153
  }
154
154
  )
155
155
  }
156
- @prog = Program.new([0...3,4...7,1...20,17..."45/2".to_r])
156
+ @prog = [0...3,4...7,1...20,17..."45/2".to_r]
157
157
  tcs = {
158
158
  0 => Change::Immediate.new(120),
159
159
  4 => Change::Gradual.linear(60,2),
@@ -74,32 +74,32 @@ describe ScoreConverter::Measured do
74
74
 
75
75
  describe '#convert_program' do
76
76
  before :each do
77
- @prog = Program.new([0...4,2...5])
77
+ @prog = [0...4,2...5]
78
78
  @score = Score::Measured.new(FOUR_FOUR, 120, program: @prog)
79
79
  @converter = ScoreConverter::Measured.new(@score,200)
80
80
  end
81
81
 
82
- it 'shuld return Program with same number of segments' do
82
+ it 'shuld return array with same size' do
83
83
  prog = @converter.convert_program
84
- prog.should be_a Program
85
- prog.segments.size.should eq(@score.program.segments.size)
84
+ prog.should be_a Array
85
+ prog.size.should eq(@score.program.size)
86
86
  end
87
87
 
88
88
  it 'should convert program segments offsets from measure-based to note-based' do
89
89
  prog = ScoreConverter::Measured.new(@score,200).convert_program
90
- prog.segments.size.should eq(2)
91
- prog.segments[0].first.should eq(0)
92
- prog.segments[0].last.should eq(8)
93
- prog.segments[1].first.should eq(4)
94
- prog.segments[1].last.should eq(10)
90
+ prog.size.should eq(2)
91
+ prog[0].first.should eq(0)
92
+ prog[0].last.should eq(8)
93
+ prog[1].first.should eq(4)
94
+ prog[1].last.should eq(10)
95
95
 
96
96
  @score.start_meter = THREE_FOUR
97
97
  prog = ScoreConverter::Measured.new(@score,200).convert_program
98
- prog.segments.size.should eq(2)
99
- prog.segments[0].first.should eq(0)
100
- prog.segments[0].last.should eq(6)
101
- prog.segments[1].first.should eq(3)
102
- prog.segments[1].last.should eq(7.5)
98
+ prog.size.should eq(2)
99
+ prog[0].first.should eq(0)
100
+ prog[0].last.should eq(6)
101
+ prog[1].first.should eq(3)
102
+ prog[1].last.should eq(7.5)
103
103
  end
104
104
  end
105
105
 
@@ -111,7 +111,7 @@ describe ScoreConverter::Measured do
111
111
  end
112
112
 
113
113
  it 'should use output from convert_program' do
114
- prog = Program.new([0...4,2...5])
114
+ prog =[0...4,2...5]
115
115
  score = Score::Measured.new(FOUR_FOUR, 120, program: prog)
116
116
  converter = ScoreConverter::Measured.new(score,200)
117
117
  nscore = converter.convert_score
@@ -197,23 +197,23 @@ describe ScoreConverter::Unmeasured do
197
197
 
198
198
  describe '#convert_program' do
199
199
  before :each do
200
- @prog = Program.new([0...4,2...5])
200
+ @prog = [0...4,2...5]
201
201
  @score = Score::Unmeasured.new(120, program: @prog)
202
202
  @converter = ScoreConverter::Unmeasured.new(@score,200)
203
203
  @prog2 = @converter.convert_program
204
204
  end
205
205
 
206
- it 'should return Program with same number of segments' do
207
- @prog2.should be_a Program
208
- @prog2.segments.size.should eq(@prog.segments.size)
206
+ it 'should return array with same size' do
207
+ @prog2.should be_a Array
208
+ @prog2.size.should eq(@prog.size)
209
209
  end
210
210
 
211
211
  it 'should convert program segments offsets from note-based to time-based' do
212
212
  prog = @prog2
213
- prog.segments[0].first.should eq(0)
214
- prog.segments[0].last.should eq(8)
215
- prog.segments[1].first.should eq(4)
216
- prog.segments[1].last.should eq(10)
213
+ prog[0].first.should eq(0)
214
+ prog[0].last.should eq(8)
215
+ prog[1].first.should eq(4)
216
+ prog[1].last.should eq(10)
217
217
  end
218
218
  end
219
219
 
@@ -225,7 +225,7 @@ describe ScoreConverter::Unmeasured do
225
225
  end
226
226
 
227
227
  it 'should use output from convert_program' do
228
- prog = Program.new([0...4,2...5])
228
+ prog = [0...4,2...5]
229
229
  score = Score::Unmeasured.new(120, program: prog)
230
230
  converter = ScoreConverter::Unmeasured.new(score,200)
231
231
  nscore = converter.convert_score
@@ -1,83 +1,85 @@
1
1
  require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
2
2
 
3
- {
4
- Link::Glissando => Link::Portamento,
5
- Link::Portamento => Link::Glissando,
6
- Link::Slur => Link::Legato,
7
- Link::Legato => Link::Slur
8
- }.each do |klass,klass2|
3
+ [
4
+ [Link::Glissando, Link::Portamento, LINK_SYMBOLS[Links::GLISSANDO]],
5
+ [Link::Portamento, Link::Glissando, LINK_SYMBOLS[Links::PORTAMENTO]],
6
+ ].each do |klass,klass2,link_symbol|
9
7
  describe klass do
8
+ before :all do
9
+ @tgt_pitch = C2
10
+ @obj = klass.new(@tgt_pitch)
11
+ end
12
+
10
13
  describe '#initialize' do
11
14
  it 'should assign the given pitch to :target_pitch' do
12
- klass.new(C2).target_pitch.should eq(C2)
15
+ @obj.target_pitch.should eq(@tgt_pitch)
13
16
  end
14
17
  end
15
18
 
16
19
  describe '#==' do
17
20
  it 'should return true if two links have the same target pitch' do
18
- klass.new(C2).should eq(klass.new(C2))
21
+ @obj.should eq(klass.new(@tgt_pitch))
19
22
  end
20
23
 
21
24
  it 'should return false if two links do not have the same target pitch' do
22
- klass.new(C2).should_not eq(klass.new(F5))
25
+ @obj.should_not eq(klass.new(@tgt_pitch.transpose(1)))
23
26
  end
24
27
 
25
28
  it 'should return false if the link type is different' do
26
- klass.new(C2).should_not eq(klass2.new(C2))
29
+ @obj.should_not eq(klass2.new(@tgt_pitch))
27
30
  end
28
31
  end
29
32
 
30
33
  describe '#clone' do
31
34
  it 'should return a link equal to original' do
32
- l = klass.new(C4)
33
- l.clone.should eq l
35
+ @obj.clone.should eq @obj
34
36
  end
35
37
  end
36
38
 
37
39
  describe '#to_yaml' do
38
40
  it 'should produce YAML that can be loaded' do
39
- l = klass.new(C5)
40
- YAML.load(l.to_yaml).should eq l
41
+ YAML.load(@obj.to_yaml).should eq @obj
41
42
  end
42
43
  end
43
44
 
44
45
  describe '#to_s' do
45
46
  it 'should produce string that include link char and target pitch str' do
46
- l = klass.new(C3)
47
- l.to_s.should eq(l.link_char + "C3")
47
+ @obj.to_s.should eq(link_symbol + @tgt_pitch.to_s)
48
48
  end
49
49
  end
50
50
  end
51
51
  end
52
52
 
53
53
  describe Link::Tie do
54
+ before :all do
55
+ @obj = Link::Tie.new
56
+ end
57
+
54
58
  describe '#==' do
55
59
  it 'should return true if another Tie object is given' do
56
- Link::Tie.new.should eq(Link::Tie.new)
60
+ @obj.should eq(Link::Tie.new)
57
61
  end
58
62
 
59
- it 'should return false if a non-Tie object is given' do
60
- Link::Tie.new.should_not eq(Link::Portamento.new(C2))
63
+ it 'should return false if an object of another class is given' do
64
+ @obj.should_not eq(5)
61
65
  end
62
66
  end
63
67
 
64
68
  describe '#clone' do
65
69
  it 'should return a link equal to original' do
66
- l = Link::Tie.new
67
- l.clone.should eq l
70
+ @obj.clone.should eq @obj
68
71
  end
69
72
  end
70
73
 
71
74
  describe '#to_yaml' do
72
75
  it 'should produce YAML that can be loaded' do
73
- l = Link::Tie.new
74
- YAML.load(l.to_yaml).should eq l
76
+ YAML.load(@obj.to_yaml).should eq @obj
75
77
  end
76
78
  end
77
79
 
78
80
  describe '#to_s' do
79
- it 'should return =' do
80
- Link::Tie.new.to_s.should eq("=")
81
+ it "should return #{LINK_SYMBOLS[Links::TIE]}" do
82
+ @obj.to_s.should eq(LINK_SYMBOLS[Links::TIE])
81
83
  end
82
84
  end
83
85
  end