mtk 0.0.2 → 0.0.3
Sign up to get free protection for your applications and to get access to all the features.
- data/.yardopts +3 -2
- data/DEVELOPMENT_NOTES.md +114 -0
- data/INTRO.md +64 -8
- data/LICENSE.txt +1 -1
- data/README.md +31 -102
- data/Rakefile +56 -18
- data/bin/mtk +215 -0
- data/examples/crescendo.rb +5 -5
- data/examples/drum_pattern1.rb +23 -0
- data/examples/dynamic_pattern.rb +8 -11
- data/examples/gets_and_play.rb +26 -0
- data/examples/notation.rb +22 -0
- data/examples/play_midi.rb +8 -10
- data/examples/random_tone_row.rb +2 -2
- data/examples/syntax_to_midi.rb +28 -0
- data/examples/test_output.rb +8 -0
- data/examples/tone_row_melody.rb +6 -6
- data/lib/mtk.rb +52 -40
- data/lib/mtk/chord.rb +55 -0
- data/lib/mtk/constants/durations.rb +57 -0
- data/lib/mtk/constants/intensities.rb +61 -0
- data/lib/mtk/constants/intervals.rb +73 -0
- data/lib/mtk/constants/pitch_classes.rb +29 -0
- data/lib/mtk/constants/pitches.rb +52 -0
- data/lib/mtk/duration.rb +211 -0
- data/lib/mtk/events/event.rb +119 -0
- data/lib/mtk/events/note.rb +112 -0
- data/lib/mtk/events/parameter.rb +54 -0
- data/lib/mtk/helpers/collection.rb +164 -0
- data/lib/mtk/helpers/convert.rb +36 -0
- data/lib/mtk/helpers/lilypond.rb +162 -0
- data/lib/mtk/helpers/output_selector.rb +67 -0
- data/lib/mtk/helpers/pitch_collection.rb +23 -0
- data/lib/mtk/helpers/pseudo_constants.rb +26 -0
- data/lib/mtk/intensity.rb +156 -0
- data/lib/mtk/interval.rb +155 -0
- data/lib/mtk/lang/mtk_grammar.citrus +190 -13
- data/lib/mtk/lang/parser.rb +29 -0
- data/lib/mtk/melody.rb +94 -0
- data/lib/mtk/midi/dls_synth_device.rb +144 -0
- data/lib/mtk/midi/dls_synth_output.rb +62 -0
- data/lib/mtk/midi/file.rb +67 -32
- data/lib/mtk/midi/input.rb +97 -0
- data/lib/mtk/midi/jsound_input.rb +36 -17
- data/lib/mtk/midi/jsound_output.rb +48 -46
- data/lib/mtk/midi/output.rb +195 -0
- data/lib/mtk/midi/unimidi_input.rb +117 -0
- data/lib/mtk/midi/unimidi_output.rb +121 -0
- data/lib/mtk/{_numeric_extensions.rb → numeric_extensions.rb} +12 -0
- data/lib/mtk/patterns/chain.rb +49 -0
- data/lib/mtk/{pattern → patterns}/choice.rb +14 -8
- data/lib/mtk/patterns/cycle.rb +18 -0
- data/lib/mtk/patterns/for_each.rb +71 -0
- data/lib/mtk/patterns/function.rb +39 -0
- data/lib/mtk/{pattern → patterns}/lines.rb +11 -17
- data/lib/mtk/{pattern → patterns}/palindrome.rb +11 -8
- data/lib/mtk/patterns/pattern.rb +171 -0
- data/lib/mtk/patterns/sequence.rb +20 -0
- data/lib/mtk/pitch.rb +7 -6
- data/lib/mtk/pitch_class.rb +124 -46
- data/lib/mtk/pitch_class_set.rb +58 -35
- data/lib/mtk/sequencers/event_builder.rb +131 -0
- data/lib/mtk/sequencers/legato_sequencer.rb +24 -0
- data/lib/mtk/sequencers/rhythmic_sequencer.rb +28 -0
- data/lib/mtk/{sequencer/abstract_sequencer.rb → sequencers/sequencer.rb} +37 -11
- data/lib/mtk/{sequencer → sequencers}/step_sequencer.rb +4 -4
- data/lib/mtk/timeline.rb +39 -22
- data/lib/mtk/variable.rb +32 -0
- data/spec/mtk/chord_spec.rb +83 -0
- data/spec/mtk/{_constants → constants}/durations_spec.rb +12 -41
- data/spec/mtk/{_constants → constants}/intensities_spec.rb +13 -37
- data/spec/mtk/{_constants → constants}/intervals_spec.rb +14 -32
- data/spec/mtk/{_constants → constants}/pitch_classes_spec.rb +8 -4
- data/spec/mtk/{_constants → constants}/pitches_spec.rb +5 -1
- data/spec/mtk/duration_spec.rb +372 -0
- data/spec/mtk/events/event_spec.rb +234 -0
- data/spec/mtk/events/note_spec.rb +174 -0
- data/spec/mtk/events/parameter_spec.rb +220 -0
- data/spec/mtk/{helper → helpers}/collection_spec.rb +86 -3
- data/spec/mtk/{helper → helpers}/pseudo_constants_spec.rb +2 -2
- data/spec/mtk/intensity_spec.rb +289 -0
- data/spec/mtk/interval_spec.rb +265 -0
- data/spec/mtk/lang/parser_spec.rb +597 -0
- data/spec/mtk/melody_spec.rb +223 -0
- data/spec/mtk/midi/file_spec.rb +16 -16
- data/spec/mtk/midi/jsound_input_spec.rb +11 -0
- data/spec/mtk/midi/jsound_output_spec.rb +11 -0
- data/spec/mtk/midi/output_spec.rb +102 -0
- data/spec/mtk/midi/unimidi_input_spec.rb +11 -0
- data/spec/mtk/midi/unimidi_output_spec.rb +11 -0
- data/spec/mtk/{_numeric_extensions_spec.rb → numeric_extensions_spec.rb} +1 -0
- data/spec/mtk/patterns/chain_spec.rb +110 -0
- data/spec/mtk/{pattern → patterns}/choice_spec.rb +20 -30
- data/spec/mtk/{pattern → patterns}/cycle_spec.rb +25 -35
- data/spec/mtk/patterns/for_each_spec.rb +136 -0
- data/spec/mtk/{pattern → patterns}/function_spec.rb +17 -30
- data/spec/mtk/{pattern → patterns}/lines_spec.rb +11 -27
- data/spec/mtk/{pattern → patterns}/palindrome_spec.rb +13 -29
- data/spec/mtk/patterns/pattern_spec.rb +132 -0
- data/spec/mtk/patterns/sequence_spec.rb +203 -0
- data/spec/mtk/pitch_class_set_spec.rb +23 -21
- data/spec/mtk/pitch_class_spec.rb +151 -39
- data/spec/mtk/pitch_spec.rb +22 -1
- data/spec/mtk/sequencers/event_builder_spec.rb +245 -0
- data/spec/mtk/sequencers/legato_sequencer_spec.rb +45 -0
- data/spec/mtk/sequencers/rhythmic_sequencer_spec.rb +84 -0
- data/spec/mtk/sequencers/sequencer_spec.rb +215 -0
- data/spec/mtk/{sequencer → sequencers}/step_sequencer_spec.rb +35 -13
- data/spec/mtk/timeline_spec.rb +109 -16
- data/spec/mtk/variable_spec.rb +52 -0
- data/spec/spec_coverage.rb +2 -0
- data/spec/spec_helper.rb +3 -0
- metadata +188 -91
- data/lib/mtk/_constants/durations.rb +0 -80
- data/lib/mtk/_constants/intensities.rb +0 -81
- data/lib/mtk/_constants/intervals.rb +0 -85
- data/lib/mtk/_constants/pitch_classes.rb +0 -35
- data/lib/mtk/_constants/pitches.rb +0 -49
- data/lib/mtk/event.rb +0 -70
- data/lib/mtk/helper/collection.rb +0 -114
- data/lib/mtk/helper/event_builder.rb +0 -85
- data/lib/mtk/helper/pseudo_constants.rb +0 -26
- data/lib/mtk/lang/grammar.rb +0 -17
- data/lib/mtk/note.rb +0 -63
- data/lib/mtk/pattern/abstract_pattern.rb +0 -132
- data/lib/mtk/pattern/cycle.rb +0 -51
- data/lib/mtk/pattern/enumerator.rb +0 -26
- data/lib/mtk/pattern/function.rb +0 -46
- data/lib/mtk/pattern/sequence.rb +0 -30
- data/lib/mtk/pitch_set.rb +0 -84
- data/lib/mtk/sequencer/rhythmic_sequencer.rb +0 -29
- data/lib/mtk/transform/invertible.rb +0 -15
- data/lib/mtk/transform/mappable.rb +0 -18
- data/lib/mtk/transform/set_theory_operations.rb +0 -34
- data/lib/mtk/transform/transposable.rb +0 -14
- data/spec/mtk/event_spec.rb +0 -139
- data/spec/mtk/helper/event_builder_spec.rb +0 -92
- data/spec/mtk/lang/grammar_spec.rb +0 -100
- data/spec/mtk/note_spec.rb +0 -115
- data/spec/mtk/pattern/abstract_pattern_spec.rb +0 -45
- data/spec/mtk/pattern/note_cycle_spec.rb.bak +0 -116
- data/spec/mtk/pattern/pitch_cycle_spec.rb.bak +0 -47
- data/spec/mtk/pattern/pitch_sequence_spec.rb.bak +0 -37
- data/spec/mtk/pattern/sequence_spec.rb +0 -151
- data/spec/mtk/pitch_set_spec.rb +0 -198
- data/spec/mtk/sequencer/abstract_sequencer_spec.rb +0 -159
- data/spec/mtk/sequencer/rhythmic_sequencer_spec.rb +0 -49
@@ -1,85 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
module Helper
|
3
|
-
|
4
|
-
# A helper class for {Sequencer}s.
|
5
|
-
# Takes a list of patterns and constructs a list of {Event}s from the next elements in each pattern.
|
6
|
-
class EventBuilder
|
7
|
-
|
8
|
-
DEFAULT_PITCH = MTK::Pitches::C4
|
9
|
-
DEFAULT_INTENSITY = MTK::Intensities::f
|
10
|
-
DEFAULT_DURATION = 1
|
11
|
-
|
12
|
-
def initialize(patterns, options={})
|
13
|
-
@patterns = patterns
|
14
|
-
@options = options
|
15
|
-
@max_interval = options.fetch :max_interval, 12
|
16
|
-
rewind
|
17
|
-
end
|
18
|
-
|
19
|
-
# Build a list of events from the next element in each {Pattern}
|
20
|
-
# @return [Array] an array of events
|
21
|
-
def next
|
22
|
-
pitches = []
|
23
|
-
intensity = @default_intensity
|
24
|
-
duration = @default_duration
|
25
|
-
|
26
|
-
for pattern in @patterns
|
27
|
-
element = pattern.next
|
28
|
-
case element
|
29
|
-
when Pitch then pitches << element
|
30
|
-
when PitchSet then pitches += element.pitches
|
31
|
-
when PitchClass then pitches += pitches_for_pitch_classes([element], @previous_pitch || @default_pitch)
|
32
|
-
when PitchClassSet then pitches += pitches_for_pitch_classes(element, @previous_pitch || @default_pitch)
|
33
|
-
else case pattern.type
|
34
|
-
when :pitch
|
35
|
-
if element.is_a? Numeric
|
36
|
-
# pitch interval case
|
37
|
-
if @previous_pitches
|
38
|
-
pitches += @previous_pitches.map{|pitch| pitch + element }
|
39
|
-
else
|
40
|
-
pitches << ((@previous_pitch || @default_pitch) + element)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
when :intensity then intensity = element
|
44
|
-
when :duration then duration = element
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
if not pitches.empty?
|
50
|
-
@previous_pitch = pitches.last
|
51
|
-
@previous_pitches = pitches.length > 1 ? pitches : nil
|
52
|
-
pitches.map{|pitch| Note(pitch,intensity,duration) }
|
53
|
-
else
|
54
|
-
nil
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
# Reset the EventBuilder to its initial state
|
59
|
-
def rewind
|
60
|
-
@default_pitch = @options.fetch :default_pitch, DEFAULT_PITCH
|
61
|
-
@default_intensity = @options.fetch :default_intensity, DEFAULT_INTENSITY
|
62
|
-
@default_duration = @options.fetch :default_duration, DEFAULT_DURATION
|
63
|
-
@previous_pitch = nil
|
64
|
-
@previous_pitches = nil
|
65
|
-
@patterns.each{|pattern| pattern.rewind }
|
66
|
-
end
|
67
|
-
|
68
|
-
########################
|
69
|
-
private
|
70
|
-
|
71
|
-
def pitches_for_pitch_classes(pitch_classes, previous_pitch)
|
72
|
-
pitches = []
|
73
|
-
for pitch_class in pitch_classes
|
74
|
-
pitch = previous_pitch.nearest(pitch_class)
|
75
|
-
pitch -= 12 if pitch > @default_pitch+@max_interval # keep within max_distance of start (default is one octave)
|
76
|
-
pitch += 12 if pitch < @default_pitch-@max_interval
|
77
|
-
pitches << pitch
|
78
|
-
end
|
79
|
-
pitches
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
|
84
|
-
end
|
85
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module MTK::Helper
|
2
|
-
|
3
|
-
|
4
|
-
# Extension for modules that want to define pseudo-constants (constant-like values with lower-case names)
|
5
|
-
module PseudoConstants
|
6
|
-
|
7
|
-
# Define a module method and module function (available both through the module namespace and as a mixin method),
|
8
|
-
# to provide a constant with a lower-case name.
|
9
|
-
#
|
10
|
-
# @param name [Symbol] the name of the pseudo-constant
|
11
|
-
# @param value [Object] the value of the pseudo-constant
|
12
|
-
# @return [nil]
|
13
|
-
def define_constant name, value
|
14
|
-
if name[0..0] =~ /[A-Z]/
|
15
|
-
const_set name, value # it's just a normal constant
|
16
|
-
else
|
17
|
-
# the pseudo-constant definition is the combination of a method and module_function:
|
18
|
-
define_method(name) { value }
|
19
|
-
module_function name
|
20
|
-
end
|
21
|
-
nil
|
22
|
-
end
|
23
|
-
|
24
|
-
end
|
25
|
-
|
26
|
-
end
|
data/lib/mtk/lang/grammar.rb
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
require 'citrus'
|
2
|
-
Citrus.load File.join(File.dirname(__FILE__),'mtk_grammar')
|
3
|
-
|
4
|
-
module MTK
|
5
|
-
module Lang
|
6
|
-
|
7
|
-
# Parser for the {file:lib/mtk/lang/mtk_grammar.citrus MTK grammar}
|
8
|
-
class Grammar
|
9
|
-
|
10
|
-
def self.parse(syntax, root=:pitch)
|
11
|
-
MTK_Grammar.parse(syntax, :root => root).value
|
12
|
-
end
|
13
|
-
|
14
|
-
end
|
15
|
-
|
16
|
-
end
|
17
|
-
end
|
data/lib/mtk/note.rb
DELETED
@@ -1,63 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
|
3
|
-
# A musical {Event} defined by a {Pitch}, intensity, and duration
|
4
|
-
class Note < Event
|
5
|
-
|
6
|
-
# frequency of the note as a Pitch
|
7
|
-
attr_reader :pitch
|
8
|
-
|
9
|
-
def initialize(pitch, intensity, duration)
|
10
|
-
@pitch = pitch
|
11
|
-
super(intensity, duration)
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.from_hash(hash)
|
15
|
-
new hash[:pitch], hash[:intensity], hash[:duration]
|
16
|
-
end
|
17
|
-
|
18
|
-
def to_hash
|
19
|
-
super.merge({ :pitch => @pitch })
|
20
|
-
end
|
21
|
-
|
22
|
-
def self.from_midi(pitch, velocity, beats)
|
23
|
-
new Pitches::PITCHES[pitch], velocity/127.0, beats
|
24
|
-
end
|
25
|
-
|
26
|
-
def to_midi
|
27
|
-
[pitch.to_i, velocity, duration]
|
28
|
-
end
|
29
|
-
|
30
|
-
def transpose(interval)
|
31
|
-
self.class.new(@pitch+interval, @intensity, @duration)
|
32
|
-
end
|
33
|
-
|
34
|
-
def invert(around_pitch)
|
35
|
-
self.class.new(@pitch.invert(around_pitch), @intensity, @duration)
|
36
|
-
end
|
37
|
-
|
38
|
-
def == other
|
39
|
-
super and other.respond_to? :pitch and @pitch == other.pitch
|
40
|
-
end
|
41
|
-
|
42
|
-
def to_s
|
43
|
-
"Note(#{pitch}, #{super})"
|
44
|
-
end
|
45
|
-
|
46
|
-
def inspect
|
47
|
-
"Note(#{pitch}, #{super})"
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
|
52
|
-
# Construct a {Note} from any supported type
|
53
|
-
def Note(*anything)
|
54
|
-
anything = anything.first if anything.size == 1
|
55
|
-
case anything
|
56
|
-
when Array then Note.new(*anything)
|
57
|
-
when Note then anything
|
58
|
-
else raise "Note doesn't understand #{anything.class}"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
module_function :Note
|
62
|
-
|
63
|
-
end
|
@@ -1,132 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
module Pattern
|
3
|
-
|
4
|
-
# A pattern of elements that can be emitted one element at a time via calls to {#next}.
|
5
|
-
#
|
6
|
-
# Patterns can be reset to the beginning via {#rewind}.
|
7
|
-
#
|
8
|
-
# @abstract Subclass and override {#advance!} and {#current} to implement a Pattern
|
9
|
-
#
|
10
|
-
class AbstractPattern
|
11
|
-
include Helper::Collection
|
12
|
-
include Enumerator
|
13
|
-
|
14
|
-
# The elements in the pattern
|
15
|
-
attr_reader :elements
|
16
|
-
|
17
|
-
attr_reader :options
|
18
|
-
|
19
|
-
# The type of elements in the pattern, such as :pitch, :intensity, or :duration
|
20
|
-
#
|
21
|
-
# This is often needed by {Sequencer} classes to interpret the pattern elements.
|
22
|
-
attr_reader :type
|
23
|
-
|
24
|
-
# The number of elements emitted since the last {#rewind}
|
25
|
-
attr_reader :element_count
|
26
|
-
|
27
|
-
# The maximum number of elements this Pattern will emit before a StopIteration exception
|
28
|
-
attr_reader :max_elements
|
29
|
-
|
30
|
-
# @param elements [Enumerable, #to_a] the list of elements in the pattern
|
31
|
-
# @param options [Hash] the pattern options
|
32
|
-
# @option options [String] :type the pattern {#type}
|
33
|
-
# @option options [Fixnum] :max_elements the {#max_elements}
|
34
|
-
def initialize(elements, options={})
|
35
|
-
elements = elements.to_a if elements.respond_to? :to_a and not elements.is_a? Proc # Proc check prevents warnings in Ruby 1.8
|
36
|
-
@elements = elements
|
37
|
-
@options = options
|
38
|
-
@type = options[:type]
|
39
|
-
@max_elements = options[:max_elements]
|
40
|
-
rewind
|
41
|
-
end
|
42
|
-
|
43
|
-
# Construct a pattern from an Array.
|
44
|
-
# @param (see #initialize)
|
45
|
-
# @option (see #initialize)
|
46
|
-
# @see #initialize
|
47
|
-
def self.from_a(elements, options={})
|
48
|
-
new(elements, options)
|
49
|
-
end
|
50
|
-
|
51
|
-
# Reset the pattern to the beginning
|
52
|
-
def rewind
|
53
|
-
@current = nil
|
54
|
-
@element_count = 0
|
55
|
-
self
|
56
|
-
end
|
57
|
-
|
58
|
-
# Emit the next element in the pattern
|
59
|
-
# @raise StopIteration when the pattern has emitted all values, or has hit the {#max_elements} limit.
|
60
|
-
def next
|
61
|
-
if @current.is_a? Enumerator
|
62
|
-
begin
|
63
|
-
subpattern_next = @current.next
|
64
|
-
subpattern_has_next = true
|
65
|
-
rescue StopIteration
|
66
|
-
subpattern_has_next = false
|
67
|
-
end
|
68
|
-
|
69
|
-
return emit subpattern_next if subpattern_has_next
|
70
|
-
# else fall through and continue with normal behavior
|
71
|
-
end
|
72
|
-
|
73
|
-
begin
|
74
|
-
advance!
|
75
|
-
rescue StopIteration
|
76
|
-
@current = nil
|
77
|
-
raise
|
78
|
-
end
|
79
|
-
|
80
|
-
@current = current
|
81
|
-
if @current.is_a? Enumerator
|
82
|
-
@current.rewind # start over, in case we already enumerated this element and then did a rewind
|
83
|
-
return self.next
|
84
|
-
end
|
85
|
-
|
86
|
-
emit @current
|
87
|
-
end
|
88
|
-
|
89
|
-
|
90
|
-
##################
|
91
|
-
protected
|
92
|
-
|
93
|
-
# Update internal state (index, etc) so that {#current} will refer to the next element.
|
94
|
-
# @note Override this method in a subclass to define a custom Pattern.
|
95
|
-
# @raise StopIteration if there are no more elements
|
96
|
-
def advance!
|
97
|
-
raise StopIteration if @elements.nil? or @elements.empty?
|
98
|
-
end
|
99
|
-
|
100
|
-
# The current element in the pattern, which will be returned by {#next} (after a call to {#advance!}).
|
101
|
-
# @note Override this method in a subclass to define a custom Pattern.
|
102
|
-
def current
|
103
|
-
@elements[0]
|
104
|
-
end
|
105
|
-
|
106
|
-
|
107
|
-
##################
|
108
|
-
private
|
109
|
-
|
110
|
-
def emit element
|
111
|
-
@element_count += 1
|
112
|
-
raise StopIteration if @max_elements and @element_count > @max_elements
|
113
|
-
element
|
114
|
-
end
|
115
|
-
end
|
116
|
-
|
117
|
-
# Build any "TypedPattern" (like PitchCycle or DurationPalindrome) or even just Pattern
|
118
|
-
def method_missing(method, *args, &block)
|
119
|
-
# Assuming we get something like PitchCycle, split into 'Pitch' and 'Cycle'
|
120
|
-
camel_case_words = method.to_s.gsub(/([a-z])([A-Z])/,'\1 \2').split(' ')
|
121
|
-
pattern = MTK::Pattern.const_get camel_case_words.last
|
122
|
-
if camel_case_words.length > 1
|
123
|
-
type = camel_case_words.first.downcase.to_sym
|
124
|
-
pattern.new(args, :type => type)
|
125
|
-
else
|
126
|
-
pattern.new(args)
|
127
|
-
end
|
128
|
-
end
|
129
|
-
module_function :method_missing
|
130
|
-
|
131
|
-
end
|
132
|
-
end
|
data/lib/mtk/pattern/cycle.rb
DELETED
@@ -1,51 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
module Pattern
|
3
|
-
|
4
|
-
# An endless enumerator that outputs an element one at a time from a list of elements,
|
5
|
-
# looping back to the beginning when elements run out.
|
6
|
-
class Cycle < AbstractPattern
|
7
|
-
|
8
|
-
# The number of cycles emitted (1 cycle == all elements emitted) since the last {#rewind}
|
9
|
-
attr_reader :cycle_count
|
10
|
-
|
11
|
-
# The maximum number of cycles this Pattern will emit before a StopIteration exception
|
12
|
-
attr_reader :max_cycles
|
13
|
-
|
14
|
-
def initialize(elements, options={})
|
15
|
-
super
|
16
|
-
@max_cycles = options[:max_cycles]
|
17
|
-
end
|
18
|
-
|
19
|
-
# Reset the sequence to the beginning
|
20
|
-
def rewind
|
21
|
-
@index = -1
|
22
|
-
@cycle_count = 0
|
23
|
-
super
|
24
|
-
end
|
25
|
-
|
26
|
-
###################
|
27
|
-
protected
|
28
|
-
|
29
|
-
# (see AbstractPattern#advance!)
|
30
|
-
def advance!
|
31
|
-
super # base advance!() implementation prevents infinite loops with empty patterns
|
32
|
-
@index += 1
|
33
|
-
if @index >= @elements.length
|
34
|
-
@cycle_count += 1
|
35
|
-
if @max_cycles and @cycle_count >= @max_cycles
|
36
|
-
raise StopIteration
|
37
|
-
end
|
38
|
-
@index = -1
|
39
|
-
advance!
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
# (see AbstractPattern#current)
|
44
|
-
def current
|
45
|
-
@elements[@index]
|
46
|
-
end
|
47
|
-
|
48
|
-
end
|
49
|
-
|
50
|
-
end
|
51
|
-
end
|
@@ -1,26 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
module Pattern
|
3
|
-
|
4
|
-
# The core interface for all Patterns.
|
5
|
-
#
|
6
|
-
# This module doesn't provide any useful default functionality.
|
7
|
-
# It only indicates that a class is compatible with MTK's pattern enumerator interface.
|
8
|
-
#
|
9
|
-
module Enumerator
|
10
|
-
|
11
|
-
# Return the next element in the enumerator
|
12
|
-
# @raise StopIteration when no more elements are available
|
13
|
-
def next
|
14
|
-
raise StopIteration
|
15
|
-
end
|
16
|
-
|
17
|
-
# Reset the enumerator to the beginning
|
18
|
-
# @return self
|
19
|
-
def rewind
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
end
|
26
|
-
end
|
data/lib/mtk/pattern/function.rb
DELETED
@@ -1,46 +0,0 @@
|
|
1
|
-
module MTK
|
2
|
-
module Pattern
|
3
|
-
|
4
|
-
# An arbitrary function that dynamically generates elements.
|
5
|
-
#
|
6
|
-
class Function < AbstractPattern
|
7
|
-
|
8
|
-
attr_reader :function
|
9
|
-
|
10
|
-
def initialize(elements, options={})
|
11
|
-
super
|
12
|
-
@function = @elements
|
13
|
-
# unpack from the varargs Array that may be passed in from the "convenience constructor methods" defined in MTK::Pattern \
|
14
|
-
@function = @function.first if @function.is_a? Enumerable
|
15
|
-
end
|
16
|
-
|
17
|
-
# Reset the sequence to the beginning
|
18
|
-
def rewind
|
19
|
-
@prev = nil
|
20
|
-
@function_call_count = -1
|
21
|
-
super
|
22
|
-
end
|
23
|
-
|
24
|
-
###################
|
25
|
-
protected
|
26
|
-
|
27
|
-
# (see AbstractPattern#advance!)
|
28
|
-
def advance!
|
29
|
-
raise StopIteration if @elements.nil?
|
30
|
-
end
|
31
|
-
|
32
|
-
# (see AbstractPattern#current)
|
33
|
-
def current
|
34
|
-
@function_call_count += 1
|
35
|
-
@prev = case @function.arity
|
36
|
-
when 0 then @function.call
|
37
|
-
when 1 then @function.call(@prev)
|
38
|
-
when 2 then @function.call(@prev, @function_call_count)
|
39
|
-
else @function.call(@prev, @function_call_count, @element_count)
|
40
|
-
end
|
41
|
-
end
|
42
|
-
|
43
|
-
end
|
44
|
-
|
45
|
-
end
|
46
|
-
end
|