Permalink
Browse files

reworked the Sequence(), PitchSequence(), etc, constructor convenienc…

…e methods in MTK::Pattern into a method_missing implementation that provides all these constructor convenience methods to all Pattern classes.

Added tests to ensure the 3 main types of patterns (:pitch, :interval, and :duration) have constructor convenience methods available for each pattern class.
  • Loading branch information...
1 parent 6d66c2a commit f9d3cca8a74959ca2497b5b9c5c5602903967be3 @adamjmurray committed Jun 30, 2011
@@ -6,11 +6,14 @@ module Pattern
# @abstract subclass and override {#advance!} and {#current} to implement a Pattern
#
class AbstractPattern
+ include Collection
include Enumerator
# The elements in the pattern
attr_reader :elements
+ attr_reader :options
+
# The type of elements in the pattern, such as :pitch, :intensity, or :duration
#
# This is often needed by {Sequencer} classes to interpret the pattern elements.
@@ -107,5 +110,19 @@ def emit element
end
end
+ # Build any "TypedPattern" (like PitchCycle or DurationPalindrome) or even just Pattern
+ def method_missing(method, *args, &block)
+ # Assuming we get something like PitchCycle, split into 'Pitch' and 'Cycle'
+ camel_case_words = method.to_s.gsub(/([a-z])([A-Z])/,'\1 \2').split(' ')
+ pattern = MTK::Pattern.const_get camel_case_words.last
+ if camel_case_words.length > 1
+ type = camel_case_words.first.downcase.to_sym
+ pattern.new(args, :type => type)
+ else
+ pattern.new(args)
+ end
+ end
+ module_function :method_missing
+
end
end
View
@@ -4,7 +4,6 @@ module Pattern
# An endless enumerator that outputs an element one at a time from a list of elements,
# looping back to the beginning when elements run out.
class Cycle < AbstractPattern
- include Collection
# The number of cycles emitted (1 cycle == all elements emitted) since the last {#rewind}
attr_reader :cycle_count
@@ -10,13 +10,14 @@ def rewind
super
end
- ##############
- protected
-
+ # true if the first/last element are repeated when the ends are reached, else false
def repeat_ends?
@repeat_ends ||= @options.fetch :repeat_ends, false
end
+ ##############
+ protected
+
# (see AbstractPattern#advance!)
def advance!
raise StopIteration if @elements.nil? or @elements.empty? # prevent infinite loops
@@ -3,7 +3,6 @@ module Pattern
# A finite list of elements, which can be enumerated one at a time.
class Sequence < AbstractPattern
- include Collection
# Reset the sequence to the beginning
def rewind
@@ -16,8 +15,9 @@ def rewind
# (see AbstractPattern#advance!)
def advance!
+ super
@index += 1
- raise StopIteration if @elements.nil? or @index >= @elements.length
+ raise StopIteration if @index >= @elements.length
end
# (see AbstractPattern#current)
@@ -26,26 +26,5 @@ def current
end
end
- def Sequence(*anything)
- Sequence.new(anything)
- end
- module_function :Sequence
-
- def PitchSequence(*anything)
- Sequence.new(anything, :type => :pitch)
- end
- module_function :PitchSequence
-
- def IntensitySequence(*anything)
- Sequence.new(anything, :type => :intensity)
- end
- module_function :IntensitySequence
-
- def DurationSequence(*anything)
- Sequence.new(anything, :type => :duration)
- end
- module_function :DurationSequence
-
-
end
end
@@ -4,6 +4,8 @@
PATTERN = MTK::Pattern::AbstractPattern
+ let(:elements) { [1,2,3] }
+
describe "#type" do
it "is the :type value from the constuctor's options hash" do
PATTERN.new([], :type => :my_type).type.should == :my_type
@@ -26,4 +28,18 @@
end
end
+ describe "#==" do
+ it "is true if the elements and types are equal" do
+ PATTERN.new(elements, :type => :some_type).should == PATTERN.new(elements, :type => :some_type)
+ end
+
+ it "is false if the elements are not equal" do
+ PATTERN.new(elements, :type => :some_type).should_not == PATTERN.new(elements + [4], :type => :some_type)
+ end
+
+ it "is false if the types are not equal" do
+ PATTERN.new(elements, :type => :some_type).should_not == PATTERN.new(elements, :type => :another_type)
+ end
+ end
+
end
@@ -31,3 +31,64 @@
end
end
+
+
+describe MTK::Pattern do
+
+ describe "#Choice" do
+ it "creates a Choice" do
+ MTK::Pattern.Choice(1,2,3).should be_a MTK::Pattern::Choice
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.Choice(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "does not set a type" do
+ MTK::Pattern.Choice(1,2,3).type.should be_nil
+ end
+ end
+
+ describe "#PitchChoice" do
+ it "creates a Choice" do
+ MTK::Pattern.PitchChoice(1,2,3).should be_a MTK::Pattern::Choice
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.PitchChoice(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.PitchChoice([]).type.should == :pitch
+ end
+ end
+
+ describe "#IntensityChoice" do
+ it "creates a Choice" do
+ MTK::Pattern.IntensityChoice(1,2,3).should be_a MTK::Pattern::Choice
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.IntensityChoice(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.IntensityChoice([]).type.should == :intensity
+ end
+ end
+
+ describe "#DurationChoice" do
+ it "creates a Choice" do
+ MTK::Pattern.DurationChoice(1,2,3).should be_a MTK::Pattern::Choice
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.DurationChoice(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.DurationChoice([]).type.should == :duration
+ end
+ end
+
+end
@@ -70,3 +70,64 @@
end
end
+
+
+describe MTK::Pattern do
+
+ describe "#Cycle" do
+ it "creates a Cycle" do
+ MTK::Pattern.Cycle(1,2,3).should be_a MTK::Pattern::Cycle
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.Cycle(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "does not set a type" do
+ MTK::Pattern.Cycle(1,2,3).type.should be_nil
+ end
+ end
+
+ describe "#PitchCycle" do
+ it "creates a Cycle" do
+ MTK::Pattern.PitchCycle(1,2,3).should be_a MTK::Pattern::Cycle
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.PitchCycle(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.PitchCycle([]).type.should == :pitch
+ end
+ end
+
+ describe "#IntensityCycle" do
+ it "creates a Cycle" do
+ MTK::Pattern.IntensityCycle(1,2,3).should be_a MTK::Pattern::Cycle
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.IntensityCycle(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.IntensityCycle([]).type.should == :intensity
+ end
+ end
+
+ describe "#DurationCycle" do
+ it "creates a Cycle" do
+ MTK::Pattern.DurationCycle(1,2,3).should be_a MTK::Pattern::Cycle
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.DurationCycle(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.DurationCycle([]).type.should == :duration
+ end
+ end
+
+end
@@ -5,7 +5,6 @@
PALINDROME = MTK::Pattern::Palindrome
describe "#next" do
-
it "reverses direction when the ends of the list are reached" do
palindrome = PALINDROME.new [1,2,3,4]
nexts = []
@@ -45,4 +44,81 @@
end
end
+ describe "#repeat_ends?" do
+ it "is true if the :repeat_ends option is true" do
+ PALINDROME.new([], :repeat_ends => true).repeat_ends?.should be_true
+ end
+
+ it "is false if the :repeat_ends option is true" do
+ PALINDROME.new([], :repeat_ends => false).repeat_ends?.should be_false
+ end
+ end
+
+ describe "#==" do
+ it "is false if the :repeat_ends options are different" do
+ PALINDROME.new([1,2,3], :repeat_ends => true).should_not == PALINDROME.new([1,2,3], :repeat_ends => false)
+ end
+ end
+
end
+
+
+describe MTK::Pattern do
+
+ describe "#Palindrome" do
+ it "creates a Palindrome" do
+ MTK::Pattern.Palindrome(1,2,3).should be_a MTK::Pattern::Palindrome
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.Palindrome(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "does not set a type" do
+ MTK::Pattern.Palindrome(1,2,3).type.should be_nil
+ end
+ end
+
+ describe "#PitchPalindrome" do
+ it "creates a Palindrome" do
+ MTK::Pattern.PitchPalindrome(1,2,3).should be_a MTK::Pattern::Palindrome
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.PitchPalindrome(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.PitchPalindrome([]).type.should == :pitch
+ end
+ end
+
+ describe "#IntensityPalindrome" do
+ it "creates a Palindrome" do
+ MTK::Pattern.IntensityPalindrome(1,2,3).should be_a MTK::Pattern::Palindrome
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.IntensityPalindrome(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.IntensityPalindrome([]).type.should == :intensity
+ end
+ end
+
+ describe "#DurationPalindrome" do
+ it "creates a Palindrome" do
+ MTK::Pattern.DurationPalindrome(1,2,3).should be_a MTK::Pattern::Palindrome
+ end
+
+ it "sets #elements from the varargs" do
+ MTK::Pattern.DurationPalindrome(1,2,3).elements.should == [1,2,3]
+ end
+
+ it "sets #type to :pitch" do
+ MTK::Pattern.DurationPalindrome([]).type.should == :duration
+ end
+ end
+
+end
Oops, something went wrong.

0 comments on commit f9d3cca

Please sign in to comment.