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