musa-dsl 0.23.6 → 0.23.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d4151142ca6664ad550224f1ab9af55f31ce8982ff24cd4bfdd5bcd02bd45756
4
- data.tar.gz: 9c2f01bb75266047984017e7edbd7f18ed353c34321b197af0faf7a3e385449a
3
+ metadata.gz: abb4a2e7ffcd4376fd2d54f73172d611fe65da0cf6406365c7341b65e0706d30
4
+ data.tar.gz: 84214e98aa34a365a370e7597e0a64bafb800eafd59e17a6fdd8ac840bd915de
5
5
  SHA512:
6
- metadata.gz: 5b02d2620956fd954a7435bb7b6888d7107d02b7e57722a0f5e2f84c57f38576eab3a3bc5972b058387bcf4ad92833acce44d60c2808f36690e865b2ac776d38
7
- data.tar.gz: 6a13c17fb864649fe6881e5ee3d34f2c1c48ada65b1640835310fb1658897d43a631cb63c30a186c7fa71bf3cee809ddd46627a36869a25a0a94099ea079bcb0
6
+ metadata.gz: 26936f34fc5038249db6df38ee405af52ff67ff7328d47a0f1f030768c33f61f828004b3d5581adc4857e2fbca60aba628e3c2cf14b21b48e3f455b52f587efd
7
+ data.tar.gz: 107fbc88359e3fe58b996d3156ae09b381580807bf6e0fe51fe281a37eb1b476eeeb483eacc63cb28e7c215ebd713d30dc432304d54b3b9155ef6fc304b6a33a
@@ -6,12 +6,13 @@ module Musa
6
6
  def with(*value_parameters, **key_parameters, &block)
7
7
  binder = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
8
8
 
9
- keep_block_context = binder.parameters[0][1] == :_ unless binder.parameters.empty?
10
- keep_block_context ||= false
9
+ keep_proc_context = @keep_proc_context_on_with
10
+ keep_proc_context ||= binder.parameters[0][1] == :_ unless binder.parameters.empty?
11
+ keep_proc_context ||= false
11
12
 
12
13
  effective_value_parameters, effective_key_parameters = binder._apply(value_parameters, key_parameters)
13
14
 
14
- if keep_block_context
15
+ if keep_proc_context
15
16
  binder.call(self, *effective_value_parameters, **effective_key_parameters)
16
17
  else
17
18
  if effective_value_parameters.empty? && effective_key_parameters.empty?
@@ -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,9 +1,10 @@
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 {}
5
5
 
6
- block_procedure_binder ||= SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
6
+ block_procedure_binder ||=
7
+ Musa::Extension::SmartProcBinder::SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
7
8
 
8
9
  _numeric_at position, control do
9
10
  control._start_position ||= position
@@ -84,4 +85,4 @@ module Musa; module Sequencer
84
85
 
85
86
  private_constant :EveryControl
86
87
  end
87
- end; end
88
+ end
@@ -1,9 +1,10 @@
1
- using Musa::Extension::Hashify
2
- using Musa::Extension::Arrayfy
1
+ require_relative '../core-ext/arrayfy'
2
+ require_relative '../core-ext/inspect-nice'
3
3
 
4
+ using Musa::Extension::Arrayfy
4
5
  using Musa::Extension::InspectNice
5
6
 
6
- module Musa; module Sequencer
7
+ module Musa::Sequencer
7
8
  class BaseSequencer
8
9
  private def _move(every: nil,
9
10
  from:, to: nil,
@@ -436,4 +437,4 @@ module Musa; module Sequencer
436
437
 
437
438
  private_constant :MoveControl
438
439
  end
439
- end; end
440
+ end
@@ -1,5 +1,3 @@
1
- using Musa::Extension::DeepCopy
2
-
3
1
  module Musa
4
2
  module Sequencer
5
3
  class BaseSequencer
@@ -1,13 +1,10 @@
1
- using Musa::Extension::Hashify
2
- using Musa::Extension::Arrayfy
1
+ require_relative '../core-ext/inspect-nice'
3
2
 
4
3
  using Musa::Extension::InspectNice
5
4
 
6
- module Musa; module Sequencer
5
+ module Musa::Sequencer
7
6
  class BaseSequencer
8
- private def _play_timed(timed_serie,
9
- control,
10
- &block)
7
+ private def _play_timed(timed_serie, control, &block)
11
8
 
12
9
  if first_value_sample = timed_serie.peek_next_value
13
10
  debug "_play_timed: first_value_sample #{first_value_sample}"
@@ -25,7 +22,7 @@ module Musa; module Sequencer
25
22
  last_positions = hash_mode ? {} : []
26
23
  end
27
24
 
28
- binder = SmartProcBinder.new(block)
25
+ binder = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)
29
26
 
30
27
  _play_timed_step(hash_mode, component_ids, extra_attribute_names, timed_serie,
31
28
  position, last_positions, binder, control)
@@ -40,45 +37,52 @@ module Musa; module Sequencer
40
37
 
41
38
  source_next_value = timed_serie.next_value
42
39
 
43
- affected_components = component_ids.select { |_| !source_next_value[:value][_].nil? } if source_next_value
40
+ if source_next_value
41
+ affected_components = component_ids.select { |_| !source_next_value[:value][_].nil? }
44
42
 
45
- if affected_components && affected_components.any?
46
- time = source_next_value[:time]
43
+ if affected_components&.any?
44
+ time = source_next_value[:time]
47
45
 
48
- values = hash_mode ? {} : []
49
- extra_attributes = extra_attribute_names.collect { |_| [_, hash_mode ? {} : []] }.to_h
50
- started_ago = hash_mode ? {} : []
46
+ values = hash_mode ? {} : []
47
+ extra_attributes = extra_attribute_names.collect { |_| [_, hash_mode ? {} : []] }.to_h
48
+ started_ago = hash_mode ? {} : []
51
49
 
52
- affected_components.each do |component|
53
- values[component] = source_next_value[:value][component]
50
+ affected_components.each do |component|
51
+ values[component] = source_next_value[:value][component]
54
52
 
55
- extra_attribute_names.each do |attribute_name|
56
- extra_attributes[attribute_name][component] = source_next_value[attribute_name][component]
53
+ extra_attribute_names.each do |attribute_name|
54
+ extra_attributes[attribute_name][component] = source_next_value[attribute_name][component]
55
+ end
56
+
57
+ last_positions[component] = _quantize_position(time, warn: false)
57
58
  end
58
59
 
59
- last_positions[component] = _quantize_position(time, warn: false)
60
- end
60
+ component_ids.each do |component|
61
+ if last_positions[component] && last_positions[component] != time
62
+ sa = _quantize_position(time, warn: false) - last_positions[component]
63
+ started_ago[component] = (sa == 0) ? nil : sa
64
+ end
65
+ end
61
66
 
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
67
+ _numeric_at _quantize_position(start_position + time, warn: true), control do
68
+ binder.call(values,
69
+ **extra_attributes,
70
+ time: start_position + time,
71
+ started_ago: started_ago,
72
+ control: control)
73
+
74
+ _play_timed_step(hash_mode,
75
+ component_ids, extra_attribute_names,
76
+ timed_serie,
77
+ start_position,
78
+ last_positions,
79
+ binder, control)
66
80
  end
67
81
  end
82
+ else
68
83
 
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)
84
+ control.do_after.each do |do_after|
85
+ _numeric_at position + do_after[:bars], control, &do_after[:block]
82
86
  end
83
87
  end
84
88
  end
@@ -107,5 +111,5 @@ module Musa; module Sequencer
107
111
 
108
112
  private_constant :PlayTimedControl
109
113
  end
110
- end; end
114
+ end
111
115
 
@@ -1,11 +1,9 @@
1
+ require_relative '../core-ext/inspect-nice'
1
2
  require_relative 'base-sequencer-implementation-play-helper'
2
3
 
3
- using Musa::Extension::Hashify
4
- using Musa::Extension::Arrayfy
5
-
6
4
  using Musa::Extension::InspectNice
7
5
 
8
- module Musa; module Sequencer
6
+ module Musa::Sequencer
9
7
  class BaseSequencer
10
8
  private def _play(serie,
11
9
  control,
@@ -175,4 +173,4 @@ module Musa; module Sequencer
175
173
 
176
174
  private_constant :PlayControl
177
175
  end
178
- end; end
176
+ end
@@ -1,16 +1,10 @@
1
- require_relative '../core-ext/arrayfy'
2
1
  require_relative '../core-ext/smart-proc-binder'
2
+ require_relative '../core-ext/inspect-nice'
3
3
 
4
- using Musa::Extension::Arrayfy
5
- using Musa::Extension::DeepCopy
4
+ using Musa::Extension::InspectNice
6
5
 
7
- module Musa; module Sequencer
6
+ module Musa::Sequencer
8
7
  class BaseSequencer
9
- include Musa::Extension::SmartProcBinder
10
- include Musa::Extension::DeepCopy
11
-
12
- using Musa::Extension::InspectNice
13
-
14
8
  private def _tick(position_to_run)
15
9
  @before_tick.each { |block| block.call position_to_run }
16
10
  queue = @timeslots[position_to_run]
@@ -72,7 +66,7 @@ module Musa; module Sequencer
72
66
  at_position = _quantize_position(at_position)
73
67
 
74
68
  block_key_parameters_binder =
75
- SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
69
+ Musa::Extension::SmartProcBinder::SmartProcBinder.new block, on_rescue: proc { |e| _rescue_error(e) }
76
70
 
77
71
  key_parameters = {}
78
72
  key_parameters[:control] = control if block_key_parameters_binder.key?(:control)
@@ -133,8 +127,6 @@ module Musa; module Sequencer
133
127
  end
134
128
 
135
129
  class EventHandler
136
- include Musa::Extension::SmartProcBinder
137
-
138
130
  attr_accessor :continue_parameters
139
131
 
140
132
  @@counter = 0
@@ -174,7 +166,7 @@ module Musa; module Sequencer
174
166
  @handlers[event] ||= {}
175
167
 
176
168
  # TODO: add on_rescue: proc { |e| _rescue_block_error(e) } [this method is on Sequencer, not in EventHandler]
177
- @handlers[event][name] = { block: SmartProcBinder.new(block), only_once: only_once }
169
+ @handlers[event][name] = { block: Musa::Extension::SmartProcBinder::SmartProcBinder.new(block), only_once: only_once }
178
170
  end
179
171
 
180
172
  def launch(event, *value_parameters, **key_parameters)
@@ -214,4 +206,4 @@ module Musa; module Sequencer
214
206
 
215
207
  private_constant :EventHandler
216
208
  end
217
- end; end
209
+ end
@@ -18,7 +18,7 @@ module Musa
18
18
  :event_handler
19
19
 
20
20
  def_delegators :@dsl, :position, :quantize_position, :logger, :debug
21
- def_delegators :@dsl, :with, :now, :at, :wait, :play, :play_timed, :every, :move
21
+ def_delegators :@dsl, :now, :at, :wait, :play, :play_timed, :every, :move
22
22
  def_delegators :@dsl, :everying, :playing, :moving
23
23
  def_delegators :@dsl, :launch, :on
24
24
  def_delegators :@dsl, :run
@@ -28,6 +28,7 @@ module Musa
28
28
  sequencer: nil,
29
29
  logger: nil,
30
30
  do_log: nil, do_error_log: nil, log_position_format: nil,
31
+ keep_proc_context: nil,
31
32
  &block)
32
33
 
33
34
  @sequencer = sequencer
@@ -37,14 +38,17 @@ module Musa
37
38
  do_error_log: do_error_log,
38
39
  log_position_format: log_position_format
39
40
 
40
- @dsl = DSLContext.new @sequencer
41
+ @dsl = DSLContext.new @sequencer, keep_proc_context: keep_proc_context
41
42
 
42
- with &block if block_given?
43
+ @dsl.with &block if block_given?
44
+ end
45
+
46
+ def with(&block)
47
+ @dsl.with &block
43
48
  end
44
49
 
45
50
  class DSLContext
46
51
  extend Forwardable
47
- include Musa::Extension::SmartProcBinder
48
52
  include Musa::Extension::With
49
53
 
50
54
  attr_reader :sequencer
@@ -57,8 +61,9 @@ module Musa
57
61
  :ticks_per_bar, :logger, :debug, :inspect,
58
62
  :run
59
63
 
60
- def initialize(sequencer)
64
+ def initialize(sequencer, keep_proc_context:)
61
65
  @sequencer = sequencer
66
+ @keep_proc_context_on_with = keep_proc_context
62
67
  end
63
68
 
64
69
  def now(*value_parameters, **key_parameters, &block)
@@ -104,7 +109,7 @@ module Musa
104
109
  block ||= proc {}
105
110
 
106
111
  @sequencer.every *value_parameters, **key_parameters do |*value_args, **key_args|
107
- args = SmartProcBinder.new(block)._apply(value_args, key_args)
112
+ args = Musa::Extension::SmartProcBinder::SmartProcBinder.new(block)._apply(value_args, key_args)
108
113
  with *args.first, **args.last, &block
109
114
  end
110
115
  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)
@@ -15,7 +15,7 @@ module Musa
15
15
  left_open: nil,
16
16
  right_open: nil)
17
17
 
18
- Series.QUANTIZE(self,
18
+ Series::Constructors.QUANTIZE(self,
19
19
  reference: reference,
20
20
  step: step,
21
21
  value_attribute: value_attribute,
@@ -6,7 +6,33 @@ module Musa
6
6
  module Series
7
7
  module Operations
8
8
  def composer(&block)
9
- Composer::Composer.new(input: self, &block).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
 
@@ -42,8 +68,7 @@ module Musa
42
68
  @outputs = {}
43
69
 
44
70
  inputs.keys&.each do |input|
45
- p = PROXY()
46
- p.proxy_source = inputs[input] if inputs[input]
71
+ p = PROXY(inputs[input])
47
72
 
48
73
  @inputs[input] = @pipelines[input] = Pipeline.new(input, input: p, output: p.buffered, pipelines: @pipelines)
49
74
 
@@ -119,7 +144,8 @@ module Musa
119
144
  end
120
145
 
121
146
  def commit!
122
- first_serie_operation = @first_proc&.call(NIL())
147
+ first_serie_operation = @first_proc&.call(UNDEFINED())
148
+
123
149
  @input ||= first_serie_operation
124
150
 
125
151
  @routes.each_value do |route|
@@ -256,9 +282,18 @@ module Musa
256
282
  when Proc
257
283
  call_constructor_according_to_last_and_parameter(last.call, constructor, parameter)
258
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
+
259
295
  when Serie
260
- # TODO: ignoring last, should make an error?
261
- Musa::Series::Constructors.method(constructor).call(*parameter)
296
+ raise "Unexpected source serie #{last} for constructor #{constructor}"
262
297
 
263
298
  when nil
264
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.6'
4
- s.date = '2021-07-29'
3
+ s.version = '0.23.11'
4
+ s.date = '2021-08-31'
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.6
4
+ version: 0.23.11
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-29 00:00:00.000000000 Z
11
+ date: 2021-08-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: citrus