musa-dsl 0.23.5 → 0.23.10

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 19683437b5ef89739c0d1283c86b18c547a24dd058ca5013abdea4f9c6335f5c
4
- data.tar.gz: 99fea2b0076baf8976050bd9467f4ecafb87a44bad1b37933e741116f1f5ec96
3
+ metadata.gz: 03b06753c72ecbea6d6b7b056996afa6defaa57e74edd389272728822c537e52
4
+ data.tar.gz: 6580590252818be5df7a5f42094a026897852e874ece2ce77e657a499255b2d1
5
5
  SHA512:
6
- metadata.gz: 26765814873920f392a76fdef1f8f7fc6ce3baca086d47ba443fb74246768943dbe074ebc35b71d946aab7136fd6a433fe03ad897bcff8a16e7045a1fd0c5e7f
7
- data.tar.gz: 57a1761af4bb50cb40c75680e89716e8f21b8f5a4ea345b42bdb3e2065f58a315fac8b579227741b601c25f2e2e8a617d7fef2cd799366f7df4b749c9a532ec9
6
+ metadata.gz: 52a8bb01f12163cac1598946db6a60b10cb460894eac06952c82fb7b9eb32a76c6c05d1ff6b1c2133cd024253f3be5e100eec06c67afc6e0314d3bbbf2332bc2
7
+ data.tar.gz: a7eb355bb4d9e13523f4769d4f204f150d0eb59fb2adaf0ddc989750b42e3958f1422074d11d798df99d560990a5e005d748ad06d99205273af0bdf3cf12e5e2
data/Gemfile CHANGED
@@ -1,5 +1,7 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
+ ruby '2.7.3'
4
+
3
5
  gem 'logger', '~> 1.4', '>= 1.4.3'
4
6
 
5
7
  group :neuma do
@@ -9,7 +9,6 @@ module Musa
9
9
  include Musa::Extension::SmartProcBinder
10
10
  include Musa::Series::Serie.base
11
11
 
12
-
13
12
  def initialize(transitions:, start:, finish: nil, random: nil)
14
13
  @transitions = transitions.clone.freeze
15
14
 
@@ -21,6 +20,7 @@ module Musa
21
20
 
22
21
  @procedure_binders = {}
23
22
 
23
+ mark_as_prototype!
24
24
  init
25
25
  end
26
26
 
@@ -1,4 +1,4 @@
1
- module Musa; module Sequencer
1
+ module Musa::Sequencer
2
2
  class BaseSequencer
3
3
  private def _every(interval, control, block_procedure_binder: nil, &block)
4
4
  block ||= proc {}
@@ -84,4 +84,4 @@ module Musa; module Sequencer
84
84
 
85
85
  private_constant :EveryControl
86
86
  end
87
- end; end
87
+ end
@@ -3,7 +3,7 @@ using Musa::Extension::Arrayfy
3
3
 
4
4
  using Musa::Extension::InspectNice
5
5
 
6
- module Musa; module Sequencer
6
+ module Musa::Sequencer
7
7
  class BaseSequencer
8
8
  private def _move(every: nil,
9
9
  from:, to: nil,
@@ -436,4 +436,4 @@ module Musa; module Sequencer
436
436
 
437
437
  private_constant :MoveControl
438
438
  end
439
- end; end
439
+ end
@@ -3,11 +3,9 @@ using Musa::Extension::Arrayfy
3
3
 
4
4
  using Musa::Extension::InspectNice
5
5
 
6
- module Musa; module Sequencer
6
+ module Musa::Sequencer
7
7
  class BaseSequencer
8
- private def _play_timed(timed_serie,
9
- control,
10
- &block)
8
+ private def _play_timed(timed_serie, control, &block)
11
9
 
12
10
  if first_value_sample = timed_serie.peek_next_value
13
11
  debug "_play_timed: first_value_sample #{first_value_sample}"
@@ -40,45 +38,52 @@ module Musa; module Sequencer
40
38
 
41
39
  source_next_value = timed_serie.next_value
42
40
 
43
- affected_components = component_ids.select { |_| !source_next_value[:value][_].nil? } if source_next_value
41
+ if source_next_value
42
+ affected_components = component_ids.select { |_| !source_next_value[:value][_].nil? }
44
43
 
45
- if affected_components && affected_components.any?
46
- time = source_next_value[:time]
44
+ if affected_components&.any?
45
+ time = source_next_value[:time]
47
46
 
48
- values = hash_mode ? {} : []
49
- extra_attributes = extra_attribute_names.collect { |_| [_, hash_mode ? {} : []] }.to_h
50
- started_ago = hash_mode ? {} : []
47
+ values = hash_mode ? {} : []
48
+ extra_attributes = extra_attribute_names.collect { |_| [_, hash_mode ? {} : []] }.to_h
49
+ started_ago = hash_mode ? {} : []
51
50
 
52
- affected_components.each do |component|
53
- values[component] = source_next_value[:value][component]
51
+ affected_components.each do |component|
52
+ values[component] = source_next_value[:value][component]
54
53
 
55
- extra_attribute_names.each do |attribute_name|
56
- extra_attributes[attribute_name][component] = source_next_value[attribute_name][component]
54
+ extra_attribute_names.each do |attribute_name|
55
+ extra_attributes[attribute_name][component] = source_next_value[attribute_name][component]
56
+ end
57
+
58
+ last_positions[component] = _quantize_position(time, warn: false)
57
59
  end
58
60
 
59
- last_positions[component] = _quantize_position(time, warn: false)
60
- end
61
+ component_ids.each do |component|
62
+ if last_positions[component] && last_positions[component] != time
63
+ sa = _quantize_position(time, warn: false) - last_positions[component]
64
+ started_ago[component] = (sa == 0) ? nil : sa
65
+ end
66
+ end
61
67
 
62
- component_ids.each do |component|
63
- if last_positions[component] && last_positions[component] != time
64
- sa = _quantize_position(time, warn: false) - last_positions[component]
65
- started_ago[component] = (sa == 0) ? nil : sa
68
+ _numeric_at _quantize_position(start_position + time, warn: true), control do
69
+ binder.call(values,
70
+ **extra_attributes,
71
+ time: start_position + time,
72
+ started_ago: started_ago,
73
+ control: control)
74
+
75
+ _play_timed_step(hash_mode,
76
+ component_ids, extra_attribute_names,
77
+ timed_serie,
78
+ start_position,
79
+ last_positions,
80
+ binder, control)
66
81
  end
67
82
  end
83
+ else
68
84
 
69
- _numeric_at _quantize_position(start_position + time, warn: true), control do
70
- binder.call(values,
71
- **extra_attributes,
72
- time: start_position + time,
73
- started_ago: started_ago,
74
- control: control)
75
-
76
- _play_timed_step(hash_mode,
77
- component_ids, extra_attribute_names,
78
- timed_serie,
79
- start_position,
80
- last_positions,
81
- binder, control)
85
+ control.do_after.each do |do_after|
86
+ _numeric_at position + do_after[:bars], control, &do_after[:block]
82
87
  end
83
88
  end
84
89
  end
@@ -107,5 +112,5 @@ module Musa; module Sequencer
107
112
 
108
113
  private_constant :PlayTimedControl
109
114
  end
110
- end; end
115
+ end
111
116
 
@@ -5,7 +5,7 @@ using Musa::Extension::Arrayfy
5
5
 
6
6
  using Musa::Extension::InspectNice
7
7
 
8
- module Musa; module Sequencer
8
+ module Musa::Sequencer
9
9
  class BaseSequencer
10
10
  private def _play(serie,
11
11
  control,
@@ -175,4 +175,4 @@ module Musa; module Sequencer
175
175
 
176
176
  private_constant :PlayControl
177
177
  end
178
- end; end
178
+ end
@@ -4,7 +4,7 @@ require_relative '../core-ext/smart-proc-binder'
4
4
  using Musa::Extension::Arrayfy
5
5
  using Musa::Extension::DeepCopy
6
6
 
7
- module Musa; module Sequencer
7
+ module Musa::Sequencer
8
8
  class BaseSequencer
9
9
  include Musa::Extension::SmartProcBinder
10
10
  include Musa::Extension::DeepCopy
@@ -214,4 +214,4 @@ module Musa; module Sequencer
214
214
 
215
215
  private_constant :EventHandler
216
216
  end
217
- end; end
217
+ end
@@ -12,24 +12,36 @@ module Musa
12
12
 
13
13
  module Serie
14
14
  def self.base
15
- SerieImplementation
15
+ Module.new do
16
+ include SerieImplementation
17
+
18
+ def has_source; false; end
19
+ private def mandatory_source; false; end
20
+
21
+ def has_sources; false; end
22
+ private def mandatory_sources; false; end
23
+ end
16
24
  end
17
25
 
18
26
  def self.with(source: false,
19
27
  source_as: nil,
20
28
  private_source: nil,
29
+ mandatory_source: nil,
21
30
  sources: false,
22
31
  sources_as: nil,
23
32
  private_sources: nil,
33
+ mandatory_sources: nil,
24
34
  smart_block: false,
25
35
  block: false,
26
36
  block_as: nil)
27
37
 
28
38
  source_as ||= :source
29
39
  source_setter = (source_as.to_s + '=').to_sym
40
+ _mandatory_source = source if mandatory_source.nil?
30
41
 
31
42
  sources_as ||= :sources
32
43
  sources_setter = (sources_as.to_s + '=').to_sym
44
+ _mandatory_sources = sources if mandatory_sources.nil?
33
45
 
34
46
  block_as ||= :proc
35
47
  block_setter = (block_as.to_s + '=').to_sym
@@ -38,15 +50,19 @@ module Musa
38
50
  include SerieImplementation
39
51
 
40
52
  if source
53
+ private def has_source; true; end
54
+ define_method(:mandatory_source) { _mandatory_source }
55
+ private :mandatory_source
56
+
41
57
  define_method source_as do
42
58
  @source
43
59
  end
44
60
 
45
61
  define_method source_setter do |serie|
46
- raise ArgumentError, "New #{source_as} should be a #{@get}" unless @source.nil? || @source.prototype? == serie&.prototype?
62
+ unless @source.nil? || @source.undefined? || serie.state == @source.state
63
+ raise ArgumentError, "New serie for #{source_as} should be a #{@state} instead of a #{serie.state}"
64
+ end
47
65
 
48
- serie ||= Musa::Series::Constructors.NIL
49
- @get = serie&.instance? ? :instance : :prototype
50
66
  @source = serie
51
67
  mark_regarding! @source
52
68
  end
@@ -55,45 +71,49 @@ module Musa
55
71
  private source_as
56
72
  private source_setter
57
73
  end
74
+ else
75
+ private def has_source; false; end
76
+ private def mandatory_source; false; end
58
77
  end
59
78
 
60
79
  if sources
61
- define_method sources_as do ||
80
+ private def has_sources; true; end
81
+ define_method(:mandatory_sources) { _mandatory_sources }
82
+ private :mandatory_source
83
+
84
+ define_method sources_as do
62
85
  @sources
63
86
  end
64
87
 
65
88
  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"
89
+ unless series.is_a?(Hash) || series.is_a?(Array)
90
+ raise ArgumentError, "New series for #{sources_as} should be a Hash or an Array instead of a #{series.class.name}"
75
91
  end
76
92
 
77
- mark_as! getter
93
+ @sources = series
94
+ try_to_resolve_undefined_state_if_needed
78
95
  end
79
96
 
80
97
  if private_sources
81
98
  private sources_as
82
99
  private sources_setter
83
100
  end
101
+ else
102
+ private def has_sources; false; end
103
+ private def mandatory_sources; false; end
84
104
  end
85
105
 
86
106
  if smart_block
87
107
  define_method block_as do |&block|
88
108
  if block
89
- @block = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
109
+ @block = Extension::SmartProcBinder::SmartProcBinder.new(block)
90
110
  else
91
111
  @block.proc
92
112
  end
93
113
  end
94
114
 
95
115
  define_method block_setter do |block|
96
- @block = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
116
+ @block = Extension::SmartProcBinder::SmartProcBinder.new(block)
97
117
  end
98
118
 
99
119
  elsif block
@@ -113,35 +133,53 @@ module Musa
113
133
  end
114
134
 
115
135
  module Prototyping
136
+ def state
137
+ try_to_resolve_undefined_state_if_needed
138
+ @state || :undefined
139
+ end
140
+
116
141
  def prototype?
117
- @is_instance ? false : true
142
+ try_to_resolve_undefined_state_if_needed
143
+ @state&.==(:prototype)
118
144
  end
119
145
 
120
146
  def instance?
121
- @is_instance ? true : false
147
+ try_to_resolve_undefined_state_if_needed
148
+ @state&.==(:instance)
149
+ end
150
+
151
+ def undefined?
152
+ try_to_resolve_undefined_state_if_needed
153
+ @state.nil? || @state == :undefined
154
+ end
155
+
156
+ def defined?
157
+ !undefined?
122
158
  end
123
159
 
124
160
  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
161
+ try_to_resolve_undefined_state_if_needed
132
162
 
163
+ if prototype?
164
+ self
165
+ elsif instance?
166
+ # if the series has been directly created as an instance (i.e., because is an operation over an instance)
167
+ # the prototype doesn't exist.
168
+ #
133
169
  @instance_of
134
170
  else
135
- self
171
+ raise PrototypingError, 'Can\'t get the prototype of an undefined serie'
136
172
  end
137
173
  end
138
174
 
139
175
  alias_method :p, :prototype
140
176
 
141
177
  def instance
142
- if @is_instance
178
+ try_to_resolve_undefined_state_if_needed
179
+
180
+ if instance?
143
181
  self
144
- else
182
+ elsif prototype?
145
183
  new_instance = clone
146
184
 
147
185
  new_instance._instance!
@@ -149,6 +187,8 @@ module Musa
149
187
  new_instance.init if new_instance.respond_to?(:init)
150
188
 
151
189
  new_instance
190
+ else
191
+ raise PrototypingError, 'Can\'t get an instance of an undefined serie'
152
192
  end
153
193
  end
154
194
 
@@ -163,61 +203,128 @@ module Musa
163
203
  protected def _prototype!
164
204
  @source = @source.prototype if @source
165
205
 
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
206
+ case @sources
207
+ when Array
208
+ @sources = @sources.collect(&:prototype)
209
+ when Hash
210
+ @sources = @sources.transform_values(&:prototype)
172
211
  end
173
212
  end
174
213
 
175
214
  protected def _instance!
176
215
  @source = @source.instance if @source
177
216
 
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
217
+ case @sources
218
+ when Array
219
+ @sources = @sources.collect(&:instance)
220
+ when Hash
221
+ @sources = @sources.transform_values(&:instance)
184
222
  end
185
223
  end
186
224
 
187
- protected def mark_as!(getter)
188
- case getter
225
+ protected def mark_as!(state)
226
+ case state
227
+ when nil, :undefined
228
+ mark_as_undefined!
189
229
  when :prototype
190
230
  mark_as_prototype!
191
231
  when :instance
192
232
  mark_as_instance!
193
233
  else
194
- raise ArgumentError, "Only can be marked as :prototype or :instance"
234
+ raise ArgumentError, "Unexpected state #{state}. Only accepted nil, :undefined, :prototype or :instance."
195
235
  end
196
236
  end
197
237
 
198
238
  protected def mark_regarding!(source)
199
- if source.prototype?
239
+ if source.nil? || source.undefined?
240
+ mark_as_undefined!
241
+ elsif source.prototype?
200
242
  mark_as_prototype!
201
- else
243
+ elsif source.instance?
202
244
  mark_as_instance!
203
245
  end
204
246
  end
205
247
 
248
+ protected def mark_as_undefined!
249
+ @state = :undefined
250
+ self
251
+ end
252
+
206
253
  protected def mark_as_prototype!
207
- @get = :prototype
254
+ notify = @state != :prototype
208
255
 
209
- @is_instance = nil
256
+ @state = :prototype
257
+
258
+ _sources_resolved if notify
210
259
  self
211
260
  end
212
261
 
213
262
  protected def mark_as_instance!(prototype = nil)
214
- @get = :instance
263
+ notify = @state != :instance
215
264
 
265
+ @state = :instance
216
266
  @instance_of = prototype
217
- @is_instance = true
267
+
268
+ _sources_resolved if notify
218
269
  self
219
270
  end
220
271
 
272
+ protected def _sources_resolved; end
273
+
274
+ private def try_to_resolve_undefined_state_if_needed
275
+
276
+ return unless @state.nil? || @state == :undefined
277
+
278
+ states = []
279
+
280
+ if has_source
281
+ if mandatory_source
282
+ states << @source&.state || :undefined
283
+ elsif @source
284
+ states << @source.state
285
+ end
286
+ end
287
+
288
+ if has_sources
289
+ sources = case @sources
290
+ when Array
291
+ @sources
292
+ when Hash
293
+ @sources.values
294
+ when nil
295
+ []
296
+ end
297
+
298
+ undefined_sources =
299
+ sources.empty? ||
300
+ sources.any?(&:undefined?) ||
301
+ sources.any?(&:instance?) && sources.any?(&:prototype?)
302
+
303
+ instance_sources = sources.all?(&:instance?) unless undefined_sources
304
+
305
+ sources_state = if undefined_sources
306
+ :undefined
307
+ elsif instance_sources
308
+ :instance
309
+ else
310
+ :prototype
311
+ end
312
+
313
+ if mandatory_sources
314
+ states << sources_state
315
+ elsif !(@sources.nil? || @sources.empty?)
316
+ states << sources_state
317
+ end
318
+ end
319
+
320
+ # in case of having source and sources, if both states are equal the final state is that one, else the final state is undefined
321
+ #
322
+ new_state = states.first if states.first == states.last
323
+ new_state ||= :undefined
324
+
325
+ mark_as!(new_state)
326
+ end
327
+
221
328
  class PrototypingError < RuntimeError
222
329
  def initialize(message = nil)
223
330
  message ||= 'This serie is a prototype serie: cannot be consumed. To consume the serie use an instance serie via .instance method'
@@ -245,7 +352,7 @@ module Musa
245
352
  private def _init; end
246
353
 
247
354
  def restart(...)
248
- raise PrototypingError unless @is_instance
355
+ check_state_permissions
249
356
  init
250
357
  _restart(...)
251
358
 
@@ -255,7 +362,7 @@ module Musa
255
362
  private def _restart; end
256
363
 
257
364
  def next_value
258
- raise PrototypingError unless @is_instance
365
+ check_state_permissions
259
366
 
260
367
  unless @_have_current_value && @_current_value.nil?
261
368
  if @_have_peeked_next_value
@@ -274,7 +381,7 @@ module Musa
274
381
  alias_method :v, :next_value
275
382
 
276
383
  def peek_next_value
277
- raise PrototypingError unless @is_instance
384
+ check_state_permissions
278
385
 
279
386
  if !@_have_peeked_next_value
280
387
  @_have_peeked_next_value = true
@@ -285,16 +392,20 @@ module Musa
285
392
  end
286
393
 
287
394
  def current_value
288
- raise PrototypingError unless @is_instance
395
+ check_state_permissions
289
396
 
290
397
  @_current_value
291
398
  end
292
399
 
293
400
  def infinite?
401
+ check_state_permissions(allows_prototype: true)
294
402
  @source&.infinite? || false
295
403
  end
296
404
 
297
405
  def to_a(duplicate: nil, recursive: nil, restart: nil, dr: nil)
406
+ check_state_permissions(allows_prototype: true)
407
+ raise 'Cannot convert to array an infinite serie' if infinite?
408
+
298
409
  recursive ||= false
299
410
 
300
411
  dr = instance? if dr.nil?
@@ -302,8 +413,6 @@ module Musa
302
413
  duplicate = dr if duplicate.nil?
303
414
  restart = dr if restart.nil?
304
415
 
305
- raise 'Cannot convert to array an infinite serie' if infinite?
306
-
307
416
  array = []
308
417
 
309
418
  serie = instance
@@ -324,12 +433,37 @@ module Musa
324
433
 
325
434
  alias_method :a, :to_a
326
435
 
436
+ private def process_for_to_a(value)
437
+ case value
438
+ when Serie
439
+ value.to_a(recursive: true, restart: false, duplicate: false)
440
+ when Array
441
+ a = value.clone
442
+ a.collect! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
443
+ when Hash
444
+ h = value.clone
445
+ h.transform_values! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
446
+ else
447
+ value
448
+ end
449
+ end
450
+
327
451
  def to_node(**attributes)
328
452
  Nodificator.to_node(self, **attributes)
329
453
  end
330
454
 
331
455
  alias_method :node, :to_node
332
456
 
457
+ private def check_state_permissions(allows_prototype: nil)
458
+ try_to_resolve_undefined_state_if_needed
459
+
460
+ raise PrototypingError if !allows_prototype && prototype?
461
+
462
+ unless instance? || prototype?
463
+ raise PrototypingError, 'This serie is in undefined state: cannot be consumed. To consume the serie be sure the serie\'s sources are all in a defined state.'
464
+ end
465
+ end
466
+
333
467
  class Nodificator
334
468
  extend Musa::GenerativeGrammar
335
469
 
@@ -339,21 +473,6 @@ module Musa
339
473
  end
340
474
 
341
475
  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
356
- end
357
476
  end
358
477
 
359
478
  private_constant :SerieImplementation
@@ -30,7 +30,7 @@ module Musa
30
30
 
31
31
  def buffer
32
32
  @buffer ||= Buffer.new(@history)
33
- @buffer.send(@get).tap { |_| @buffers << _ }
33
+ @buffer.send(state).tap { |_| @buffers << _ }
34
34
  end
35
35
 
36
36
  private def clear_old_history
@@ -51,6 +51,7 @@ module Musa
51
51
  def initialize(history)
52
52
  @history = history
53
53
  @last_nil_index = -1
54
+ mark_as_prototype!
54
55
  init
55
56
  end
56
57
 
@@ -102,19 +103,31 @@ module Musa
102
103
  @nils = [0]
103
104
  @buffers = Set[]
104
105
 
105
- @singleton = nil
106
106
  @buffer = nil
107
107
 
108
108
  init
109
109
  end
110
110
 
111
- def instance
112
- @singleton ||= super
111
+ def buffer
112
+ Buffer.new(self)
113
113
  end
114
114
 
115
- def buffer
116
- @buffer ||= Buffer.new(self)
117
- @buffer
115
+ def _sources_resolved
116
+ (prototype || self).singleton = self if instance?
117
+ end
118
+
119
+ protected def singleton=(the_instance)
120
+ @singleton ||= the_instance
121
+ end
122
+
123
+ def singleton
124
+ if instance?
125
+ prototype.nil? ? @singleton : prototype.singleton
126
+ elsif prototype?
127
+ @singleton
128
+ else
129
+ raise "ES UNDEFINED!"
130
+ end
118
131
  end
119
132
 
120
133
  private def _restart(buffer)
@@ -163,9 +176,7 @@ module Musa
163
176
  private def clear_old_history
164
177
  min_last_nil_index = @buffers.collect(&:last_nil_index).min
165
178
 
166
- if min_last_nil_index && min_last_nil_index >=0
167
-
168
- pre_nils = @nils.clone
179
+ if min_last_nil_index && min_last_nil_index >= 0
169
180
  @history = @history.drop(min_last_nil_index)
170
181
 
171
182
  @nils.collect! { |_| _ - min_last_nil_index }
@@ -182,9 +193,6 @@ module Musa
182
193
 
183
194
  def initialize(base)
184
195
  self.source = base
185
-
186
- mark_as_prototype! # necesario para que se creen instancias diferentes cada vez que se ejecute BufferSerie.buffer()
187
-
188
196
  init
189
197
  end
190
198
 
@@ -198,13 +206,18 @@ module Musa
198
206
  @index -= offset
199
207
  end
200
208
 
201
- private def _init
202
- @source._register(self) if instance?
209
+ # private def _init
210
+ # @source.prototype.singleton._register(self) if instance?
211
+ # @index = @last_nil_index
212
+ # end
213
+ #
214
+ private def _sources_resolved
215
+ @source.singleton._register(self) if instance?
203
216
  @index = @last_nil_index
204
217
  end
205
218
 
206
219
  private def _restart
207
- @source.restart(self)
220
+ @source.singleton.restart(self)
208
221
  @needs_restart = false
209
222
  end
210
223
 
@@ -216,7 +229,7 @@ module Musa
216
229
  @index += 1
217
230
  value = @history[@index]
218
231
  else
219
- value = _next_value unless @source.next_value.nil?
232
+ value = _next_value unless @source.singleton.next_value.nil?
220
233
  end
221
234
 
222
235
  if value.nil?
@@ -5,26 +5,30 @@ module Musa
5
5
  end
6
6
 
7
7
  class Splitter
8
+ include Series::Serie.with(source: true)
8
9
  include Enumerable
9
- include Series::Serie::Prototyping
10
+
11
+ private def has_source; true; end
12
+ private def has_sources; false; end
10
13
 
11
14
  def initialize(source)
12
- @source = source
15
+ self.source = source
13
16
  @series = {}
17
+
18
+ init
14
19
  end
15
20
 
16
21
  def source=(serie)
17
- @source = serie
22
+ super
18
23
  @proxy.source = @source if @proxy
19
24
  end
20
25
 
21
- protected def _instance!
22
- super
26
+ def _sources_resolved
23
27
  @proxy = SplitterProxy.new(@source)
24
28
  end
25
29
 
26
30
  def [](key_or_index)
27
- raise "Can't get a component because Splitter is a prototype. To get a component you need a Splitter instance." unless @is_instance
31
+ raise "Can't get a component because Splitter is a prototype. To get a component you need a Splitter instance." unless instance?
28
32
 
29
33
  if @series.key?(key_or_index)
30
34
  @series[key_or_index]
@@ -34,7 +38,7 @@ module Musa
34
38
  end
35
39
 
36
40
  def each
37
- raise "Can't iterate because Splitter is a prototype. To iterate you need a Splitter instance." unless @is_instance
41
+ raise "Can't iterate because Splitter is in state '#{state}'. To iterate you need a Splitter in state 'instance'." unless instance?
38
42
 
39
43
  if block_given?
40
44
  if @proxy.hash_mode?
@@ -162,6 +166,8 @@ module Musa
162
166
  end
163
167
  end
164
168
 
169
+ private_constant :SplitterProxy
170
+
165
171
  class Split
166
172
  include Series::Serie.base
167
173
 
@@ -10,6 +10,10 @@ using Musa::Extension::ExplodeRanges
10
10
 
11
11
  module Musa
12
12
  module Series::Constructors
13
+ def UNDEFINED
14
+ UndefinedSerie.new
15
+ end
16
+
13
17
  def NIL
14
18
  NilSerie.new
15
19
  end
@@ -44,10 +48,14 @@ module Musa
44
48
  ForLoop.new from, to, step
45
49
  end
46
50
 
47
- def RND(*values, from: nil, to: nil, step: nil, random: nil)
51
+ def RND(*_values, values: nil, from: nil, to: nil, step: nil, random: nil)
52
+ raise ArgumentError, "Can't use both direct values #{_values} and values named parameter #{values} at the same time." if values && !_values.empty?
53
+
48
54
  random = Random.new random if random.is_a?(Integer)
49
55
  random ||= Random.new
50
56
 
57
+ values ||= _values
58
+
51
59
  if !values.empty? && from.nil? && to.nil? && step.nil?
52
60
  RandomValuesFromArray.new values.explode_ranges, random
53
61
  elsif values.empty? && !to.nil?
@@ -63,10 +71,14 @@ module Musa
63
71
  Sequence.new(series)
64
72
  end
65
73
 
66
- def RND1(*values, from: nil, to: nil, step: nil, random: nil)
74
+ def RND1(*_values, values: nil, from: nil, to: nil, step: nil, random: nil)
75
+ raise ArgumentError, "Can't use both direct values #{_values} and values named parameter #{values} at the same time." if values && !_values.empty?
76
+
67
77
  random = Random.new random if random.is_a?(Integer)
68
78
  random ||= Random.new
69
79
 
80
+ values ||= _values
81
+
70
82
  if !values.empty? && from.nil? && to.nil? && step.nil?
71
83
  RandomValueFromArray.new values.explode_ranges, random
72
84
  elsif values.empty? && !to.nil?
@@ -99,8 +111,22 @@ module Musa
99
111
  ### Implementation
100
112
  ###
101
113
 
114
+ class UndefinedSerie
115
+ include Series::Serie.base
116
+
117
+ def initialize
118
+ mark_as_undefined!
119
+ end
120
+ end
121
+
122
+ private_constant :UndefinedSerie
123
+
102
124
  class NilSerie
103
- include Musa::Series::Serie.base
125
+ include Series::Serie.base
126
+
127
+ def initialize
128
+ mark_as_prototype!
129
+ end
104
130
 
105
131
  def _next_value; nil; end
106
132
  end
@@ -108,7 +134,7 @@ module Musa
108
134
  private_constant :NilSerie
109
135
 
110
136
  class FromArray
111
- include Musa::Series::Serie.base
137
+ include Series::Serie.base
112
138
 
113
139
  def initialize(values = nil, extends = nil)
114
140
  @values = values
@@ -143,15 +169,14 @@ module Musa
143
169
  # private_constant :FromArray
144
170
 
145
171
  class Sequence
146
- include Musa::Series::Serie.with(sources: true)
172
+ include Series::Serie.with(sources: true)
147
173
 
148
174
  def initialize(series)
149
175
  self.sources = series
150
-
151
176
  init
152
177
  end
153
178
 
154
- attr_accessor :sources
179
+ attr_reader :sources
155
180
 
156
181
  private def _init
157
182
  @index = 0
@@ -189,9 +214,9 @@ module Musa
189
214
  private_constant :Sequence
190
215
 
191
216
  class FromEvalBlockWithParameters
192
- include Musa::Series::Serie.with(smart_block: true)
217
+ include Series::Serie.with(smart_block: true)
193
218
 
194
- using Musa::Extension::DeepCopy
219
+ using Extension::DeepCopy
195
220
 
196
221
  def initialize(*parameters, **key_parameters, &block)
197
222
  raise ArgumentError, 'Yield block is undefined' unless block
@@ -245,7 +270,7 @@ module Musa
245
270
  private_constant :FromEvalBlockWithParameters
246
271
 
247
272
  class ForLoop
248
- include Musa::Series::Serie.base
273
+ include Series::Serie.base
249
274
 
250
275
  def initialize(from, to, step)
251
276
  @from = from
@@ -303,7 +328,7 @@ module Musa
303
328
  private_constant :ForLoop
304
329
 
305
330
  class RandomValueFromArray
306
- include Musa::Series::Serie.base
331
+ include Series::Serie.base
307
332
 
308
333
  def initialize(values, random)
309
334
  @values = values
@@ -332,7 +357,7 @@ module Musa
332
357
  private_constant :RandomValueFromArray
333
358
 
334
359
  class RandomNumberFromRange
335
- include Musa::Series::Serie.base
360
+ include Series::Serie.base
336
361
 
337
362
  def initialize(from, to, step, random)
338
363
  @from = from
@@ -392,7 +417,7 @@ module Musa
392
417
  private_constant :RandomNumberFromRange
393
418
 
394
419
  class RandomValuesFromArray
395
- include Musa::Series::Serie.base
420
+ include Series::Serie.base
396
421
 
397
422
  def initialize(values, random)
398
423
  @values = values.clone.freeze
@@ -424,7 +449,7 @@ module Musa
424
449
  private_constant :RandomValuesFromArray
425
450
 
426
451
  class RandomNumbersFromRange
427
- include Musa::Series::Serie.base
452
+ include Series::Serie.base
428
453
 
429
454
  def initialize(from, to, step, random)
430
455
  @from = from
@@ -486,7 +511,7 @@ module Musa
486
511
  private_constant :RandomNumbersFromRange
487
512
 
488
513
  class FromHashOfSeries
489
- include Musa::Series::Serie.with(sources: true)
514
+ include Series::Serie.with(sources: true)
490
515
 
491
516
  def initialize(hash_of_series, cycle_all_series)
492
517
  self.sources = hash_of_series
@@ -545,7 +570,7 @@ module Musa
545
570
  private_constant :FromHashOfSeries
546
571
 
547
572
  class FromArrayOfSeries
548
- include Musa::Series::Serie.with(sources: true)
573
+ include Series::Serie.with(sources: true)
549
574
 
550
575
  def initialize(series_array, cycle_all_series)
551
576
  self.sources = series_array
@@ -604,7 +629,7 @@ module Musa
604
629
  private_constant :FromArrayOfSeries
605
630
 
606
631
  class SinFunction
607
- include Musa::Series::Serie.base
632
+ include Series::Serie.base
608
633
 
609
634
  def initialize(start, steps, amplitude, center)
610
635
  @start = start.to_f
@@ -679,7 +704,7 @@ module Musa
679
704
  private_constant :SinFunction
680
705
 
681
706
  class Fibonacci
682
- include Musa::Series::Serie.base
707
+ include Series::Serie.base
683
708
 
684
709
  def initialize
685
710
  mark_as_prototype!
@@ -707,7 +732,7 @@ module Musa
707
732
  private_constant :Fibonacci
708
733
 
709
734
  class HarmonicNotes
710
- include Musa::Series::Serie.base
735
+ include Series::Serie.base
711
736
 
712
737
  def initialize(error, extended)
713
738
  @error = error
@@ -125,7 +125,9 @@ module Musa
125
125
  ###
126
126
 
127
127
  class ProcessWith
128
- include Serie.with(source: true, sources: true, sources_as: :with_sources, smart_block: true)
128
+ include Serie.with(source: true,
129
+ sources: true, sources_as: :with_sources, mandatory_sources: false,
130
+ smart_block: true)
129
131
 
130
132
  def initialize(serie, with_series = nil, on_restart = nil, &block)
131
133
  self.source = serie
@@ -800,12 +802,6 @@ module Musa
800
802
  init
801
803
  end
802
804
 
803
- def source=(serie)
804
- raise ArgumentError, "A serie to reverse can't be infinite" if serie.infinite?
805
- super
806
- init
807
- end
808
-
809
805
  private def _init
810
806
  @reversed = nil
811
807
  end
@@ -815,6 +811,8 @@ module Musa
815
811
  end
816
812
 
817
813
  private def _next_value
814
+ raise ArgumentError, "A serie to reverse can't be infinite" if @source.infinite?
815
+
818
816
  @reversed ||= Constructors.S(*next_values_array_of(@source).reverse).instance
819
817
  @reversed.next_value
820
818
  end
@@ -22,10 +22,6 @@ module Musa
22
22
  @source.next_value if @source
23
23
  end
24
24
 
25
- def infinite?
26
- @source.infinite? if @source
27
- end
28
-
29
25
  private def method_missing(method_name, *args, **key_args, &block)
30
26
  if @source
31
27
  if @source.respond_to?(method_name)
@@ -6,7 +6,33 @@ module Musa
6
6
  module Series
7
7
  module Operations
8
8
  def composer(&block)
9
- Composer::Composer.new(&block).tap { |_| _.input.proxy_source = self}.output
9
+ ComposerAsOperationSerie.new(self, &block)
10
+ end
11
+
12
+ class ComposerAsOperationSerie
13
+ include Serie.with(source: true)
14
+
15
+ def initialize(serie, &block)
16
+ self.source = serie
17
+ @block = block
18
+
19
+ init
20
+ end
21
+
22
+ attr_reader :composer
23
+
24
+ private def _init
25
+ @composer = Composer::Composer.new(input: @source, &@block)
26
+ @output = @composer.output
27
+ end
28
+
29
+ private def _restart
30
+ @output.restart
31
+ end
32
+
33
+ private def _next_value
34
+ @output.next_value
35
+ end
10
36
  end
11
37
  end
12
38
 
@@ -14,9 +40,22 @@ module Musa
14
40
  class Composer
15
41
  using Musa::Extension::Arrayfy
16
42
 
17
- def initialize(inputs: [:input], outputs: [:output], auto_commit: nil, &block)
43
+ def initialize(input: nil, inputs: [:input], outputs: [:output], auto_commit: nil, &block)
18
44
  auto_commit = true if auto_commit.nil?
19
45
 
46
+ inputs = case inputs
47
+ when Array
48
+ inputs.collect { |_| [_, nil] }.to_h
49
+ when nil
50
+ {}
51
+ when Hash
52
+ inputs
53
+ else
54
+ raise ArgumentError, "inputs: expected a Hash with input names and source series { name: serie, ... } or an Array with names [name, ...] but received #{inputs}"
55
+ end
56
+
57
+ inputs[:input] = input if input
58
+
20
59
  @pipelines = {}
21
60
 
22
61
  def @pipelines.[]=(name, pipeline)
@@ -28,8 +67,9 @@ module Musa
28
67
  @inputs = {}
29
68
  @outputs = {}
30
69
 
31
- inputs&.each do |input|
32
- p = PROXY()
70
+ inputs.keys&.each do |input|
71
+ p = PROXY(inputs[input])
72
+
33
73
  @inputs[input] = @pipelines[input] = Pipeline.new(input, input: p, output: p.buffered, pipelines: @pipelines)
34
74
 
35
75
  @dsl.define_singleton_method(input) { input }
@@ -104,7 +144,8 @@ module Musa
104
144
  end
105
145
 
106
146
  def commit!
107
- first_serie_operation = @first_proc&.call(NIL())
147
+ first_serie_operation = @first_proc&.call(UNDEFINED())
148
+
108
149
  @input ||= first_serie_operation
109
150
 
110
151
  @routes.each_value do |route|
@@ -241,9 +282,18 @@ module Musa
241
282
  when Proc
242
283
  call_constructor_according_to_last_and_parameter(last.call, constructor, parameter)
243
284
 
285
+ when UndefinedSerie
286
+ case parameter
287
+ when Hash
288
+ Musa::Series::Constructors.method(constructor).call(**parameter)
289
+ when Array
290
+ Musa::Series::Constructors.method(constructor).call(*parameter)
291
+ else
292
+ raise "Unexpected parameter #{parameter} for constructor #{constructor}"
293
+ end
294
+
244
295
  when Serie
245
- # TODO: ignoring last, should make an error?
246
- Musa::Series::Constructors.method(constructor).call(*parameter)
296
+ raise "Unexpected source serie #{last} for constructor #{constructor}"
247
297
 
248
298
  when nil
249
299
  Musa::Series::Constructors.method(constructor).call(*parameter)
data/musa-dsl.gemspec CHANGED
@@ -1,7 +1,7 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'musa-dsl'
3
- s.version = '0.23.5'
4
- s.date = '2021-07-28'
3
+ s.version = '0.23.10'
4
+ s.date = '2021-08-05'
5
5
  s.summary = 'A simple Ruby DSL for making complex music'
6
6
  s.description = 'Musa-DSL: A Ruby framework and DSL for algorithmic sound and musical thinking and composition'
7
7
  s.authors = ['Javier Sánchez Yeste']
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: musa-dsl
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.23.5
4
+ version: 0.23.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - Javier Sánchez Yeste
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-07-28 00:00:00.000000000 Z
11
+ date: 2021-08-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: citrus