musa-dsl 0.22.6 → 0.23.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,69 +1,49 @@
1
- module Musa
2
- module Series
3
- # TODO: adapt to series prototyping
1
+ require_relative 'base-series'
4
2
 
3
+ module Musa
4
+ module Series::Constructors
5
5
  def PROXY(serie = nil)
6
6
  ProxySerie.new(serie)
7
7
  end
8
8
 
9
9
  class ProxySerie
10
- include Serie
11
-
12
- attr_reader :target
10
+ include Series::Serie.with(source: true)
13
11
 
14
12
  def initialize(serie)
15
- @target = serie.instance if serie
16
- mark_as_instance!
17
- end
18
-
19
- def target=(target)
20
- @target = target.instance
21
- end
22
-
23
- def _prototype!
24
- raise PrototypingSerieError, 'Cannot get prototype of a proxy serie'
13
+ self.source = serie
14
+ init
25
15
  end
26
16
 
27
- def restart
28
- @target.restart if @target
17
+ private def _restart
18
+ @source.restart if @source
29
19
  end
30
20
 
31
- def current_value
32
- @target.current_value if @target
33
- end
34
-
35
- def next_value
36
- @target.next_value if @target
37
- end
38
-
39
- def peek_next_value
40
- @target.peek_next_value if @target
21
+ private def _next_value
22
+ @source.next_value if @source
41
23
  end
42
24
 
43
25
  def infinite?
44
- @target.infinite? if @target
26
+ @source.infinite? if @source
45
27
  end
46
28
 
47
- private
48
-
49
- def method_missing(method_name, *args, **key_args, &block)
50
- if @target && @target.respond_to?(method_name)
51
- @target.send method_name, *args, **key_args, &block
29
+ private def method_missing(method_name, *args, **key_args, &block)
30
+ if @source && @source.respond_to?(method_name)
31
+ @source.send method_name, *args, **key_args, &block
52
32
  else
53
33
  super
54
34
  end
55
35
  end
56
36
 
57
- def respond_to_missing?(method_name, include_private)
58
- @target && @target.respond_to?(method_name, include_private) # || super
37
+ private def respond_to_missing?(method_name, include_private)
38
+ @source && @source.respond_to?(method_name, include_private) # || super
59
39
  end
60
40
  end
41
+ end
61
42
 
62
- module SerieOperations
63
- # TODO add test case
64
- def proxied
65
- Series::ProxySerie.new self
66
- end
43
+ module Series::Operations
44
+ # TODO add test case
45
+ def proxy
46
+ Series::ProxySerie.new(self)
67
47
  end
68
48
  end
69
49
  end
@@ -1,34 +1,32 @@
1
1
  require_relative '../datasets/e'
2
2
  require_relative '../core-ext/inspect-nice'
3
3
 
4
+ require_relative 'base-series'
5
+
4
6
  # TODO remove debugging puts, intermediate hash comments on :info and InspectNice
5
7
  using Musa::Extension::InspectNice
6
8
 
7
9
  module Musa
8
- module Series
9
- module SerieOperations
10
- def quantize(reference: nil, step: nil,
11
- value_attribute: nil,
12
- stops: nil,
13
- predictive: nil,
14
- left_open: nil,
15
- right_open: nil)
16
-
17
- Series.QUANTIZE(self,
18
- reference: reference,
19
- step: step,
20
- value_attribute: value_attribute,
21
- stops: stops,
22
- predictive: predictive,
23
- left_open: left_open,
24
- right_open: right_open)
25
- end
10
+ module Series::Operations
11
+ def quantize(reference: nil, step: nil,
12
+ value_attribute: nil,
13
+ stops: nil,
14
+ predictive: nil,
15
+ left_open: nil,
16
+ right_open: nil)
17
+
18
+ Series.QUANTIZE(self,
19
+ reference: reference,
20
+ step: step,
21
+ value_attribute: value_attribute,
22
+ stops: stops,
23
+ predictive: predictive,
24
+ left_open: left_open,
25
+ right_open: right_open)
26
26
  end
27
27
  end
28
28
 
29
- module Series
30
- extend self
31
-
29
+ module Series::Constructors
32
30
  def QUANTIZE(time_value_serie,
33
31
  reference: nil, step: nil,
34
32
  value_attribute: nil,
@@ -82,28 +80,27 @@ module Musa
82
80
  private_constant :QuantizerTools
83
81
 
84
82
  class RawQuantizer
85
- include Serie
83
+ include Series::Serie.with(source: true)
86
84
  include QuantizerTools
87
85
 
88
86
  attr_reader :source
89
87
 
90
88
  def initialize(reference, step, source, value_attribute, stops, left_open, right_open)
89
+ self.source = source
90
+
91
91
  @reference = reference
92
92
  @step_size = step.abs
93
93
 
94
- @source = source
95
94
  @value_attribute = value_attribute
96
95
 
97
96
  @stops = stops
98
97
  @left_open = left_open
99
98
  @right_open = right_open
100
99
 
101
- _restart false
102
-
103
- mark_regarding! source
100
+ init
104
101
  end
105
102
 
106
- def _restart(restart_sources = true)
103
+ private def _init
107
104
  @last_processed_q_value = nil
108
105
  @last_processed_time = nil
109
106
 
@@ -111,11 +108,13 @@ module Musa
111
108
 
112
109
  @points = []
113
110
  @segments = []
111
+ end
114
112
 
115
- @source.restart if restart_sources
113
+ private def _restart
114
+ @source.restart
116
115
  end
117
116
 
118
- def _next_value
117
+ private def _next_value
119
118
  if @stops
120
119
  i = 2
121
120
 
@@ -348,16 +347,17 @@ module Musa
348
347
  private_constant :RawQuantizer
349
348
 
350
349
  class PredictiveQuantizer
351
- include Serie
350
+ include Series::Serie.with(source: true)
352
351
  include QuantizerTools
353
352
 
354
353
  attr_reader :source
355
354
 
356
355
  def initialize(reference, step, source, value_attribute, include_stops)
356
+ self.source = source
357
+
357
358
  @reference = reference
358
359
  @step_size = step
359
360
 
360
- @source = source
361
361
  @value_attribute = value_attribute
362
362
 
363
363
  @include_stops = include_stops
@@ -365,25 +365,25 @@ module Musa
365
365
  @halfway_offset = step / 2r
366
366
  @crossing_reference = reference - @halfway_offset
367
367
 
368
- _restart false
369
-
370
- mark_regarding! source
368
+ init
371
369
  end
372
370
 
373
- def _restart(restart_sources = true)
374
- @source.restart if restart_sources
375
-
371
+ private def _init
376
372
  @last_time = nil
377
373
  @crossings = []
378
374
 
379
375
  @first = true
380
376
  end
381
377
 
378
+ private def _restart
379
+ @source.restart
380
+ end
381
+
382
382
  def infinite?
383
383
  !!@source.infinite?
384
384
  end
385
385
 
386
- def _next_value
386
+ private def _next_value
387
387
  result = nil
388
388
 
389
389
  first_time, first_value = get_time_value(@source.peek_next_value) if @first
@@ -1,51 +1,53 @@
1
- module Musa
2
- module Series
3
- # TODO: adapt to series prototyping
1
+ require_relative 'base-series'
4
2
 
3
+ module Musa
4
+ module Series::Constructors
5
5
  def QUEUE(*series)
6
6
  QueueSerie.new(series)
7
7
  end
8
8
 
9
9
  class QueueSerie
10
- include Serie
11
-
12
- attr_reader :targets, :target
10
+ include Series::Serie.with(sources: true)
13
11
 
14
12
  def initialize(series)
15
- @targets = series.collect(&:instance)
16
- @targets ||= []
17
-
18
- mark_as_instance!
19
-
20
- _restart
13
+ self.sources = series
14
+ init
21
15
  end
22
16
 
23
17
  def <<(serie)
24
- @targets << serie.instance
25
- check_current
18
+ # when queue is a prototype it is also frozen so no serie can be added (it would raise an Exception if tried).
19
+ # when queue is an instance the added serie should also be an instance (raise an Exception otherwise)
20
+ #
21
+ raise ArgumentError, "Only an instance serie can be queued" unless serie.instance?
22
+
23
+ @sources << serie
24
+ @current ||= @sources[@index]
25
+
26
26
  self
27
27
  end
28
28
 
29
29
  def clear
30
- @targets.clear
31
- restart
30
+ @sources.clear
31
+ init
32
32
  self
33
33
  end
34
34
 
35
- def _prototype!
36
- raise PrototypingSerieError, 'Cannot get prototype of a proxy serie'
35
+ private def _init
36
+ @index = 0
37
+ @current = @sources[@index]
38
+ @restart_sources = false
37
39
  end
38
40
 
39
- def _restart
40
- @index = -1
41
- forward
41
+ private def _restart
42
+ @current.restart
43
+ @restart_sources = true
42
44
  end
43
45
 
44
- def _next_value
46
+ private def _next_value
45
47
  value = nil
46
48
 
47
- if @target
48
- value = @target.next_value
49
+ if @current
50
+ value = @current.next_value
49
51
 
50
52
  if value.nil?
51
53
  forward
@@ -57,38 +59,32 @@ module Musa
57
59
  end
58
60
 
59
61
  def infinite?
60
- !!@targets.find(&:infinite?)
62
+ !!@sources.find(&:infinite?)
61
63
  end
62
64
 
63
- private
64
-
65
- def forward
65
+ private def forward
66
66
  @index += 1
67
- @target = nil
68
- @target = @targets[@index].restart if @index < @targets.size
69
- end
70
-
71
- def check_current
72
- @target = @targets[@index].restart unless @target
67
+ @current = @sources[@index]
68
+ @current&.restart if @restart_sources
73
69
  end
74
70
 
75
- def method_missing(method_name, *args, **key_args, &block)
76
- if @target && @target.respond_to?(method_name)
77
- @target.send method_name, *args, **key_args, &block
71
+ private def method_missing(method_name, *args, **key_args, &block)
72
+ if @current&.respond_to?(method_name)
73
+ @current.send method_name, *args, **key_args, &block
78
74
  else
79
75
  super
80
76
  end
81
77
  end
82
78
 
83
- def respond_to_missing?(method_name, include_private)
84
- @target && @target.respond_to?(method_name, include_private) # || super
79
+ private def respond_to_missing?(method_name, include_private)
80
+ @current&.respond_to?(method_name, include_private) # || super
85
81
  end
86
82
  end
83
+ end
87
84
 
88
- module SerieOperations
89
- def queued
90
- Series::QueueSerie.new [self]
91
- end
85
+ module Series::Operations
86
+ def queued
87
+ Series::Constructors.QUEUE(self)
92
88
  end
93
89
  end
94
90
  end
@@ -0,0 +1,149 @@
1
+ require_relative 'base-series'
2
+
3
+ require_relative '../core-ext/with'
4
+
5
+ module Musa
6
+ module Series
7
+ module Composer
8
+ class Composer
9
+ using Musa::Extension::Arrayfy
10
+
11
+ attr_reader :inputs, :outputs
12
+
13
+ def initialize(inputs: [:input], outputs: [:output], &block)
14
+ @pipelines = {}
15
+
16
+ @links = Set[]
17
+ @links_from = {}
18
+ @links_to = {}
19
+
20
+ @dsl = DSLContext.new(@pipelines, @links, @links_from, @links_to)
21
+ @inputs = {}
22
+ @outputs = {}
23
+
24
+ inputs&.each do |input|
25
+ @inputs[input] = Series::Constructors.PROXY
26
+ @pipelines[input] = { input: nil, output: @inputs[input].buffered }
27
+
28
+ @dsl.define_singleton_method(input) { input }
29
+ end
30
+
31
+ outputs&.each do |output|
32
+ @outputs[output] = Series::Constructors.PROXY
33
+ @pipelines[output] = { input: @outputs[output], output: nil }
34
+
35
+ @dsl.define_singleton_method(output) { output }
36
+ end
37
+
38
+ @dsl.with &block if block
39
+ end
40
+
41
+ def route(from, to:, on: nil, as: nil)
42
+ @dsl.route(from, to: to, on: on, as: as)
43
+ end
44
+
45
+ def pipeline(name, *elements)
46
+ @dsl.pipeline(name, elements)
47
+ end
48
+
49
+ def update(&block)
50
+ @dsl.with &block
51
+ end
52
+
53
+ class DSLContext
54
+ include Musa::Extension::With
55
+
56
+ def initialize(pipelines, links, links_from, links_to)
57
+ @pipelines = pipelines
58
+
59
+ @links = links
60
+ @links_from = links_from
61
+ @links_to = links_to
62
+ end
63
+
64
+ def route(from, to:, on: nil, as: nil)
65
+ from_pipeline = @pipelines[from]
66
+ to_pipeline = @pipelines[to]
67
+
68
+ raise ArgumentError, "Pipeline '#{from}' not found." unless from_pipeline
69
+ raise ArgumentError, "Pipeline '#{to}' not found." unless to_pipeline
70
+
71
+ @links_from[from] ||= Set[]
72
+
73
+ on ||= as ? :sources : :source
74
+
75
+ raise ArgumentError, "Pipeline #{@links_to[[to, on, as]]} already connected to pipeline #{to} on #{on} as #{as}" if @links_to[[to, on, as]]
76
+
77
+ if as
78
+ to_pipeline[:input].send(on)[as] = from_pipeline[:output].buffer
79
+ else
80
+ to_pipeline[:input].send("#{on.to_s}=".to_sym, from_pipeline[:output].buffer)
81
+ end
82
+
83
+ @links_from[from] << [to, on, as]
84
+ @links_to[[to, on, as]] = from
85
+ @links << [from, to, on, as]
86
+ end
87
+
88
+ def pipeline(name, elements)
89
+ first = last = nil
90
+
91
+ elements.each do |e|
92
+ case e
93
+ when Hash
94
+ if e.size == 1
95
+ operation = e.keys.first
96
+ parameters = e.values.first
97
+
98
+ if Musa::Series::Constructors.instance_methods.include?(operation)
99
+ raise ArgumentError, "Called constructor '#{operation}' ignoring previous elements" unless last.nil?
100
+
101
+ last = Musa::Series::Constructors.method(operation).call(*parameters)
102
+
103
+ elsif Musa::Series::Operations.instance_methods.include?(operation)
104
+ first = last = Musa::Series::Constructors.PROXY if last.nil?
105
+ last = last.send(operation, *parameters)
106
+
107
+ end
108
+ else
109
+ raise ArgumentError, "Don't know how to handle #{e}"
110
+ end
111
+ when Symbol
112
+ first = last = Musa::Series::Constructors.PROXY if last.nil?
113
+ # operation == e
114
+ last = last.send(e) if Musa::Series::Operations.instance_methods.include?(e)
115
+ end
116
+
117
+ first ||= last
118
+ end
119
+
120
+ @pipelines[name] = { input: first, output: last.buffered }
121
+
122
+ define_singleton_method(name) { name }
123
+ end
124
+
125
+ private def method_missing(symbol, *args, &block)
126
+ if Musa::Series::Operations.instance_methods.include?(symbol)
127
+ symbol
128
+ elsif Musa::Series::Constructors.instance_methods.include?(symbol)
129
+ symbol
130
+ else
131
+ raise ArgumentError, "Pipeline '#{symbol}' is undefined" if args.empty?
132
+
133
+ pipeline(symbol, args)
134
+ end
135
+ end
136
+
137
+ private def respond_to_missing?(method_name, include_private = false)
138
+ Musa::Series::Operations.instance_methods.include?(method_name) ||
139
+ Musa::Series::Constructors.instance_methods.include?(method_name) ||
140
+ @pipelines.key?(method_name) ||
141
+ super
142
+ end
143
+ end
144
+
145
+ private_constant :DSLContext
146
+ end
147
+ end
148
+ end
149
+ end