mtk 0.0.2 → 0.0.3

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 (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