musa-dsl 0.23.6 → 0.23.11

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: 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