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.
Files changed (42) 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 +1 -0
  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-public.rb → base-sequencer.rb} +15 -23
  26. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +9 -7
  27. data/lib/musa-dsl/sequencer/sequencer.rb +8 -1
  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 +139 -60
  31. data/lib/musa-dsl/series/main-serie-constructors.rb +254 -165
  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 -2
  38. data/lib/musa-dsl/series/timed-serie.rb +343 -0
  39. data/musa-dsl.gemspec +13 -3
  40. metadata +11 -11
  41. data/lib/musa-dsl/series/flattener-timed-serie.rb +0 -61
  42. 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, 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
@@ -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, with: nil, debug: nil, &block)
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, with: with, debug: debug, &block
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
- with = Series::S(*with).repeat if with.is_a?(Array)
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(with: nil, &block)
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, with: with, &block
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, with: nil, debug: nil, &block)
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, with: with, debug: debug, &block
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
- with = Series::S(*with).repeat if with.is_a? Array
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 :@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
- require_relative 'base-sequencer-public'
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