musa-dsl 0.22.3 → 0.23.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +3 -1
  3. data/lib/musa-dsl.rb +14 -8
  4. data/lib/musa-dsl/core-ext/deep-copy.rb +12 -1
  5. data/lib/musa-dsl/core-ext/inspect-nice.rb +1 -2
  6. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +13 -11
  7. data/lib/musa-dsl/datasets/p.rb +41 -16
  8. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +14 -12
  9. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +32 -6
  10. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +24 -10
  11. data/lib/musa-dsl/generative/backboner.rb +6 -11
  12. data/lib/musa-dsl/generative/generative-grammar.rb +1 -3
  13. data/lib/musa-dsl/generative/markov.rb +10 -6
  14. data/lib/musa-dsl/logger/logger.rb +6 -1
  15. data/lib/musa-dsl/matrix/matrix.rb +9 -7
  16. data/lib/musa-dsl/midi/midi-voices.rb +8 -7
  17. data/lib/musa-dsl/music/scales.rb +1 -1
  18. data/lib/musa-dsl/neumalang/neumalang.rb +1 -1
  19. data/lib/musa-dsl/neumas/array-to-neumas.rb +1 -1
  20. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +9 -4
  21. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +30 -129
  22. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +10 -24
  23. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +9 -9
  24. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +3 -5
  25. data/lib/musa-dsl/sequencer/base-sequencer.rb +14 -23
  26. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +9 -7
  27. data/lib/musa-dsl/sequencer/sequencer.rb +7 -0
  28. data/lib/musa-dsl/series/base-series.rb +293 -144
  29. data/lib/musa-dsl/series/buffer-serie.rb +237 -0
  30. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +136 -105
  31. data/lib/musa-dsl/series/main-serie-constructors.rb +251 -156
  32. data/lib/musa-dsl/series/main-serie-operations.rb +308 -303
  33. data/lib/musa-dsl/series/proxy-serie.rb +21 -41
  34. data/lib/musa-dsl/series/quantizer-serie.rb +44 -46
  35. data/lib/musa-dsl/series/queue-serie.rb +39 -43
  36. data/lib/musa-dsl/series/series-composer.rb +149 -0
  37. data/lib/musa-dsl/series/series.rb +6 -3
  38. data/lib/musa-dsl/series/timed-serie.rb +343 -0
  39. data/musa-dsl.gemspec +13 -3
  40. metadata +10 -11
  41. data/lib/musa-dsl/series/flattener-timed-serie.rb +0 -61
  42. data/lib/musa-dsl/series/holder-serie.rb +0 -87
  43. data/lib/musa-dsl/series/union-timed-series.rb +0 -109
@@ -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, with: nil, debug: nil, &block)
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(value_parameters, key_parameters)
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, block: block_key_parameters_binder,
104
- value_parameters: value_parameters,
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(bar_position_serie, control, with: nil, debug: nil, &block)
114
- bar_position = bar_position_serie.next_value
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, with: with_value, debug: debug, &block
114
+ _numeric_at bar_position, control, debug: debug, &block
124
115
 
125
116
  _numeric_at bar_position, control, debug: false do
126
- _serie_at bar_position_serie, control, with: with, debug: debug, &block
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
@@ -83,6 +83,11 @@ module Musa
83
83
  @timeslots.empty?
84
84
  end
85
85
 
86
+ def quantize_position(position, warn: nil)
87
+ warn ||= false
88
+ _quantize_position(position, warn: warn)
89
+ end
90
+
86
91
  def run
87
92
  tick until empty?
88
93
  end
@@ -115,22 +120,19 @@ module Musa
115
120
  @event_handlers.last.launch event, *value_parameters, **key_parameters
116
121
  end
117
122
 
118
- def wait(bars_delay, with: nil, debug: nil, &block)
123
+ def wait(bars_delay, debug: nil, &block)
119
124
  debug ||= false
120
125
 
121
126
  control = EventHandler.new @event_handlers.last
122
127
  @event_handlers.push control
123
128
 
124
129
  if bars_delay.is_a? Numeric
125
- _numeric_at position + bars_delay.rationalize, control, with: with, debug: debug, &block
130
+ _numeric_at position + bars_delay.rationalize, control, debug: debug, &block
126
131
  else
127
132
  bars_delay = Series::S(*bars_delay) if bars_delay.is_a?(Array)
128
133
  bars_delay = bars_delay.instance if bars_delay
129
134
 
130
- with = Series::S(*with).repeat if with.is_a?(Array)
131
- with = with.instance if with
132
-
133
- _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
134
136
  end
135
137
 
136
138
  @event_handlers.pop
@@ -138,11 +140,11 @@ module Musa
138
140
  control
139
141
  end
140
142
 
141
- def now(with: nil, &block)
143
+ def now(&block)
142
144
  control = EventHandler.new @event_handlers.last
143
145
  @event_handlers.push control
144
146
 
145
- _numeric_at position, control, with: with, &block
147
+ _numeric_at position, control, &block
146
148
 
147
149
  @event_handlers.pop
148
150
 
@@ -155,22 +157,19 @@ module Musa
155
157
  nil
156
158
  end
157
159
 
158
- def at(bar_position, with: nil, debug: nil, &block)
160
+ def at(bar_position, debug: nil, &block)
159
161
  debug ||= false
160
162
 
161
163
  control = EventHandler.new @event_handlers.last
162
164
  @event_handlers.push control
163
165
 
164
166
  if bar_position.is_a? Numeric
165
- _numeric_at bar_position.rationalize, control, with: with, debug: debug, &block
167
+ _numeric_at bar_position.rationalize, control, debug: debug, &block
166
168
  else
167
169
  bar_position = Series::S(*bar_position) if bar_position.is_a? Array
168
170
  bar_position = bar_position.instance if bar_position
169
171
 
170
- with = Series::S(*with).repeat if with.is_a? Array
171
- with = with.instance if with
172
-
173
- _serie_at bar_position, control, with: with, debug: debug, &block
172
+ _serie_at bar_position, control, debug: debug, &block
174
173
  end
175
174
 
176
175
  @event_handlers.pop
@@ -216,9 +215,6 @@ module Musa
216
215
  end
217
216
 
218
217
  def play_timed(timed_serie,
219
- reference: nil,
220
- step: nil,
221
- right_open: nil,
222
218
  on_stop: nil,
223
219
  after_bars: nil, after: nil,
224
220
  &block)
@@ -234,12 +230,7 @@ module Musa
234
230
 
235
231
  @event_handlers.push control
236
232
 
237
- _play_timed(timed_serie.instance,
238
- control,
239
- reference: reference,
240
- step: step,
241
- right_open: right_open,
242
- &block)
233
+ _play_timed(timed_serie.instance, control, &block)
243
234
 
244
235
  @event_handlers.pop
245
236
 
@@ -17,11 +17,11 @@ module Musa
17
17
  :position=,
18
18
  :event_handler
19
19
 
20
- def_delegators :@context, :position, :logger, :debug
21
- def_delegators :@context, :with, :now, :at, :wait, :play, :play_timed, :every, :move
22
- def_delegators :@context, :everying, :playing, :moving
23
- def_delegators :@context, :launch, :on
24
- def_delegators :@context, :run
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
- @context = DSLContext.new @sequencer
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, :size, :everying, :playing, :moving,
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
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 SerieOperations end
8
+ module Constructors; extend self; end
9
+ module Operations; end
9
10
 
10
- module SeriePrototyping
11
- def prototype?
12
- @is_instance ? false : true
13
- end
11
+ include Constructors
14
12
 
15
- def instance?
16
- @is_instance ? true : false
13
+ module Serie
14
+ def self.base
15
+ SerieImplementation
17
16
  end
18
17
 
19
- def prototype
20
- if @is_instance
21
- @instance_of || (@instance_of = self.clone.tap(&:_prototype!).mark_as_prototype!)
22
- else
23
- self
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
- alias_method :p, :prototype
115
+ module Prototyping
116
+ def prototype?
117
+ @is_instance ? false : true
118
+ end
28
119
 
29
- def instance
30
- if @is_instance
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
- alias_method :i, :instance
38
-
39
- # By default, if there is a @source attribute that contains the source of the serie, SeriePrototyping will
40
- # handle prototyping/instancing automatically.
41
- # If there is a @sources attribute with the eventual several sources, SeriePrototyping will handle them by
42
- # default.
43
- # If needed the subclasses can override this behaviour to accomodate to real subclass specificities.
44
- #
45
- protected def _prototype!
46
- @source = @source.prototype if @source
47
-
48
- if @sources
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
- protected def _instance!
58
- @source = @source.instance if @source
139
+ alias_method :p, :prototype
59
140
 
60
- if @sources
61
- if @sources.is_a?(Array)
62
- @sources = @sources.collect(&:instance)
63
- elsif @sources.is_a?(Hash)
64
- @sources = @sources.transform_values(&:instance)
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
- protected def mark_regarding!(source)
70
- if source.prototype?
71
- mark_as_prototype!
72
- else
73
- mark_as_instance!
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
- protected def mark_as_prototype!
78
- @is_instance = nil
79
- freeze
80
- end
175
+ protected def _instance!
176
+ @source = @source.instance if @source
81
177
 
82
- protected def mark_as_instance!(prototype = nil)
83
- @instance_of = prototype
84
- @is_instance = true
85
- self
86
- end
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
- class PrototypingSerieError < RuntimeError
89
- def initialize(message = nil)
90
- message ||= 'This serie is a prototype serie: cannot be consumed. To consume the serie use an instance serie via .instance method'
91
- super message
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
- module Serie
97
- include SeriePrototyping
98
- include SerieOperations
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
- def restart
101
- raise PrototypingSerieError unless @is_instance
206
+ protected def mark_as_prototype!
207
+ @get = :prototype
102
208
 
103
- @_have_peeked_next_value = false
104
- @_peeked_next_value = nil
105
- @_have_current_value = false
106
- @_current_value = nil
209
+ @is_instance = nil
210
+ self
211
+ end
107
212
 
108
- _restart if respond_to? :_restart
213
+ protected def mark_as_instance!(prototype = nil)
214
+ @get = :instance
109
215
 
110
- self
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
- def next_value
114
- raise PrototypingSerieError unless @is_instance
229
+ module SerieImplementation
230
+ include Serie
231
+ include Prototyping
232
+ include Operations
115
233
 
116
- unless @_have_current_value && @_current_value.nil?
117
- if @_have_peeked_next_value
118
- @_have_peeked_next_value = false
119
- @_current_value = @_peeked_next_value
120
- else
121
- @_current_value = _next_value
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
- @_current_value
126
- end
272
+ private def _next_value; end
127
273
 
128
- alias_method :v, :next_value
274
+ alias_method :v, :next_value
129
275
 
130
- def peek_next_value
131
- raise PrototypingSerieError unless @is_instance
276
+ def peek_next_value
277
+ raise PrototypingError unless @is_instance
132
278
 
133
- unless @_have_peeked_next_value
134
- @_have_peeked_next_value = true
135
- @_peeked_next_value = _next_value
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
- @_peeked_next_value
139
- end
287
+ def current_value
288
+ raise PrototypingError unless @is_instance
140
289
 
141
- def current_value
142
- raise PrototypingSerieError unless @is_instance
290
+ @_current_value
291
+ end
143
292
 
144
- @_current_value
145
- end
293
+ def infinite?
294
+ @source&.infinite? || false
295
+ end
146
296
 
147
- def infinite?
148
- false
149
- end
297
+ def to_a(recursive: nil, duplicate: nil, restart: nil, dr: nil)
298
+ recursive ||= false
150
299
 
151
- def to_a(recursive: nil, duplicate: nil, restart: nil, dr: nil)
152
- recursive ||= false
300
+ dr = instance? if dr.nil?
153
301
 
154
- dr ||= instance?
302
+ duplicate = dr if duplicate.nil?
303
+ restart = dr if restart.nil?
155
304
 
156
- duplicate = dr if duplicate.nil?
157
- restart = dr if restart.nil?
305
+ raise 'Cannot convert to array an infinite serie' if infinite?
158
306
 
159
- raise 'Cannot convert to array an infinite serie' if infinite?
307
+ array = []
160
308
 
161
- array = []
309
+ serie = instance
162
310
 
163
- serie = instance
311
+ serie = serie.clone(deep: true) if duplicate
312
+ serie = serie.restart if restart
164
313
 
165
- serie = serie.clone(deep: true) if duplicate
166
- serie = serie.restart if restart
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
- while value = serie.next_value
169
- array << if recursive
170
- process_for_to_a(value)
171
- else
172
- value
173
- end
322
+ array
174
323
  end
175
324
 
176
- array
177
- end
325
+ alias_method :a, :to_a
178
326
 
179
- alias_method :a, :to_a
180
-
181
- def to_node(**attributes)
182
- Nodificator.to_node(self, **attributes)
183
- end
327
+ def to_node(**attributes)
328
+ Nodificator.to_node(self, **attributes)
329
+ end
184
330
 
185
- alias_method :node, :to_node
331
+ alias_method :node, :to_node
186
332
 
187
- class Nodificator
188
- extend Musa::GenerativeGrammar
333
+ class Nodificator
334
+ extend Musa::GenerativeGrammar
189
335
 
190
- def self.to_node(serie, **attributes)
191
- N(serie, **attributes)
336
+ def self.to_node(serie, **attributes)
337
+ N(serie, **attributes)
338
+ end
192
339
  end
193
- end
194
340
 
195
- private_constant :Nodificator
196
-
197
- private def process_for_to_a(value)
198
- case value
199
- when Serie
200
- value.to_a(recursive: true, restart: false, duplicate: false)
201
- when Array
202
- a = value.clone
203
- a.collect! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
204
- when Hash
205
- h = value.clone
206
- h.transform_values! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
207
- else
208
- value
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