musa-dsl 0.22.2 → 0.23.0
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.
- checksums.yaml +4 -4
- data/Gemfile +3 -1
- data/lib/musa-dsl.rb +14 -8
- data/lib/musa-dsl/core-ext/deep-copy.rb +12 -1
- data/lib/musa-dsl/core-ext/inspect-nice.rb +1 -2
- data/lib/musa-dsl/core-ext/smart-proc-binder.rb +13 -11
- data/lib/musa-dsl/datasets/p.rb +41 -16
- data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +14 -12
- data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +32 -6
- data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +24 -10
- data/lib/musa-dsl/generative/backboner.rb +6 -11
- data/lib/musa-dsl/generative/generative-grammar.rb +1 -3
- data/lib/musa-dsl/generative/markov.rb +10 -6
- data/lib/musa-dsl/logger/logger.rb +6 -1
- data/lib/musa-dsl/matrix/matrix.rb +9 -7
- data/lib/musa-dsl/midi/midi-voices.rb +1 -0
- data/lib/musa-dsl/music/scales.rb +1 -1
- data/lib/musa-dsl/neumalang/neumalang.rb +1 -1
- data/lib/musa-dsl/neumas/array-to-neumas.rb +1 -1
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +9 -4
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +30 -129
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +10 -24
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +9 -9
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +3 -5
- data/lib/musa-dsl/sequencer/{base-sequencer-public.rb → base-sequencer.rb} +15 -23
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +9 -7
- data/lib/musa-dsl/sequencer/sequencer.rb +8 -1
- data/lib/musa-dsl/series/base-series.rb +293 -144
- data/lib/musa-dsl/series/buffer-serie.rb +237 -0
- data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +139 -60
- data/lib/musa-dsl/series/main-serie-constructors.rb +254 -165
- data/lib/musa-dsl/series/main-serie-operations.rb +308 -303
- data/lib/musa-dsl/series/proxy-serie.rb +21 -41
- data/lib/musa-dsl/series/quantizer-serie.rb +44 -46
- data/lib/musa-dsl/series/queue-serie.rb +39 -43
- data/lib/musa-dsl/series/series-composer.rb +149 -0
- data/lib/musa-dsl/series/series.rb +6 -2
- data/lib/musa-dsl/series/timed-serie.rb +343 -0
- data/musa-dsl.gemspec +13 -3
- metadata +11 -11
- data/lib/musa-dsl/series/flattener-timed-serie.rb +0 -61
- data/lib/musa-dsl/series/holder-serie.rb +0 -87
@@ -9,6 +9,8 @@ module Musa; module Sequencer
|
|
9
9
|
include Musa::Extension::SmartProcBinder
|
10
10
|
include Musa::Extension::DeepCopy
|
11
11
|
|
12
|
+
using Musa::Extension::InspectNice
|
13
|
+
|
12
14
|
private def _tick(position_to_run)
|
13
15
|
@before_tick.each { |block| block.call position_to_run }
|
14
16
|
queue = @timeslots[position_to_run]
|
@@ -63,21 +65,16 @@ module Musa; module Sequencer
|
|
63
65
|
nil
|
64
66
|
end
|
65
67
|
|
66
|
-
private def _numeric_at(at_position, control,
|
68
|
+
private def _numeric_at(at_position, control, debug: nil, &block)
|
67
69
|
raise ArgumentError, "'at_position' parameter cannot be nil" if at_position.nil?
|
68
70
|
raise ArgumentError, 'Yield block is mandatory' unless block
|
69
71
|
|
70
72
|
at_position = _quantize_position(at_position)
|
71
73
|
|
72
|
-
value_parameters = []
|
73
|
-
value_parameters << with if !with.nil? && !with.is_a?(Hash)
|
74
|
-
|
75
74
|
block_key_parameters_binder =
|
76
75
|
SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
|
77
76
|
|
78
77
|
key_parameters = {}
|
79
|
-
key_parameters.merge! block_key_parameters_binder._apply(nil, with).last if with.is_a?(Hash)
|
80
|
-
|
81
78
|
key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
|
82
79
|
|
83
80
|
if at_position == @position
|
@@ -85,7 +82,7 @@ module Musa; module Sequencer
|
|
85
82
|
|
86
83
|
begin
|
87
84
|
locked = @tick_mutex.try_lock
|
88
|
-
block_key_parameters_binder._call(
|
85
|
+
block_key_parameters_binder._call(nil, key_parameters)
|
89
86
|
ensure
|
90
87
|
@tick_mutex.unlock if locked
|
91
88
|
end
|
@@ -100,8 +97,8 @@ module Musa; module Sequencer
|
|
100
97
|
end
|
101
98
|
end
|
102
99
|
|
103
|
-
@timeslots[at_position] << { parent_control: control,
|
104
|
-
|
100
|
+
@timeslots[at_position] << { parent_control: control,
|
101
|
+
block: block_key_parameters_binder,
|
105
102
|
key_parameters: key_parameters }
|
106
103
|
else
|
107
104
|
@logger.warn('BaseSequencer') { "._numeric_at: ignoring past 'at' command for #{at_position}" }
|
@@ -110,20 +107,14 @@ module Musa; module Sequencer
|
|
110
107
|
nil
|
111
108
|
end
|
112
109
|
|
113
|
-
private def _serie_at(
|
114
|
-
bar_position =
|
115
|
-
|
116
|
-
with_value = if with.respond_to? :next_value
|
117
|
-
with.next_value
|
118
|
-
else
|
119
|
-
with
|
120
|
-
end
|
110
|
+
private def _serie_at(position_or_serie, control, debug: nil, &block)
|
111
|
+
bar_position = position_or_serie.next_value
|
121
112
|
|
122
113
|
if bar_position
|
123
|
-
_numeric_at bar_position, control,
|
114
|
+
_numeric_at bar_position, control, debug: debug, &block
|
124
115
|
|
125
116
|
_numeric_at bar_position, control, debug: false do
|
126
|
-
_serie_at
|
117
|
+
_serie_at position_or_serie, control, debug: debug, &block
|
127
118
|
end
|
128
119
|
else
|
129
120
|
# serie finalizada
|
@@ -224,8 +215,3 @@ module Musa; module Sequencer
|
|
224
215
|
private_constant :EventHandler
|
225
216
|
end
|
226
217
|
end; end
|
227
|
-
|
228
|
-
require_relative 'base-sequencer-implementation-every'
|
229
|
-
require_relative 'base-sequencer-implementation-move'
|
230
|
-
require_relative 'base-sequencer-implementation-play'
|
231
|
-
require_relative 'base-sequencer-implementation-play-timed'
|
@@ -3,6 +3,8 @@ module Musa
|
|
3
3
|
class BaseSequencer
|
4
4
|
module TickBasedTiming
|
5
5
|
|
6
|
+
using Musa::Extension::InspectNice
|
7
|
+
|
6
8
|
attr_reader :position, :ticks_per_bar, :tick_duration
|
7
9
|
|
8
10
|
def tick
|
@@ -27,9 +29,7 @@ module Musa
|
|
27
29
|
_release_public_ticks
|
28
30
|
end
|
29
31
|
|
30
|
-
private
|
31
|
-
|
32
|
-
def _init_timing
|
32
|
+
private def _init_timing
|
33
33
|
@ticks_per_bar = Rational(beats_per_bar * ticks_per_beat)
|
34
34
|
@tick_duration = Rational(1, @ticks_per_bar)
|
35
35
|
|
@@ -37,11 +37,11 @@ module Musa
|
|
37
37
|
@hold_ticks = 0
|
38
38
|
end
|
39
39
|
|
40
|
-
def _reset_timing
|
40
|
+
private def _reset_timing
|
41
41
|
@position = @position_mutex.synchronize { 1r - @tick_duration }
|
42
42
|
end
|
43
43
|
|
44
|
-
def _quantize_position(position, warn: true)
|
44
|
+
private def _quantize_position(position, warn: true)
|
45
45
|
ticks_position = position / @tick_duration
|
46
46
|
|
47
47
|
if ticks_position.round != ticks_position
|
@@ -50,19 +50,19 @@ module Musa
|
|
50
50
|
|
51
51
|
if warn
|
52
52
|
@logger.warn('BaseSequencer') { "_check_position: rounding "\
|
53
|
-
"position #{original_position} (#{original_position.to_f.round(5)}) "\
|
54
|
-
"to tick precision: #{position} (#{position.to_f.round(5)})" }
|
53
|
+
"position #{original_position.inspect} (#{original_position.to_f.round(5)}) "\
|
54
|
+
"to tick precision: #{position.inspect} (#{position.to_f.round(5)})" }
|
55
55
|
end
|
56
56
|
end
|
57
57
|
|
58
58
|
position
|
59
59
|
end
|
60
60
|
|
61
|
-
def _hold_public_ticks
|
61
|
+
private def _hold_public_ticks
|
62
62
|
@hold_public_ticks = true
|
63
63
|
end
|
64
64
|
|
65
|
-
def _release_public_ticks
|
65
|
+
private def _release_public_ticks
|
66
66
|
@hold_ticks.times { _tick(@position_mutex.synchronize { @position += @tick_duration }) }
|
67
67
|
@hold_ticks = 0
|
68
68
|
@hold_public_ticks = false
|
@@ -53,16 +53,14 @@ module Musa
|
|
53
53
|
@on_fast_forward.each { |block| block.call(false) }
|
54
54
|
end
|
55
55
|
|
56
|
-
private
|
57
|
-
|
58
|
-
def _init_timing
|
56
|
+
private def _init_timing
|
59
57
|
end
|
60
58
|
|
61
|
-
def _reset_timing
|
59
|
+
private def _reset_timing
|
62
60
|
@position = nil
|
63
61
|
end
|
64
62
|
|
65
|
-
def _quantize_position(position, warn: false)
|
63
|
+
private def _quantize_position(position, warn: false)
|
66
64
|
position
|
67
65
|
end
|
68
66
|
end
|
@@ -30,6 +30,7 @@ module Musa
|
|
30
30
|
else
|
31
31
|
@logger = Musa::Logger::Logger.new(sequencer: self, position_format: log_position_format)
|
32
32
|
|
33
|
+
@logger.fatal!
|
33
34
|
@logger.error! if do_error_log || do_error_log.nil?
|
34
35
|
@logger.debug! if do_log
|
35
36
|
end
|
@@ -82,6 +83,11 @@ module Musa
|
|
82
83
|
@timeslots.empty?
|
83
84
|
end
|
84
85
|
|
86
|
+
def quantize_position(position, warn: nil)
|
87
|
+
warn ||= false
|
88
|
+
_quantize_position(position, warn: warn)
|
89
|
+
end
|
90
|
+
|
85
91
|
def run
|
86
92
|
tick until empty?
|
87
93
|
end
|
@@ -114,22 +120,19 @@ module Musa
|
|
114
120
|
@event_handlers.last.launch event, *value_parameters, **key_parameters
|
115
121
|
end
|
116
122
|
|
117
|
-
def wait(bars_delay,
|
123
|
+
def wait(bars_delay, debug: nil, &block)
|
118
124
|
debug ||= false
|
119
125
|
|
120
126
|
control = EventHandler.new @event_handlers.last
|
121
127
|
@event_handlers.push control
|
122
128
|
|
123
129
|
if bars_delay.is_a? Numeric
|
124
|
-
_numeric_at position + bars_delay.rationalize, control,
|
130
|
+
_numeric_at position + bars_delay.rationalize, control, debug: debug, &block
|
125
131
|
else
|
126
132
|
bars_delay = Series::S(*bars_delay) if bars_delay.is_a?(Array)
|
127
133
|
bars_delay = bars_delay.instance if bars_delay
|
128
134
|
|
129
|
-
|
130
|
-
with = with.instance if with
|
131
|
-
|
132
|
-
_serie_at bars_delay.eval { |delay| position + delay }, control, with: with, debug: debug, &block
|
135
|
+
_serie_at bars_delay.eval { |delay| position + delay }, control, debug: debug, &block
|
133
136
|
end
|
134
137
|
|
135
138
|
@event_handlers.pop
|
@@ -137,11 +140,11 @@ module Musa
|
|
137
140
|
control
|
138
141
|
end
|
139
142
|
|
140
|
-
def now(
|
143
|
+
def now(&block)
|
141
144
|
control = EventHandler.new @event_handlers.last
|
142
145
|
@event_handlers.push control
|
143
146
|
|
144
|
-
_numeric_at position, control,
|
147
|
+
_numeric_at position, control, &block
|
145
148
|
|
146
149
|
@event_handlers.pop
|
147
150
|
|
@@ -154,22 +157,19 @@ module Musa
|
|
154
157
|
nil
|
155
158
|
end
|
156
159
|
|
157
|
-
def at(bar_position,
|
160
|
+
def at(bar_position, debug: nil, &block)
|
158
161
|
debug ||= false
|
159
162
|
|
160
163
|
control = EventHandler.new @event_handlers.last
|
161
164
|
@event_handlers.push control
|
162
165
|
|
163
166
|
if bar_position.is_a? Numeric
|
164
|
-
_numeric_at bar_position.rationalize, control,
|
167
|
+
_numeric_at bar_position.rationalize, control, debug: debug, &block
|
165
168
|
else
|
166
169
|
bar_position = Series::S(*bar_position) if bar_position.is_a? Array
|
167
170
|
bar_position = bar_position.instance if bar_position
|
168
171
|
|
169
|
-
|
170
|
-
with = with.instance if with
|
171
|
-
|
172
|
-
_serie_at bar_position, control, with: with, debug: debug, &block
|
172
|
+
_serie_at bar_position, control, debug: debug, &block
|
173
173
|
end
|
174
174
|
|
175
175
|
@event_handlers.pop
|
@@ -215,9 +215,6 @@ module Musa
|
|
215
215
|
end
|
216
216
|
|
217
217
|
def play_timed(timed_serie,
|
218
|
-
reference: nil,
|
219
|
-
step: nil,
|
220
|
-
right_open: nil,
|
221
218
|
on_stop: nil,
|
222
219
|
after_bars: nil, after: nil,
|
223
220
|
&block)
|
@@ -233,12 +230,7 @@ module Musa
|
|
233
230
|
|
234
231
|
@event_handlers.push control
|
235
232
|
|
236
|
-
_play_timed(timed_serie.instance,
|
237
|
-
control,
|
238
|
-
reference: reference,
|
239
|
-
step: step,
|
240
|
-
right_open: right_open,
|
241
|
-
&block)
|
233
|
+
_play_timed(timed_serie.instance, control, &block)
|
242
234
|
|
243
235
|
@event_handlers.pop
|
244
236
|
|
@@ -17,11 +17,11 @@ module Musa
|
|
17
17
|
:position=,
|
18
18
|
:event_handler
|
19
19
|
|
20
|
-
def_delegators :@
|
21
|
-
def_delegators :@
|
22
|
-
def_delegators :@
|
23
|
-
def_delegators :@
|
24
|
-
def_delegators :@
|
20
|
+
def_delegators :@dsl, :position, :quantize_position, :logger, :debug
|
21
|
+
def_delegators :@dsl, :with, :now, :at, :wait, :play, :play_timed, :every, :move
|
22
|
+
def_delegators :@dsl, :everying, :playing, :moving
|
23
|
+
def_delegators :@dsl, :launch, :on
|
24
|
+
def_delegators :@dsl, :run
|
25
25
|
|
26
26
|
def initialize(beats_per_bar = nil,
|
27
27
|
ticks_per_beat = nil,
|
@@ -37,7 +37,7 @@ module Musa
|
|
37
37
|
do_error_log: do_error_log,
|
38
38
|
log_position_format: log_position_format
|
39
39
|
|
40
|
-
@
|
40
|
+
@dsl = DSLContext.new @sequencer
|
41
41
|
|
42
42
|
with &block if block_given?
|
43
43
|
end
|
@@ -51,7 +51,9 @@ module Musa
|
|
51
51
|
|
52
52
|
def_delegators :@sequencer,
|
53
53
|
:launch, :on,
|
54
|
-
:position, :
|
54
|
+
:position, :quantize_position,
|
55
|
+
:size,
|
56
|
+
:everying, :playing, :moving,
|
55
57
|
:ticks_per_bar, :logger, :debug, :inspect,
|
56
58
|
:run
|
57
59
|
|
@@ -1,3 +1,10 @@
|
|
1
|
-
require_relative 'base-sequencer
|
1
|
+
require_relative 'base-sequencer'
|
2
|
+
|
2
3
|
require_relative 'base-sequencer-implementation'
|
4
|
+
|
5
|
+
require_relative 'base-sequencer-implementation-every'
|
6
|
+
require_relative 'base-sequencer-implementation-move'
|
7
|
+
require_relative 'base-sequencer-implementation-play'
|
8
|
+
require_relative 'base-sequencer-implementation-play-timed'
|
9
|
+
|
3
10
|
require_relative 'sequencer-dsl'
|
@@ -5,209 +5,358 @@ using Musa::Extension::DeepCopy
|
|
5
5
|
|
6
6
|
module Musa
|
7
7
|
module Series
|
8
|
-
module
|
8
|
+
module Constructors; extend self; end
|
9
|
+
module Operations; end
|
9
10
|
|
10
|
-
|
11
|
-
def prototype?
|
12
|
-
@is_instance ? false : true
|
13
|
-
end
|
11
|
+
include Constructors
|
14
12
|
|
15
|
-
|
16
|
-
|
13
|
+
module Serie
|
14
|
+
def self.base
|
15
|
+
SerieImplementation
|
17
16
|
end
|
18
17
|
|
19
|
-
def
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
18
|
+
def self.with(source: false,
|
19
|
+
source_as: nil,
|
20
|
+
private_source: nil,
|
21
|
+
sources: false,
|
22
|
+
sources_as: nil,
|
23
|
+
private_sources: nil,
|
24
|
+
smart_block: false,
|
25
|
+
block: false,
|
26
|
+
block_as: nil)
|
27
|
+
|
28
|
+
source_as ||= :source
|
29
|
+
source_setter = (source_as.to_s + '=').to_sym
|
30
|
+
|
31
|
+
sources_as ||= :sources
|
32
|
+
sources_setter = (sources_as.to_s + '=').to_sym
|
33
|
+
|
34
|
+
block_as ||= :proc
|
35
|
+
block_setter = (block_as.to_s + '=').to_sym
|
36
|
+
|
37
|
+
Module.new do
|
38
|
+
include SerieImplementation
|
39
|
+
|
40
|
+
if source
|
41
|
+
define_method source_as do ||
|
42
|
+
@source
|
43
|
+
end
|
44
|
+
|
45
|
+
define_method source_setter do |serie|
|
46
|
+
raise ArgumentError, "New source should be a #{@get}" unless @source.nil? || @source.prototype? == serie&.prototype?
|
47
|
+
|
48
|
+
serie ||= Musa::Series::Constructors.NIL
|
49
|
+
@get = serie&.instance? ? :instance : :prototype
|
50
|
+
@source = serie
|
51
|
+
mark_regarding! @source
|
52
|
+
end
|
53
|
+
|
54
|
+
if private_source
|
55
|
+
private source_as
|
56
|
+
private source_setter
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
if sources
|
61
|
+
define_method sources_as do ||
|
62
|
+
@sources
|
63
|
+
end
|
64
|
+
|
65
|
+
define_method sources_setter do |series|
|
66
|
+
case series
|
67
|
+
when Array
|
68
|
+
getter = @get || ((series.first)&.instance? ? :instance : :prototype)
|
69
|
+
@sources = series.collect(&getter)
|
70
|
+
when Hash
|
71
|
+
getter = @get || ((series.values.first)&.instance? ? :instance : :prototype)
|
72
|
+
@sources = series.transform_values(&getter)
|
73
|
+
else
|
74
|
+
raise ArgumentError, "Only allowed Array or Hash"
|
75
|
+
end
|
76
|
+
|
77
|
+
mark_as! getter
|
78
|
+
end
|
79
|
+
|
80
|
+
if private_sources
|
81
|
+
private sources_as
|
82
|
+
private sources_setter
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
if smart_block
|
87
|
+
define_method block_as do |&block|
|
88
|
+
if block
|
89
|
+
@block = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
|
90
|
+
else
|
91
|
+
@block.proc
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
define_method block_setter do |block|
|
96
|
+
@block = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
|
97
|
+
end
|
98
|
+
|
99
|
+
elsif block
|
100
|
+
define_method block_as do |&block|
|
101
|
+
if block
|
102
|
+
@block = block
|
103
|
+
else
|
104
|
+
@block
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
define_method block_setter do |block|
|
109
|
+
@block = block
|
110
|
+
end
|
111
|
+
end
|
24
112
|
end
|
25
113
|
end
|
26
114
|
|
27
|
-
|
115
|
+
module Prototyping
|
116
|
+
def prototype?
|
117
|
+
@is_instance ? false : true
|
118
|
+
end
|
28
119
|
|
29
|
-
|
30
|
-
|
31
|
-
self
|
32
|
-
else
|
33
|
-
clone(freeze: false).tap(&:_instance!).mark_as_instance!(self)
|
120
|
+
def instance?
|
121
|
+
@is_instance ? true : false
|
34
122
|
end
|
35
|
-
end
|
36
123
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
if @sources.is_a?(Array)
|
50
|
-
@sources = @sources.collect(&:prototype).freeze
|
51
|
-
elsif @sources.is_a?(Hash)
|
52
|
-
@sources = @sources.transform_values(&:prototype).freeze
|
124
|
+
def prototype
|
125
|
+
if @is_instance
|
126
|
+
if !@instance_of
|
127
|
+
@instance_of = clone
|
128
|
+
@instance_of._prototype!
|
129
|
+
@instance_of.mark_as_prototype!
|
130
|
+
@instance_of.init if @instance_of.respond_to?(:init)
|
131
|
+
end
|
132
|
+
|
133
|
+
@instance_of
|
134
|
+
else
|
135
|
+
self
|
53
136
|
end
|
54
137
|
end
|
55
|
-
end
|
56
138
|
|
57
|
-
|
58
|
-
@source = @source.instance if @source
|
139
|
+
alias_method :p, :prototype
|
59
140
|
|
60
|
-
|
61
|
-
if @
|
62
|
-
|
63
|
-
|
64
|
-
|
141
|
+
def instance
|
142
|
+
if @is_instance
|
143
|
+
self
|
144
|
+
else
|
145
|
+
new_instance = clone
|
146
|
+
|
147
|
+
new_instance._instance!
|
148
|
+
new_instance.mark_as_instance!(self)
|
149
|
+
new_instance.init if new_instance.respond_to?(:init)
|
150
|
+
|
151
|
+
new_instance
|
65
152
|
end
|
66
153
|
end
|
67
|
-
end
|
68
154
|
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
155
|
+
alias_method :i, :instance
|
156
|
+
|
157
|
+
# By default, if there is a @source attribute that contains the source of the serie, SeriePrototyping will
|
158
|
+
# handle prototyping/instancing automatically.
|
159
|
+
# If there is a @sources attribute with the eventual several sources, SeriePrototyping will handle them by
|
160
|
+
# default.
|
161
|
+
# If needed the subclasses can override this behaviour to accommodate to real subclass specificities.
|
162
|
+
#
|
163
|
+
protected def _prototype!
|
164
|
+
@source = @source.prototype if @source
|
165
|
+
|
166
|
+
if @sources
|
167
|
+
if @sources.is_a?(Array)
|
168
|
+
@sources = @sources.collect(&:prototype)
|
169
|
+
elsif @sources.is_a?(Hash)
|
170
|
+
@sources = @sources.transform_values(&:prototype)
|
171
|
+
end
|
172
|
+
end
|
74
173
|
end
|
75
|
-
end
|
76
174
|
|
77
|
-
|
78
|
-
|
79
|
-
freeze
|
80
|
-
end
|
175
|
+
protected def _instance!
|
176
|
+
@source = @source.instance if @source
|
81
177
|
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
178
|
+
if @sources
|
179
|
+
if @sources.is_a?(Array)
|
180
|
+
@sources = @sources.collect(&:instance)
|
181
|
+
elsif @sources.is_a?(Hash)
|
182
|
+
@sources = @sources.transform_values(&:instance)
|
183
|
+
end
|
184
|
+
end
|
185
|
+
end
|
87
186
|
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
187
|
+
protected def mark_as!(getter)
|
188
|
+
case getter
|
189
|
+
when :prototype
|
190
|
+
mark_as_prototype!
|
191
|
+
when :instance
|
192
|
+
mark_as_instance!
|
193
|
+
else
|
194
|
+
raise ArgumentError, "Only can be marked as :prototype or :instance"
|
195
|
+
end
|
92
196
|
end
|
93
|
-
end
|
94
|
-
end
|
95
197
|
|
96
|
-
|
97
|
-
|
98
|
-
|
198
|
+
protected def mark_regarding!(source)
|
199
|
+
if source.prototype?
|
200
|
+
mark_as_prototype!
|
201
|
+
else
|
202
|
+
mark_as_instance!
|
203
|
+
end
|
204
|
+
end
|
99
205
|
|
100
|
-
|
101
|
-
|
206
|
+
protected def mark_as_prototype!
|
207
|
+
@get = :prototype
|
102
208
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
@_current_value = nil
|
209
|
+
@is_instance = nil
|
210
|
+
self
|
211
|
+
end
|
107
212
|
|
108
|
-
|
213
|
+
protected def mark_as_instance!(prototype = nil)
|
214
|
+
@get = :instance
|
109
215
|
|
110
|
-
|
216
|
+
@instance_of = prototype
|
217
|
+
@is_instance = true
|
218
|
+
self
|
219
|
+
end
|
220
|
+
|
221
|
+
class PrototypingError < RuntimeError
|
222
|
+
def initialize(message = nil)
|
223
|
+
message ||= 'This serie is a prototype serie: cannot be consumed. To consume the serie use an instance serie via .instance method'
|
224
|
+
super message
|
225
|
+
end
|
226
|
+
end
|
111
227
|
end
|
112
228
|
|
113
|
-
|
114
|
-
|
229
|
+
module SerieImplementation
|
230
|
+
include Serie
|
231
|
+
include Prototyping
|
232
|
+
include Operations
|
115
233
|
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
234
|
+
def init
|
235
|
+
@_have_peeked_next_value = false
|
236
|
+
@_peeked_next_value = nil
|
237
|
+
@_have_current_value = false
|
238
|
+
@_current_value = nil
|
239
|
+
|
240
|
+
_init
|
241
|
+
|
242
|
+
self
|
243
|
+
end
|
244
|
+
|
245
|
+
private def _init; end
|
246
|
+
|
247
|
+
def restart(...)
|
248
|
+
raise PrototypingError unless @is_instance
|
249
|
+
init
|
250
|
+
_restart(...)
|
251
|
+
|
252
|
+
self
|
253
|
+
end
|
254
|
+
|
255
|
+
private def _restart; end
|
256
|
+
|
257
|
+
def next_value
|
258
|
+
raise PrototypingError unless @is_instance
|
259
|
+
|
260
|
+
unless @_have_current_value && @_current_value.nil?
|
261
|
+
if @_have_peeked_next_value
|
262
|
+
@_have_peeked_next_value = false
|
263
|
+
@_current_value = @_peeked_next_value
|
264
|
+
else
|
265
|
+
@_current_value = _next_value
|
266
|
+
end
|
122
267
|
end
|
268
|
+
|
269
|
+
@_current_value
|
123
270
|
end
|
124
271
|
|
125
|
-
|
126
|
-
end
|
272
|
+
private def _next_value; end
|
127
273
|
|
128
|
-
|
274
|
+
alias_method :v, :next_value
|
129
275
|
|
130
|
-
|
131
|
-
|
276
|
+
def peek_next_value
|
277
|
+
raise PrototypingError unless @is_instance
|
132
278
|
|
133
|
-
|
134
|
-
|
135
|
-
|
279
|
+
if !@_have_peeked_next_value
|
280
|
+
@_have_peeked_next_value = true
|
281
|
+
@_peeked_next_value = _next_value
|
282
|
+
end
|
283
|
+
|
284
|
+
@_peeked_next_value
|
136
285
|
end
|
137
286
|
|
138
|
-
|
139
|
-
|
287
|
+
def current_value
|
288
|
+
raise PrototypingError unless @is_instance
|
140
289
|
|
141
|
-
|
142
|
-
|
290
|
+
@_current_value
|
291
|
+
end
|
143
292
|
|
144
|
-
|
145
|
-
|
293
|
+
def infinite?
|
294
|
+
@source&.infinite? || false
|
295
|
+
end
|
146
296
|
|
147
|
-
|
148
|
-
|
149
|
-
end
|
297
|
+
def to_a(recursive: nil, duplicate: nil, restart: nil, dr: nil)
|
298
|
+
recursive ||= false
|
150
299
|
|
151
|
-
|
152
|
-
recursive ||= false
|
300
|
+
dr = instance? if dr.nil?
|
153
301
|
|
154
|
-
|
302
|
+
duplicate = dr if duplicate.nil?
|
303
|
+
restart = dr if restart.nil?
|
155
304
|
|
156
|
-
|
157
|
-
restart = dr if restart.nil?
|
305
|
+
raise 'Cannot convert to array an infinite serie' if infinite?
|
158
306
|
|
159
|
-
|
307
|
+
array = []
|
160
308
|
|
161
|
-
|
309
|
+
serie = instance
|
162
310
|
|
163
|
-
|
311
|
+
serie = serie.clone(deep: true) if duplicate
|
312
|
+
serie = serie.restart if restart
|
164
313
|
|
165
|
-
|
166
|
-
|
314
|
+
while value = serie.next_value
|
315
|
+
array << if recursive
|
316
|
+
process_for_to_a(value)
|
317
|
+
else
|
318
|
+
value
|
319
|
+
end
|
320
|
+
end
|
167
321
|
|
168
|
-
|
169
|
-
array << if recursive
|
170
|
-
process_for_to_a(value)
|
171
|
-
else
|
172
|
-
value
|
173
|
-
end
|
322
|
+
array
|
174
323
|
end
|
175
324
|
|
176
|
-
|
177
|
-
end
|
325
|
+
alias_method :a, :to_a
|
178
326
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
Nodificator.to_node(self, **attributes)
|
183
|
-
end
|
327
|
+
def to_node(**attributes)
|
328
|
+
Nodificator.to_node(self, **attributes)
|
329
|
+
end
|
184
330
|
|
185
|
-
|
331
|
+
alias_method :node, :to_node
|
186
332
|
|
187
|
-
|
188
|
-
|
333
|
+
class Nodificator
|
334
|
+
extend Musa::GenerativeGrammar
|
189
335
|
|
190
|
-
|
191
|
-
|
336
|
+
def self.to_node(serie, **attributes)
|
337
|
+
N(serie, **attributes)
|
338
|
+
end
|
192
339
|
end
|
193
|
-
end
|
194
340
|
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
341
|
+
private_constant :Nodificator
|
342
|
+
|
343
|
+
private def process_for_to_a(value)
|
344
|
+
case value
|
345
|
+
when Serie
|
346
|
+
value.to_a(recursive: true, restart: false, duplicate: false)
|
347
|
+
when Array
|
348
|
+
a = value.clone
|
349
|
+
a.collect! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
|
350
|
+
when Hash
|
351
|
+
h = value.clone
|
352
|
+
h.transform_values! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
|
353
|
+
else
|
354
|
+
value
|
355
|
+
end
|
209
356
|
end
|
210
357
|
end
|
358
|
+
|
359
|
+
private_constant :SerieImplementation
|
211
360
|
end
|
212
361
|
end
|
213
362
|
end
|