mtk 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (147) hide show
  1. data/.yardopts +3 -2
  2. data/DEVELOPMENT_NOTES.md +114 -0
  3. data/INTRO.md +64 -8
  4. data/LICENSE.txt +1 -1
  5. data/README.md +31 -102
  6. data/Rakefile +56 -18
  7. data/bin/mtk +215 -0
  8. data/examples/crescendo.rb +5 -5
  9. data/examples/drum_pattern1.rb +23 -0
  10. data/examples/dynamic_pattern.rb +8 -11
  11. data/examples/gets_and_play.rb +26 -0
  12. data/examples/notation.rb +22 -0
  13. data/examples/play_midi.rb +8 -10
  14. data/examples/random_tone_row.rb +2 -2
  15. data/examples/syntax_to_midi.rb +28 -0
  16. data/examples/test_output.rb +8 -0
  17. data/examples/tone_row_melody.rb +6 -6
  18. data/lib/mtk.rb +52 -40
  19. data/lib/mtk/chord.rb +55 -0
  20. data/lib/mtk/constants/durations.rb +57 -0
  21. data/lib/mtk/constants/intensities.rb +61 -0
  22. data/lib/mtk/constants/intervals.rb +73 -0
  23. data/lib/mtk/constants/pitch_classes.rb +29 -0
  24. data/lib/mtk/constants/pitches.rb +52 -0
  25. data/lib/mtk/duration.rb +211 -0
  26. data/lib/mtk/events/event.rb +119 -0
  27. data/lib/mtk/events/note.rb +112 -0
  28. data/lib/mtk/events/parameter.rb +54 -0
  29. data/lib/mtk/helpers/collection.rb +164 -0
  30. data/lib/mtk/helpers/convert.rb +36 -0
  31. data/lib/mtk/helpers/lilypond.rb +162 -0
  32. data/lib/mtk/helpers/output_selector.rb +67 -0
  33. data/lib/mtk/helpers/pitch_collection.rb +23 -0
  34. data/lib/mtk/helpers/pseudo_constants.rb +26 -0
  35. data/lib/mtk/intensity.rb +156 -0
  36. data/lib/mtk/interval.rb +155 -0
  37. data/lib/mtk/lang/mtk_grammar.citrus +190 -13
  38. data/lib/mtk/lang/parser.rb +29 -0
  39. data/lib/mtk/melody.rb +94 -0
  40. data/lib/mtk/midi/dls_synth_device.rb +144 -0
  41. data/lib/mtk/midi/dls_synth_output.rb +62 -0
  42. data/lib/mtk/midi/file.rb +67 -32
  43. data/lib/mtk/midi/input.rb +97 -0
  44. data/lib/mtk/midi/jsound_input.rb +36 -17
  45. data/lib/mtk/midi/jsound_output.rb +48 -46
  46. data/lib/mtk/midi/output.rb +195 -0
  47. data/lib/mtk/midi/unimidi_input.rb +117 -0
  48. data/lib/mtk/midi/unimidi_output.rb +121 -0
  49. data/lib/mtk/{_numeric_extensions.rb → numeric_extensions.rb} +12 -0
  50. data/lib/mtk/patterns/chain.rb +49 -0
  51. data/lib/mtk/{pattern → patterns}/choice.rb +14 -8
  52. data/lib/mtk/patterns/cycle.rb +18 -0
  53. data/lib/mtk/patterns/for_each.rb +71 -0
  54. data/lib/mtk/patterns/function.rb +39 -0
  55. data/lib/mtk/{pattern → patterns}/lines.rb +11 -17
  56. data/lib/mtk/{pattern → patterns}/palindrome.rb +11 -8
  57. data/lib/mtk/patterns/pattern.rb +171 -0
  58. data/lib/mtk/patterns/sequence.rb +20 -0
  59. data/lib/mtk/pitch.rb +7 -6
  60. data/lib/mtk/pitch_class.rb +124 -46
  61. data/lib/mtk/pitch_class_set.rb +58 -35
  62. data/lib/mtk/sequencers/event_builder.rb +131 -0
  63. data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
  64. data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
  65. data/lib/mtk/{sequencer/abstract_sequencer.rb → sequencers/sequencer.rb} +37 -11
  66. data/lib/mtk/{sequencer → sequencers}/step_sequencer.rb +4 -4
  67. data/lib/mtk/timeline.rb +39 -22
  68. data/lib/mtk/variable.rb +32 -0
  69. data/spec/mtk/chord_spec.rb +83 -0
  70. data/spec/mtk/{_constants → constants}/durations_spec.rb +12 -41
  71. data/spec/mtk/{_constants → constants}/intensities_spec.rb +13 -37
  72. data/spec/mtk/{_constants → constants}/intervals_spec.rb +14 -32
  73. data/spec/mtk/{_constants → constants}/pitch_classes_spec.rb +8 -4
  74. data/spec/mtk/{_constants → constants}/pitches_spec.rb +5 -1
  75. data/spec/mtk/duration_spec.rb +372 -0
  76. data/spec/mtk/events/event_spec.rb +234 -0
  77. data/spec/mtk/events/note_spec.rb +174 -0
  78. data/spec/mtk/events/parameter_spec.rb +220 -0
  79. data/spec/mtk/{helper → helpers}/collection_spec.rb +86 -3
  80. data/spec/mtk/{helper → helpers}/pseudo_constants_spec.rb +2 -2
  81. data/spec/mtk/intensity_spec.rb +289 -0
  82. data/spec/mtk/interval_spec.rb +265 -0
  83. data/spec/mtk/lang/parser_spec.rb +597 -0
  84. data/spec/mtk/melody_spec.rb +223 -0
  85. data/spec/mtk/midi/file_spec.rb +16 -16
  86. data/spec/mtk/midi/jsound_input_spec.rb +11 -0
  87. data/spec/mtk/midi/jsound_output_spec.rb +11 -0
  88. data/spec/mtk/midi/output_spec.rb +102 -0
  89. data/spec/mtk/midi/unimidi_input_spec.rb +11 -0
  90. data/spec/mtk/midi/unimidi_output_spec.rb +11 -0
  91. data/spec/mtk/{_numeric_extensions_spec.rb → numeric_extensions_spec.rb} +1 -0
  92. data/spec/mtk/patterns/chain_spec.rb +110 -0
  93. data/spec/mtk/{pattern → patterns}/choice_spec.rb +20 -30
  94. data/spec/mtk/{pattern → patterns}/cycle_spec.rb +25 -35
  95. data/spec/mtk/patterns/for_each_spec.rb +136 -0
  96. data/spec/mtk/{pattern → patterns}/function_spec.rb +17 -30
  97. data/spec/mtk/{pattern → patterns}/lines_spec.rb +11 -27
  98. data/spec/mtk/{pattern → patterns}/palindrome_spec.rb +13 -29
  99. data/spec/mtk/patterns/pattern_spec.rb +132 -0
  100. data/spec/mtk/patterns/sequence_spec.rb +203 -0
  101. data/spec/mtk/pitch_class_set_spec.rb +23 -21
  102. data/spec/mtk/pitch_class_spec.rb +151 -39
  103. data/spec/mtk/pitch_spec.rb +22 -1
  104. data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
  105. data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
  106. data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
  107. data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
  108. data/spec/mtk/{sequencer → sequencers}/step_sequencer_spec.rb +35 -13
  109. data/spec/mtk/timeline_spec.rb +109 -16
  110. data/spec/mtk/variable_spec.rb +52 -0
  111. data/spec/spec_coverage.rb +2 -0
  112. data/spec/spec_helper.rb +3 -0
  113. metadata +188 -91
  114. data/lib/mtk/_constants/durations.rb +0 -80
  115. data/lib/mtk/_constants/intensities.rb +0 -81
  116. data/lib/mtk/_constants/intervals.rb +0 -85
  117. data/lib/mtk/_constants/pitch_classes.rb +0 -35
  118. data/lib/mtk/_constants/pitches.rb +0 -49
  119. data/lib/mtk/event.rb +0 -70
  120. data/lib/mtk/helper/collection.rb +0 -114
  121. data/lib/mtk/helper/event_builder.rb +0 -85
  122. data/lib/mtk/helper/pseudo_constants.rb +0 -26
  123. data/lib/mtk/lang/grammar.rb +0 -17
  124. data/lib/mtk/note.rb +0 -63
  125. data/lib/mtk/pattern/abstract_pattern.rb +0 -132
  126. data/lib/mtk/pattern/cycle.rb +0 -51
  127. data/lib/mtk/pattern/enumerator.rb +0 -26
  128. data/lib/mtk/pattern/function.rb +0 -46
  129. data/lib/mtk/pattern/sequence.rb +0 -30
  130. data/lib/mtk/pitch_set.rb +0 -84
  131. data/lib/mtk/sequencer/rhythmic_sequencer.rb +0 -29
  132. data/lib/mtk/transform/invertible.rb +0 -15
  133. data/lib/mtk/transform/mappable.rb +0 -18
  134. data/lib/mtk/transform/set_theory_operations.rb +0 -34
  135. data/lib/mtk/transform/transposable.rb +0 -14
  136. data/spec/mtk/event_spec.rb +0 -139
  137. data/spec/mtk/helper/event_builder_spec.rb +0 -92
  138. data/spec/mtk/lang/grammar_spec.rb +0 -100
  139. data/spec/mtk/note_spec.rb +0 -115
  140. data/spec/mtk/pattern/abstract_pattern_spec.rb +0 -45
  141. data/spec/mtk/pattern/note_cycle_spec.rb.bak +0 -116
  142. data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +0 -47
  143. data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +0 -37
  144. data/spec/mtk/pattern/sequence_spec.rb +0 -151
  145. data/spec/mtk/pitch_set_spec.rb +0 -198
  146. data/spec/mtk/sequencer/abstract_sequencer_spec.rb +0 -159
  147. data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +0 -49
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe MTK::Pattern::Function do
3
+ describe MTK::Patterns::Function do
4
4
 
5
- FUNCTION = MTK::Pattern::Function
5
+ FUNCTION = MTK::Patterns::Function
6
6
 
7
7
  describe "#next" do
8
8
  it "calls a lambda to produce elements" do
@@ -35,7 +35,7 @@ describe MTK::Pattern::Function do
35
35
  end
36
36
 
37
37
  it "calls a 3-arg lambda with the previous value, function call count (starting from 0), and element count (starting from 0)" do
38
- function = FUNCTION.new lambda{|prev,call_index,elem_index| prev.nil? ? MTK::Pattern.Sequence(1,2,3,4) : [call_index,elem_index] }
38
+ function = FUNCTION.new lambda{|prev,call_index,elem_index| prev.nil? ? MTK::Patterns.Sequence(1,2,3,4) : [call_index,elem_index] }
39
39
  function.next.should == 1
40
40
  function.next.should == 2
41
41
  function.next.should == 3
@@ -44,7 +44,7 @@ describe MTK::Pattern::Function do
44
44
  end
45
45
 
46
46
  it "can generate other Patterns, which will be iterated over before re-calling the function" do
47
- function = FUNCTION.new lambda{|prev,index| MTK::Pattern.Sequence(index,2,3) }
47
+ function = FUNCTION.new lambda{|prev,index| MTK::Patterns.Sequence(index,2,3) }
48
48
  function.next.should == 0
49
49
  function.next.should == 2
50
50
  function.next.should == 3
@@ -67,66 +67,53 @@ describe MTK::Pattern::Function do
67
67
  end
68
68
 
69
69
 
70
- describe MTK::Pattern do
70
+ describe MTK::Patterns do
71
+
72
+ let(:mock_lambda) { lambda{|_|:mock_value} }
71
73
 
72
74
  describe "#Function" do
73
75
  it "creates a Function" do
74
- MTK::Pattern.Function(nil).should be_a MTK::Pattern::Function
76
+ MTK::Patterns.Function(nil).should be_a MTK::Patterns::Function
75
77
  end
76
78
 
77
79
  it "sets #elements from the varargs" do
78
- MTK::Pattern.Function(:mock_lambda).function.should == :mock_lambda
79
- end
80
-
81
- it "does not set a type" do
82
- MTK::Pattern.Function(:mock_lambda).type.should be_nil
80
+ MTK::Patterns.Function(:mock_lambda).function.should == :mock_lambda
83
81
  end
84
82
 
85
83
  it "doesn't wrap a lambda in the varargs Array" do
86
- function = MTK::Pattern.Function( lambda{ 1 + 1 } )
84
+ function = MTK::Patterns.Function( lambda{ 1 + 1 } )
87
85
  function.next.should == 2
88
86
  end
89
87
  end
90
88
 
91
89
  describe "#PitchFunction" do
92
90
  it "creates a Function" do
93
- MTK::Pattern.PitchFunction(:mock_lambda).should be_a MTK::Pattern::Function
91
+ MTK::Patterns.PitchFunction(mock_lambda).should be_a MTK::Patterns::Function
94
92
  end
95
93
 
96
94
  it "sets #elements from the varargs" do
97
- MTK::Pattern.PitchFunction(:mock_lambda).function.should == :mock_lambda
98
- end
99
-
100
- it "sets #type to :pitch" do
101
- MTK::Pattern.PitchFunction([]).type.should == :pitch
95
+ func = mock_lambda
96
+ MTK::Patterns.PitchFunction(func).function.should == func
102
97
  end
103
98
  end
104
99
 
105
100
  describe "#IntensityFunction" do
106
101
  it "creates a Function" do
107
- MTK::Pattern.IntensityFunction(:mock_lambda).should be_a MTK::Pattern::Function
102
+ MTK::Patterns.IntensityFunction(mock_lambda).should be_a MTK::Patterns::Function
108
103
  end
109
104
 
110
105
  it "sets #elements from the varargs" do
111
- MTK::Pattern.IntensityFunction(:mock_lambda).function.should == :mock_lambda
112
- end
113
-
114
- it "sets #type to :pitch" do
115
- MTK::Pattern.IntensityFunction([]).type.should == :intensity
106
+ MTK::Patterns.IntensityFunction(mock_lambda).function.should == mock_lambda
116
107
  end
117
108
  end
118
109
 
119
110
  describe "#DurationFunction" do
120
111
  it "creates a Function" do
121
- MTK::Pattern.DurationFunction(:mock_lambda).should be_a MTK::Pattern::Function
112
+ MTK::Patterns.DurationFunction(mock_lambda).should be_a MTK::Patterns::Function
122
113
  end
123
114
 
124
115
  it "sets #elements from the varargs" do
125
- MTK::Pattern.DurationFunction(:mock_lambda).function.should == :mock_lambda
126
- end
127
-
128
- it "sets #type to :pitch" do
129
- MTK::Pattern.DurationFunction([]).type.should == :duration
116
+ MTK::Patterns.DurationFunction(mock_lambda).function.should == mock_lambda
130
117
  end
131
118
  end
132
119
 
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe MTK::Pattern::Lines do
3
+ describe MTK::Patterns::Lines do
4
4
 
5
- LINES = MTK::Pattern::Lines
5
+ LINES = MTK::Patterns::Lines
6
6
 
7
7
  let(:elements) { [0, [10,5], [5,10]] }
8
8
  let(:lines) { LINES.new elements }
@@ -32,61 +32,45 @@ describe MTK::Pattern::Lines do
32
32
  end
33
33
 
34
34
 
35
- describe MTK::Pattern do
35
+ describe MTK::Patterns do
36
36
 
37
37
  describe "#Lines" do
38
38
  it "creates a Lines" do
39
- MTK::Pattern.Lines(1,2,3).should be_a MTK::Pattern::Lines
39
+ MTK::Patterns.Lines(1,2,3).should be_a MTK::Patterns::Lines
40
40
  end
41
41
 
42
42
  it "sets #elements from the varargs" do
43
- MTK::Pattern.Lines(1,2,3).elements.should == [1,2,3]
44
- end
45
-
46
- it "does not set a type" do
47
- MTK::Pattern.Lines(1,2,3).type.should be_nil
43
+ MTK::Patterns.Lines(1,2,3).elements.should == [1,2,3]
48
44
  end
49
45
  end
50
46
 
51
47
  describe "#PitchLines" do
52
48
  it "creates a Lines" do
53
- MTK::Pattern.PitchLines(1,2,3).should be_a MTK::Pattern::Lines
49
+ MTK::Patterns.PitchLines(1,2,3).should be_a MTK::Patterns::Lines
54
50
  end
55
51
 
56
52
  it "sets #elements from the varargs" do
57
- MTK::Pattern.PitchLines(1,2,3).elements.should == [1,2,3]
58
- end
59
-
60
- it "sets #type to :pitch" do
61
- MTK::Pattern.PitchLines([]).type.should == :pitch
53
+ MTK::Patterns.PitchLines(1,2,3).elements.should == [Pitch(1),Pitch(2),Pitch(3)]
62
54
  end
63
55
  end
64
56
 
65
57
  describe "#IntensityLines" do
66
58
  it "creates a Lines" do
67
- MTK::Pattern.IntensityLines(1,2,3).should be_a MTK::Pattern::Lines
59
+ MTK::Patterns.IntensityLines(1,2,3).should be_a MTK::Patterns::Lines
68
60
  end
69
61
 
70
62
  it "sets #elements from the varargs" do
71
- MTK::Pattern.IntensityLines(1,2,3).elements.should == [1,2,3]
72
- end
73
-
74
- it "sets #type to :pitch" do
75
- MTK::Pattern.IntensityLines([]).type.should == :intensity
63
+ MTK::Patterns.IntensityLines(1,2,3).elements.should == [Intensity(1),Intensity(2),Intensity(3)]
76
64
  end
77
65
  end
78
66
 
79
67
  describe "#DurationLines" do
80
68
  it "creates a Lines" do
81
- MTK::Pattern.DurationLines(1,2,3).should be_a MTK::Pattern::Lines
69
+ MTK::Patterns.DurationLines(1,2,3).should be_a MTK::Patterns::Lines
82
70
  end
83
71
 
84
72
  it "sets #elements from the varargs" do
85
- MTK::Pattern.DurationLines(1,2,3).elements.should == [1,2,3]
86
- end
87
-
88
- it "sets #type to :pitch" do
89
- MTK::Pattern.DurationLines([]).type.should == :duration
73
+ MTK::Patterns.DurationLines(1,2,3).elements.should == [Duration(1),Duration(2),Duration(3)]
90
74
  end
91
75
  end
92
76
 
@@ -1,8 +1,8 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe MTK::Pattern::Palindrome do
3
+ describe MTK::Patterns::Palindrome do
4
4
 
5
- PALINDROME = MTK::Pattern::Palindrome
5
+ PALINDROME = MTK::Patterns::Palindrome
6
6
 
7
7
  describe "#next" do
8
8
  it "reverses direction when the ends of the list are reached" do
@@ -20,14 +20,14 @@ describe MTK::Pattern::Palindrome do
20
20
  end
21
21
 
22
22
  it "enumerates nested sequences" do
23
- palindrome = PALINDROME.new [1, MTK::Pattern.Sequence(2,3), 4]
23
+ palindrome = PALINDROME.new [1, MTK::Patterns.Sequence(2,3), 4]
24
24
  nexts = []
25
25
  10.times { nexts << palindrome.next }
26
26
  nexts.should == [1,2,3,4, 2,3,1, 2,3,4] # note sequence goes forward in both directions!
27
27
  end
28
28
 
29
29
  it "enumerates nested sequences, and repeats the last element" do
30
- palindrome = PALINDROME.new [1, MTK::Pattern.Sequence(2,3), 4], :repeat_ends => true
30
+ palindrome = PALINDROME.new [1, MTK::Patterns.Sequence(2,3), 4], :repeat_ends => true
31
31
  nexts = []
32
32
  9.times { nexts << palindrome.next }
33
33
  nexts.should == [1,2,3,4, 4,2,3,1, 1] # note sequence goes forward in both directions!
@@ -63,61 +63,45 @@ describe MTK::Pattern::Palindrome do
63
63
  end
64
64
 
65
65
 
66
- describe MTK::Pattern do
66
+ describe MTK::Patterns do
67
67
 
68
68
  describe "#Palindrome" do
69
69
  it "creates a Palindrome" do
70
- MTK::Pattern.Palindrome(1,2,3).should be_a MTK::Pattern::Palindrome
70
+ MTK::Patterns.Palindrome(1,2,3).should be_a MTK::Patterns::Palindrome
71
71
  end
72
72
 
73
73
  it "sets #elements from the varargs" do
74
- MTK::Pattern.Palindrome(1,2,3).elements.should == [1,2,3]
75
- end
76
-
77
- it "does not set a type" do
78
- MTK::Pattern.Palindrome(1,2,3).type.should be_nil
74
+ MTK::Patterns.Palindrome(1,2,3).elements.should == [1,2,3]
79
75
  end
80
76
  end
81
77
 
82
78
  describe "#PitchPalindrome" do
83
79
  it "creates a Palindrome" do
84
- MTK::Pattern.PitchPalindrome(1,2,3).should be_a MTK::Pattern::Palindrome
80
+ MTK::Patterns.PitchPalindrome(1,2,3).should be_a MTK::Patterns::Palindrome
85
81
  end
86
82
 
87
83
  it "sets #elements from the varargs" do
88
- MTK::Pattern.PitchPalindrome(1,2,3).elements.should == [1,2,3]
89
- end
90
-
91
- it "sets #type to :pitch" do
92
- MTK::Pattern.PitchPalindrome([]).type.should == :pitch
84
+ MTK::Patterns.PitchPalindrome(1,2,3).elements.should == [Pitch(1),Pitch(2),Pitch(3)]
93
85
  end
94
86
  end
95
87
 
96
88
  describe "#IntensityPalindrome" do
97
89
  it "creates a Palindrome" do
98
- MTK::Pattern.IntensityPalindrome(1,2,3).should be_a MTK::Pattern::Palindrome
90
+ MTK::Patterns.IntensityPalindrome(1,2,3).should be_a MTK::Patterns::Palindrome
99
91
  end
100
92
 
101
93
  it "sets #elements from the varargs" do
102
- MTK::Pattern.IntensityPalindrome(1,2,3).elements.should == [1,2,3]
103
- end
104
-
105
- it "sets #type to :pitch" do
106
- MTK::Pattern.IntensityPalindrome([]).type.should == :intensity
94
+ MTK::Patterns.IntensityPalindrome(1,2,3).elements.should == [Intensity(1),Intensity(2),Intensity(3)]
107
95
  end
108
96
  end
109
97
 
110
98
  describe "#DurationPalindrome" do
111
99
  it "creates a Palindrome" do
112
- MTK::Pattern.DurationPalindrome(1,2,3).should be_a MTK::Pattern::Palindrome
100
+ MTK::Patterns.DurationPalindrome(1,2,3).should be_a MTK::Patterns::Palindrome
113
101
  end
114
102
 
115
103
  it "sets #elements from the varargs" do
116
- MTK::Pattern.DurationPalindrome(1,2,3).elements.should == [1,2,3]
117
- end
118
-
119
- it "sets #type to :pitch" do
120
- MTK::Pattern.DurationPalindrome([]).type.should == :duration
104
+ MTK::Patterns.DurationPalindrome(1,2,3).elements.should == [Duration(1),Duration(2),Duration(3)]
121
105
  end
122
106
  end
123
107
 
@@ -0,0 +1,132 @@
1
+ require 'spec_helper'
2
+
3
+ describe MTK::Patterns::Pattern do
4
+
5
+ PATTERN = MTK::Patterns::Pattern
6
+
7
+ let(:elements) { [1,2,3] }
8
+
9
+
10
+ describe "@min_elements" do
11
+ it "is the :min_elements option the pattern was constructed with" do
12
+ PATTERN.new([], min_elements: 1).min_elements.should == 1
13
+ end
14
+
15
+ it "is nil by default" do
16
+ PATTERN.new([]).min_elements.should be_nil
17
+ end
18
+
19
+ it "prevents a StopIteration error until min_elements have been emitted (overriding max_elements if necessary)" do
20
+ pattern = PATTERN.new([1,2,3], min_elements: 5, max_elements: 3)
21
+ 5.times{ pattern.next }
22
+ lambda{ pattern.next }.should raise_error StopIteration
23
+ end
24
+
25
+ it "sets exactly how many elements will be emitted when set to the same values as max_elements" do
26
+ pattern = PATTERN.new([1,2,3], min_elements: 5, max_elements: 5)
27
+ 5.times{ pattern.next }
28
+ lambda{ pattern.next }.should raise_error StopIteration
29
+ end
30
+
31
+ it "is maintained when applying Collection operations" do
32
+ PATTERN.new(elements, min_elements: 2).reverse.min_elements.should == 2
33
+ end
34
+ end
35
+
36
+ describe '#min_elements_unmet?' do
37
+ it "is true until min_elements have been emitted" do
38
+ pattern = PATTERN.new([:anything], min_elements: 5)
39
+ 5.times { pattern.min_elements_unmet?.should be_true and pattern.next }
40
+ pattern.min_elements_unmet?.should be_false
41
+ end
42
+
43
+ it "is always false if min_elements is not set" do
44
+ pattern = PATTERN.new([:anything], min_elements: nil)
45
+ 5.times { pattern.min_elements_unmet?.should be_false and pattern.next }
46
+ end
47
+
48
+ it "is always false if min_elements is 0" do
49
+ pattern = PATTERN.new([:anything], min_elements: 0)
50
+ 5.times { pattern.min_elements_unmet?.should be_false and pattern.next }
51
+ end
52
+ end
53
+
54
+
55
+ describe "@max_elements" do
56
+ it "is the :max_elements option the pattern was constructed with" do
57
+ PATTERN.new([], max_elements: 1).max_elements.should == 1
58
+ end
59
+
60
+ it "is nil by default" do
61
+ PATTERN.new([]).max_elements.should be_nil
62
+ end
63
+
64
+ it "causes a StopIteration exception once max_elements have been emitted" do
65
+ pattern = PATTERN.new([:anything], max_elements: 5)
66
+ 5.times { pattern.next }
67
+ lambda { pattern.next }.should raise_error
68
+ end
69
+
70
+ it "raises a StopIteration error when a nested pattern has emitted more than max_elements" do
71
+ pattern = PATTERN.new([Patterns.Cycle(1,2)], max_elements: 5)
72
+ 5.times{ pattern.next }
73
+ lambda{ pattern.next }.should raise_error StopIteration
74
+ end
75
+
76
+ it "is maintained when applying Collection operations" do
77
+ PATTERN.new(elements, max_elements: 2).reverse.max_elements.should == 2
78
+ end
79
+ end
80
+
81
+
82
+ describe '#max_elements_exceeded?' do
83
+ it "is false until max_elements have been emitted" do
84
+ pattern = PATTERN.new([:anything], max_elements: 5)
85
+ 5.times { pattern.max_elements_exceeded?.should be_false and pattern.next }
86
+ pattern.max_elements_exceeded?.should be_true
87
+ end
88
+
89
+ it "is always false when max_elements is not set" do
90
+ pattern = PATTERN.new([:anything], max_elements: nil)
91
+ 5.times { pattern.max_elements_exceeded?.should be_false and pattern.next }
92
+ end
93
+ end
94
+
95
+
96
+ describe "@max_cycles" do
97
+ it "is the :max_cycles option the pattern was constructed with" do
98
+ PATTERN.new([], max_cycles: 2).max_cycles.should == 2
99
+ end
100
+
101
+ it "is 1 by default" do
102
+ PATTERN.new([]).max_cycles.should == 1
103
+ end
104
+
105
+ it "is maintained when applying Collection operations" do
106
+ PATTERN.new(elements, max_cycles: 2).reverse.max_cycles.should == 2
107
+ end
108
+ end
109
+
110
+
111
+ describe "#next" do
112
+ it "raises StopIteration if elements is empty" do
113
+ lambda{ PATTERN.new([]).next }.should raise_error StopIteration
114
+ end
115
+ end
116
+
117
+
118
+ describe "#==" do
119
+ it "is true if the elements and types are equal" do
120
+ PATTERN.new(elements, :type => :some_type).should == PATTERN.new(elements, :type => :some_type)
121
+ end
122
+
123
+ it "is false if the elements are not equal" do
124
+ PATTERN.new(elements, :type => :some_type).should_not == PATTERN.new(elements + [4], :type => :some_type)
125
+ end
126
+
127
+ it "is false if the types are not equal" do
128
+ PATTERN.new(elements, :type => :some_type).should_not == PATTERN.new(elements, :type => :another_type)
129
+ end
130
+ end
131
+
132
+ end
@@ -0,0 +1,203 @@
1
+ require 'spec_helper'
2
+
3
+ describe MTK::Patterns::Sequence do
4
+
5
+ SEQUENCE = MTK::Patterns::Sequence
6
+
7
+ let(:elements) { [1,2,3] }
8
+ let(:sequence) { SEQUENCE.new(elements) }
9
+
10
+ it "is a MTK::Collection" do
11
+ sequence.should be_a MTK::Helpers::Collection
12
+ # and now we won't test any other collection features here... see collection_spec
13
+ end
14
+
15
+ describe ".from_a" do
16
+ it "acts like .new" do
17
+ SEQUENCE.from_a(elements).should == sequence
18
+ end
19
+ end
20
+
21
+ describe "#elements" do
22
+ it "is the array the sequence was constructed with" do
23
+ sequence.elements.should == elements
24
+ end
25
+ end
26
+
27
+ describe "#next" do
28
+ it "enumerates the elements" do
29
+ nexts = []
30
+ elements.length.times do
31
+ nexts << sequence.next
32
+ end
33
+ nexts.should == elements
34
+ end
35
+
36
+ it "raises StopIteration when the end of the Sequence is reached" do
37
+ elements.length.times{ sequence.next }
38
+ lambda{ sequence.next }.should raise_error(StopIteration)
39
+ end
40
+
41
+ it "should automatically break out of Kernel#loop" do
42
+ nexts = []
43
+ loop do # loop rescues StopIteration and exits the loop
44
+ nexts << sequence.next
45
+ end
46
+ nexts.should == elements
47
+ end
48
+
49
+ it "enumerates the elements in sub-sequences" do
50
+ sub_sequence = SEQUENCE.new [2,3]
51
+ sequence = SEQUENCE.new [1,sub_sequence,4]
52
+ nexts = []
53
+ loop { nexts << sequence.next }
54
+ nexts.should == [1,2,3,4]
55
+ end
56
+
57
+ it "skips over empty sub-sequences" do
58
+ sub_sequence = SEQUENCE.new []
59
+ sequence = SEQUENCE.new [1,sub_sequence,4]
60
+ nexts = []
61
+ loop { nexts << sequence.next }
62
+ nexts.should == [1,4]
63
+ end
64
+
65
+ end
66
+
67
+ describe "@min_elements" do
68
+ it "prevents a StopIteration error until min_elements have been emitted" do
69
+ pattern = SEQUENCE.new([1,2,3], cycle_count: 1, min_elements: 5)
70
+ 5.times{ pattern.next }
71
+ lambda{ pattern.next }.should raise_error StopIteration
72
+ end
73
+ end
74
+
75
+
76
+ describe "@max_cycles" do
77
+ it "is the :max_cycles option the pattern was constructed with" do
78
+ SEQUENCE.new( [], max_cycles: 2 ).max_cycles.should == 2
79
+ end
80
+
81
+ it "is 1 by default" do
82
+ SEQUENCE.new( [] ).max_cycles.should == 1
83
+ end
84
+
85
+ it "loops indefinitely when it's nil" do
86
+ sequence = SEQUENCE.new( [1], max_cycles: nil )
87
+ lambda { 100.times { sequence.next } }.should_not raise_error
88
+ end
89
+
90
+ it "causes a StopIteration exception after the number of cycles has completed" do
91
+ sequence = SEQUENCE.new( elements, max_cycles: 2 )
92
+ 2.times do
93
+ elements.length.times { sequence.next } # one full cycle
94
+ end
95
+ lambda { sequence.next }.should raise_error StopIteration
96
+ end
97
+ end
98
+
99
+
100
+ describe "#max_cycles_exceeded?" do
101
+ it "is false until max_elements have been emitted" do
102
+ sequence = SEQUENCE.new( elements, max_cycles: 2 )
103
+ 2.times do
104
+ sequence.max_cycles_exceeded?.should be_false
105
+ elements.length.times { sequence.next } # one full cycle
106
+ end
107
+ # unlike with element_count and max_elements_exceeded?, cycle_count doesn't get bumped until
108
+ # you ask for the next element and a StopIteration is thrown
109
+ lambda { sequence.next }.should raise_error StopIteration
110
+ sequence.max_cycles_exceeded?.should be_true
111
+ end
112
+
113
+ it "is always false when max_cycles is not set" do
114
+ pattern = PATTERN.new([:anything], max_cycles: nil)
115
+ 15.times { pattern.max_cycles_exceeded?.should be_false and pattern.next }
116
+ end
117
+ end
118
+
119
+
120
+ it "has max_elements_exceeded once max_elements have been emitted (edge case, has same number of elements)" do
121
+ sequence = SEQUENCE.new([1,2,3,4,5], :max_elements => 5)
122
+ 5.times { sequence.max_elements_exceeded?.should(be_false) and sequence.next }
123
+ sequence.max_elements_exceeded?.should be_true
124
+ lambda { sequence.next }.should raise_error StopIteration
125
+ end
126
+
127
+
128
+ it "raises a StopIteration error when a nested pattern has emitted more than max_elements" do
129
+ sequence = SEQUENCE.new([Patterns.Cycle(1,2)], :max_elements => 5)
130
+ 5.times { sequence.next }
131
+ lambda{ sequence.next }.should raise_error StopIteration
132
+ end
133
+
134
+
135
+ describe "#rewind" do
136
+ it "restarts at the beginning of the sequence" do
137
+ loop { sequence.next }
138
+ sequence.rewind
139
+ sequence.next.should == elements.first
140
+ end
141
+
142
+ it "returns self, so it can be chained to #next" do
143
+ first = sequence.next
144
+ sequence.rewind.next.should == first
145
+ end
146
+
147
+ it "causes sub-sequences to start from the beginning when encountered again after #rewind" do
148
+ sub_sequence = SEQUENCE.new [2,3]
149
+ sequence = SEQUENCE.new [1,sub_sequence,4]
150
+ loop { sequence.next }
151
+ sequence.rewind
152
+ nexts = []
153
+ loop { nexts << sequence.next }
154
+ nexts.should == [1,2,3,4]
155
+ end
156
+ end
157
+
158
+ end
159
+
160
+
161
+ describe MTK::Patterns do
162
+
163
+ describe "#Sequence" do
164
+ it "creates a Sequence" do
165
+ MTK::Patterns.Sequence(1,2,3).should be_a MTK::Patterns::Sequence
166
+ end
167
+
168
+ it "sets #elements from the varargs" do
169
+ MTK::Patterns.Sequence(1,2,3).elements.should == [1,2,3]
170
+ end
171
+ end
172
+
173
+ describe "#PitchSequence" do
174
+ it "creates a Sequence" do
175
+ MTK::Patterns.PitchSequence(1,2,3).should be_a MTK::Patterns::Sequence
176
+ end
177
+
178
+ it "sets #elements from the varargs" do
179
+ MTK::Patterns.PitchSequence(1,2,3).elements.should == [Pitch(1),Pitch(2),Pitch(3)]
180
+ end
181
+ end
182
+
183
+ describe "#IntensitySequence" do
184
+ it "creates a Sequence" do
185
+ MTK::Patterns.IntensitySequence(1,2,3).should be_a MTK::Patterns::Sequence
186
+ end
187
+
188
+ it "sets #elements from the varargs" do
189
+ MTK::Patterns.IntensitySequence(1,2,3).elements.should == [Intensity(1),Intensity(2),Intensity(3)]
190
+ end
191
+ end
192
+
193
+ describe "#DurationSequence" do
194
+ it "creates a Sequence" do
195
+ MTK::Patterns.DurationSequence(1,2,3).should be_a MTK::Patterns::Sequence
196
+ end
197
+
198
+ it "sets #elements from the varargs" do
199
+ MTK::Patterns.DurationSequence(1,2,3).elements.should == [Duration(1),Duration(2),Duration(3)]
200
+ end
201
+ end
202
+
203
+ end