musa-dsl 0.22.5 → 0.23.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) 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 +38 -15
  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/midi/midi-voices.rb +8 -7
  16. data/lib/musa-dsl/music/scales.rb +1 -1
  17. data/lib/musa-dsl/neumalang/neumalang.rb +1 -1
  18. data/lib/musa-dsl/neumas/array-to-neumas.rb +1 -1
  19. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +2 -2
  20. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-timed.rb +2 -1
  21. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +2 -0
  22. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +4 -2
  23. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +6 -6
  24. data/lib/musa-dsl/series/base-series.rb +293 -144
  25. data/lib/musa-dsl/series/buffer-serie.rb +236 -0
  26. data/lib/musa-dsl/series/hash-or-array-serie-splitter.rb +145 -115
  27. data/lib/musa-dsl/series/main-serie-constructors.rb +249 -156
  28. data/lib/musa-dsl/series/main-serie-operations.rb +331 -318
  29. data/lib/musa-dsl/series/proxy-serie.rb +25 -41
  30. data/lib/musa-dsl/series/quantizer-serie.rb +38 -38
  31. data/lib/musa-dsl/series/queue-serie.rb +39 -43
  32. data/lib/musa-dsl/series/series-composer.rb +316 -0
  33. data/lib/musa-dsl/series/series.rb +5 -1
  34. data/lib/musa-dsl/series/timed-serie.rb +119 -130
  35. data/musa-dsl.gemspec +13 -3
  36. metadata +9 -9
  37. data/.ruby-version +0 -1
  38. data/lib/musa-dsl/series/holder-serie.rb +0 -87
@@ -3,13 +3,8 @@ require_relative '../core-ext/with'
3
3
 
4
4
  using Musa::Extension::Arrayfy
5
5
 
6
- # incluir With -> hecho
7
- # eliminar method_missing
8
- # crear rama tb debe recibir la serie de la history -> ya lo hace
9
- # crear rama puede repetirse (hasta terminar según ended_when) -> no
10
- #
11
- # hacer que pueda funcionar en tiempo real? le vas suministrando seeds y le vas diciendo qué opción has elegido (p.ej. para hacer un armonizador en tiempo real)
12
- # esto mismo sería aplicable en otros generadores? variatio/darwin? generative-grammar? markov?
6
+ # TODO hacer que pueda funcionar en tiempo real? le vas suministrando seeds y le vas diciendo qué opción has elegido (p.ej. para hacer un armonizador en tiempo real)
7
+ # TODO esto mismo sería aplicable en otros generadores? variatio/darwin? generative-grammar? markov?
13
8
 
14
9
  module Musa
15
10
  module Backboner
@@ -17,12 +12,12 @@ module Musa
17
12
  include Musa::Extension::With
18
13
 
19
14
  def initialize(&block)
20
- @context = RulesEvalContext.new(&block)
15
+ @dsl = RulesEvalContext.new(&block)
21
16
  end
22
17
 
23
18
  def generate_possibilities(object, confirmed_node = nil, node = nil, grow_rules = nil)
24
19
  node ||= Node.new
25
- grow_rules ||= @context._grow_rules
20
+ grow_rules ||= @dsl._grow_rules
26
21
 
27
22
  history = confirmed_node.history if confirmed_node
28
23
  history ||= []
@@ -33,9 +28,9 @@ module Musa
33
28
  if grow_rule
34
29
  grow_rule.generate_possibilities(object, history).each do |new_object|
35
30
  new_node = Node.new new_object, node
36
- new_node.mark_as_ended! if @context._ended? new_object
31
+ new_node.mark_as_ended! if @dsl._ended? new_object
37
32
 
38
- rejection = @context._cut_rules.find { |cut_rule| cut_rule.rejects?(new_object, history) }
33
+ rejection = @dsl._cut_rules.find { |cut_rule| cut_rule.rejects?(new_object, history) }
39
34
  # TODO: include rejection secondary reasons in rejection message
40
35
 
41
36
  new_node.reject! rejection if rejection
@@ -100,9 +100,7 @@ module Musa
100
100
  options[index].to_serie.to_node
101
101
  end
102
102
 
103
- def to_serie(flatten: nil, &condition)
104
- flatten ||= true
105
-
103
+ def to_serie(flatten: true, &condition)
106
104
  serie = _options(&condition).collect { |o| o.collect(&:content) }.to_serie(of_series: true).merge
107
105
  serie = serie.flatten if flatten
108
106
 
@@ -7,9 +7,8 @@ module Musa
7
7
  module Markov
8
8
  class Markov
9
9
  include Musa::Extension::SmartProcBinder
10
- include Musa::Series::Serie
10
+ include Musa::Series::Serie.base
11
11
 
12
- attr_accessor :start, :finish, :random, :transitions
13
12
 
14
13
  def initialize(transitions:, start:, finish: nil, random: nil)
15
14
  @transitions = transitions.clone.freeze
@@ -22,23 +21,28 @@ module Musa
22
21
 
23
22
  @procedure_binders = {}
24
23
 
25
- _restart
24
+ init
26
25
  end
27
26
 
28
- def _restart
27
+ attr_accessor :start
28
+ attr_accessor :finish
29
+ attr_accessor :random
30
+ attr_accessor :transitions
31
+
32
+ private def _init
29
33
  @current = nil
30
34
  @finished = false
31
35
  @history = []
32
36
  end
33
37
 
34
- def _next_value
38
+ private def _next_value
35
39
  if @finished
36
40
  @current = nil
37
41
  else
38
42
  if @current.nil?
39
43
  @current = @start
40
44
  else
41
- if @transitions.has_key? @current
45
+ if @transitions.has_key?(@current)
42
46
  options = @transitions[@current]
43
47
 
44
48
  case options
@@ -1,7 +1,12 @@
1
1
  require 'logger'
2
2
 
3
+ require_relative '../core-ext/inspect-nice'
4
+
5
+
3
6
  module Musa; module Logger
4
7
  class Logger < ::Logger
8
+ using Musa::Extension::InspectNice
9
+
5
10
  def initialize(sequencer: nil, position_format: nil)
6
11
  super STDERR, level: WARN
7
12
 
@@ -22,7 +27,7 @@ module Musa; module Logger
22
27
 
23
28
  progname = "[#{progname}]" if progname
24
29
 
25
- "#{position}#{level}#{progname} #{msg}\n"
30
+ "#{position}#{level}#{progname}#{' ' if position || level || progname}#{msg}\n"
26
31
  else
27
32
  "\n"
28
33
  end
@@ -10,7 +10,7 @@ using Musa::Extension::ExplodeRanges
10
10
  module Musa
11
11
  module MIDIVoices
12
12
  class MIDIVoices
13
- attr_accessor :log
13
+ attr_accessor :do_log
14
14
 
15
15
  def initialize(sequencer:, output:, channels:, do_log: nil)
16
16
  do_log ||= false
@@ -24,7 +24,7 @@ module Musa
24
24
  end
25
25
 
26
26
  def reset
27
- @voices = @channels.collect { |channel| MIDIVoice.new sequencer: @sequencer, output: @output, channel: channel, log: @do_log }.freeze
27
+ @voices = @channels.collect { |channel| MIDIVoice.new(sequencer: @sequencer, output: @output, channel: channel, do_log: @do_log) }.freeze
28
28
  end
29
29
 
30
30
  attr_reader :voices
@@ -48,14 +48,14 @@ module Musa
48
48
  attr_accessor :name, :do_log
49
49
  attr_reader :sequencer, :output, :channel, :active_pitches, :tick_duration
50
50
 
51
- def initialize(sequencer:, output:, channel:, name: nil, log: nil)
52
- log ||= false
51
+ def initialize(sequencer:, output:, channel:, name: nil, do_log: nil)
52
+ do_log ||= false
53
53
 
54
54
  @sequencer = sequencer
55
55
  @output = output
56
56
  @channel = channel
57
57
  @name = name
58
- @do_log = log
58
+ @do_log = do_log
59
59
 
60
60
  @tick_duration = Rational(1, @sequencer.ticks_per_bar)
61
61
 
@@ -64,7 +64,7 @@ module Musa
64
64
  @active_pitches = []
65
65
  fill_active_pitches @active_pitches
66
66
 
67
- log 'Warning: voice without output' unless @output
67
+ @sequencer.logger.warn 'voice without output' unless @output
68
68
 
69
69
  self
70
70
  end
@@ -118,7 +118,7 @@ module Musa
118
118
  end
119
119
 
120
120
  def log(msg)
121
- @sequencer.log "voice #{name || @channel}: #{msg}" if @do_log
121
+ @sequencer.logger.info('MIDIVoice') { "voice #{name || @channel}: #{msg}" } if @do_log
122
122
  end
123
123
 
124
124
  def to_s
@@ -169,6 +169,7 @@ module Musa
169
169
  private_constant :ControllersControl
170
170
 
171
171
  class NoteControl
172
+ attr_reader :voice, :pitch, :velocity, :velocity_off, :duration
172
173
  attr_reader :start_position, :end_position
173
174
 
174
175
  def initialize(voice, pitch:, velocity: nil, duration: nil, velocity_off: nil)
@@ -303,7 +303,7 @@ module Musa
303
303
 
304
304
  def [](grade_or_symbol)
305
305
 
306
- raise ArgumentError, "grade_or_symbol '#{grade_or_symbol}' should be a Numeric, String or Symbol" unless grade_or_symbol.is_a?(Symbol) || grade_or_symbol.is_a?(String) || grade_or_symbol.is_a?(Integer)
306
+ raise ArgumentError, "grade_or_symbol '#{grade_or_symbol}' should be a Integer, String or Symbol" unless grade_or_symbol.is_a?(Symbol) || grade_or_symbol.is_a?(String) || grade_or_symbol.is_a?(Integer)
307
307
 
308
308
  wide_grade, sharps = grade_of(grade_or_symbol)
309
309
 
@@ -15,7 +15,7 @@ module Musa
15
15
  include Musa::Neumas
16
16
 
17
17
  def value
18
- _SE(captures(:expression).collect(&:value), extends: Neuma::Serie)
18
+ S(*captures(:expression).collect(&:value)).extend(Neuma::Serie)
19
19
  end
20
20
  end
21
21
 
@@ -21,7 +21,7 @@ module Musa
21
21
  def convert_to_neumas(e)
22
22
  case e
23
23
  when Musa::Neumas::Neuma::Serie then e
24
- when Musa::Neumas::Neuma::Parallel then _SE([e], extends: Musa::Neumas::Neuma::Serie)
24
+ when Musa::Neumas::Neuma::Parallel then S(e).extend(Musa::Neumas::Neuma::Serie)
25
25
  when String then e.to_neumas
26
26
  else
27
27
  raise ArgumentError, "Don't know how to convert to neumas #{e}"
@@ -262,11 +262,11 @@ module Musa
262
262
 
263
263
  when Musa::Series::Serie
264
264
  { current_operation: :play,
265
- current_parameter: element.restart }
265
+ current_parameter: element.instance.restart }
266
266
 
267
267
  when Parallel
268
268
  { current_operation: :parallel_play,
269
- current_parameter: element.tap { |e| e.each(&:restart) } }
269
+ current_parameter: element.instance.tap { |e| e.each(&:restart) } }
270
270
 
271
271
  when Array
272
272
  { current_operation: :no_eval_play,
@@ -66,9 +66,10 @@ module Musa; module Sequencer
66
66
  end
67
67
  end
68
68
 
69
- _numeric_at start_position + _quantize_position(time, warn: false), control do
69
+ _numeric_at _quantize_position(start_position + time, warn: true), control do
70
70
  binder.call(values,
71
71
  **extra_attributes,
72
+ time: start_position + time,
72
73
  started_ago: started_ago,
73
74
  control: control)
74
75
 
@@ -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]
@@ -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
@@ -48,8 +50,8 @@ module Musa
48
50
 
49
51
  if warn
50
52
  @logger.warn('BaseSequencer') { "_check_position: rounding "\
51
- "position #{original_position} (#{original_position.to_f.round(5)}) "\
52
- "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)})" }
53
55
  end
54
56
  end
55
57
 
@@ -17,11 +17,11 @@ module Musa
17
17
  :position=,
18
18
  :event_handler
19
19
 
20
- def_delegators :@context, :position, :quantize_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
@@ -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_as} 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).tap(&:restart)
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 accommodate 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