musa-dsl 0.22.6 → 0.23.4

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,236 @@
1
+ module Musa
2
+ module Series::Operations
3
+ def buffered(sync: false)
4
+ if sync
5
+ SyncBufferSerie.new(self)
6
+ else
7
+ BufferSerie.new(self)
8
+ end
9
+ end
10
+
11
+ class SyncBufferSerie
12
+ include Series::Serie.with(source: true)
13
+
14
+ def initialize(serie)
15
+ self.source = serie
16
+ @history = []
17
+ @buffers = Set[]
18
+
19
+ init
20
+ end
21
+
22
+ private def _restart
23
+ @source.restart
24
+ clear_old_history
25
+ end
26
+
27
+ private def _next_value
28
+ @source.next_value.tap { |value| @history << value unless value.nil? && !@history.empty? && @history.last.nil? }
29
+ end
30
+
31
+ def buffer
32
+ @buffer ||= Buffer.new(@history)
33
+ @buffer.send(@get).tap { |_| @buffers << _ }
34
+ end
35
+
36
+ private def clear_old_history
37
+ min_last_nil_index = @buffers.collect(&:last_nil_index).min
38
+
39
+ if min_last_nil_index && min_last_nil_index >=0
40
+ @history = @history.drop(min_last_nil_index)
41
+
42
+ @buffers.each do |b|
43
+ b._reindex(@history, min_last_nil_index)
44
+ end
45
+ end
46
+ end
47
+
48
+ class Buffer
49
+ include Series::Serie.base
50
+
51
+ def initialize(history)
52
+ @history = history
53
+ @last_nil_index = -1
54
+ init
55
+ end
56
+
57
+ attr_reader :last_nil_index
58
+
59
+ def _reindex(history, offset)
60
+ @history = history
61
+
62
+ @last_nil_index -= offset
63
+ @index -= offset
64
+ end
65
+
66
+ private def _init
67
+ @index = @last_nil_index
68
+ @wait_restart = false
69
+ end
70
+
71
+ private def _next_value
72
+ @index += 1 if @index + 1 < @history.size && !@wait_restart
73
+
74
+ if @history[@index].nil? && @index < @history.size
75
+
76
+ @wait_restart = true
77
+
78
+ if @index + 1 < @history.size
79
+ @last_nil_index = @index
80
+ end
81
+ end
82
+
83
+ @history[@index]
84
+ end
85
+ end
86
+
87
+ private_constant :Buffer
88
+ end
89
+
90
+ private_constant :SyncBufferSerie
91
+
92
+ class BufferSerie
93
+ # modo fill_on_restart: cuando una serie hace restart, las demás no se ven afectadas porque siguen recibiendo
94
+ # todos los elementos de la serie original
95
+
96
+ include Series::Serie.with(source: true)
97
+
98
+ def initialize(serie)
99
+ self.source = serie
100
+
101
+ @history = [nil]
102
+ @nils = [0]
103
+ @buffers = Set[]
104
+
105
+ @singleton = nil
106
+ @buffer = nil
107
+
108
+ init
109
+ end
110
+
111
+ def instance
112
+ @singleton ||= super
113
+ end
114
+
115
+ def buffer
116
+ @buffer ||= Buffer.new(self)
117
+ @buffer
118
+ end
119
+
120
+ private def _restart(buffer)
121
+ raise ArgumentError, "Can't restart a BufferSerie directly. Should use a buffer instance instead." unless buffer
122
+ return if @source_just_restarted
123
+
124
+ next_nil = @nils.find { |_| _ > buffer.index }
125
+
126
+ if next_nil && buffer.index < next_nil
127
+ buffer.last_nil_index = buffer.index = next_nil
128
+
129
+ else
130
+ until _next_value.nil?; end
131
+ buffer.last_nil_index = buffer.index = @nils.last
132
+ end
133
+
134
+ clear_old_history
135
+
136
+ @source.restart
137
+ @source_just_restarted = true
138
+ end
139
+
140
+ private def _next_value
141
+ @source_just_restarted = false
142
+ value = @source.next_value
143
+
144
+ if value.nil?
145
+ unless @history.last.nil?
146
+ @history << nil
147
+ @nils << @history.size - 1
148
+ end
149
+ else
150
+ @history << value
151
+ end
152
+
153
+ value
154
+ end
155
+
156
+ def _register(buffer)
157
+ @buffers << buffer
158
+
159
+ buffer.history = @history
160
+ buffer.last_nil_index = 0
161
+ end
162
+
163
+ private def clear_old_history
164
+ min_last_nil_index = @buffers.collect(&:last_nil_index).min
165
+
166
+ if min_last_nil_index && min_last_nil_index >=0
167
+
168
+ pre_nils = @nils.clone
169
+ @history = @history.drop(min_last_nil_index)
170
+
171
+ @nils.collect! { |_| _ - min_last_nil_index }
172
+ @nils.delete_if(&:negative?)
173
+
174
+ @buffers.each do |b|
175
+ b._reindex(@history, min_last_nil_index)
176
+ end
177
+ end
178
+ end
179
+
180
+ class Buffer
181
+ include Series::Serie.with(source: true, private_source: true)
182
+
183
+ def initialize(base)
184
+ self.source = base
185
+
186
+ mark_as_prototype! # necesario para que se creen instancias diferentes cada vez que se ejecute BufferSerie.buffer()
187
+
188
+ init
189
+ end
190
+
191
+ attr_accessor :history
192
+ attr_accessor :last_nil_index
193
+ attr_accessor :index
194
+
195
+ def _reindex(history, offset)
196
+ @history = history
197
+ @last_nil_index -= offset
198
+ @index -= offset
199
+ end
200
+
201
+ private def _init
202
+ @source._register(self) if instance?
203
+ @index = @last_nil_index
204
+ end
205
+
206
+ private def _restart
207
+ @source.restart(self)
208
+ @needs_restart = false
209
+ end
210
+
211
+ private def _next_value
212
+ value = nil
213
+
214
+ unless @needs_restart
215
+ if @index + 1 < @history.size
216
+ @index += 1
217
+ value = @history[@index]
218
+ else
219
+ value = _next_value unless @source.next_value.nil?
220
+ end
221
+
222
+ if value.nil?
223
+ @needs_restart = true
224
+ end
225
+ end
226
+
227
+ value
228
+ end
229
+ end
230
+
231
+ private_constant :Buffer
232
+ end
233
+
234
+ private_constant :BufferSerie
235
+ end
236
+ end
@@ -1,175 +1,189 @@
1
1
  module Musa
2
- module Series
3
- module SerieOperations
4
- def split
5
- Splitter.new(Splitter::BufferedProxy.new(self))
2
+ module Series::Operations
3
+ def split
4
+ Splitter.new(self)
5
+ end
6
+
7
+ class Splitter
8
+ include Enumerable
9
+ include Series::Serie::Prototyping
10
+
11
+ def initialize(source)
12
+ @source = source
13
+ @series = {}
6
14
  end
7
15
 
8
- class Splitter
9
- include Enumerable
16
+ def source=(serie)
17
+ @source = serie
18
+ @proxy.source = @source if @proxy
19
+ end
10
20
 
11
- def initialize(proxy)
12
- @proxy = proxy
13
- @series = {}
14
- end
21
+ protected def _instance!
22
+ super
23
+ @proxy = SplitterProxy.new(@source)
24
+ end
15
25
 
16
- def [](key_or_index)
17
- if @series.has_key?(key_or_index)
18
- @series[key_or_index]
19
- else
20
- @series[key_or_index] = Split.new(@proxy, key_or_index)
21
- end
26
+ 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
28
+
29
+ if @series.key?(key_or_index)
30
+ @series[key_or_index]
31
+ else
32
+ @series[key_or_index] = Split.new(@proxy, key_or_index)
22
33
  end
34
+ end
23
35
 
24
- def each
25
- if block_given?
26
- if @proxy.hash_mode?
27
- @proxy.components.each do |key|
28
- yield [key, self[key]]
29
- end
30
- elsif @proxy.array_mode?
31
- @proxy.components.each do |index|
32
- yield self[index]
33
- end
34
- else
35
- # do nothing
36
+ def each
37
+ raise "Can't iterate because Splitter is a prototype. To iterate you need a Splitter instance." unless @is_instance
38
+
39
+ if block_given?
40
+ if @proxy.hash_mode?
41
+ @proxy.components.each do |key|
42
+ yield [key, self[key]]
36
43
  end
37
- else
38
- if @proxy.hash_mode?
39
- @proxy.components.collect { |key| [key, self[key]] }.each
40
- elsif @proxy.array_mode?
41
- @proxy.components.collect { |index| self[index] }.each
42
- else
43
- [].each
44
+ elsif @proxy.array_mode?
45
+ @proxy.components.each do |index|
46
+ yield self[index]
44
47
  end
48
+ else
49
+ # do nothing
45
50
  end
46
- end
47
-
48
- def to_hash
51
+ else
49
52
  if @proxy.hash_mode?
50
- @proxy.components.collect { |key| [key, self[key]] }.to_h
53
+ @proxy.components.collect { |key| [key, self[key]] }.each
54
+ elsif @proxy.array_mode?
55
+ @proxy.components.collect { |index| self[index] }.each
51
56
  else
52
- raise RuntimeError, 'Splitter is not based on Hash: can\'t convert to Hash'
57
+ [].each
53
58
  end
54
59
  end
60
+ end
55
61
 
56
- def to_ary
57
- if @proxy.array_mode?
58
- [].tap { |_| @proxy.components.each { |i| _[i] = self[i] } }
59
- else
60
- raise RuntimeError, 'Splitter is not based on Array: can\'t convert to Array'
61
- end
62
+ def to_hash
63
+ if @proxy.hash_mode?
64
+ @proxy.components.collect { |key| [key, self[key]] }.to_h
65
+ else
66
+ raise RuntimeError, 'Splitter is not based on Hash: can\'t convert to Hash'
62
67
  end
68
+ end
63
69
 
64
- class BufferedProxy
65
- include SeriePrototyping
66
-
67
- def initialize(hash_or_array_serie)
68
- @source = hash_or_array_serie
70
+ def to_ary
71
+ if @proxy.array_mode?
72
+ [].tap { |_| @proxy.components.each { |i| _[i] = self[i] } }
73
+ else
74
+ raise RuntimeError, 'Splitter is not based on Array: can\'t convert to Array'
75
+ end
76
+ end
69
77
 
70
- infer_components
78
+ class SplitterProxy
79
+ def initialize(hash_or_array_serie)
80
+ @source = hash_or_array_serie
81
+ infer_components
82
+ end
71
83
 
72
- restart restart_source: false
84
+ attr_reader :source
73
85
 
74
- mark_regarding! @source
75
- end
86
+ def source=(hash_or_array_serie)
87
+ @source = hash_or_array_serie
88
+ infer_components
89
+ end
76
90
 
77
- attr_reader :components
91
+ def hash_mode?; @hash_mode; end
78
92
 
79
- def hash_mode?; @hash_mode; end
80
- def array_mode?; @array_mode; end
93
+ def array_mode?; @array_mode; end
81
94
 
82
- def restart(key_or_index = nil, restart_source: true)
83
- if key_or_index
84
- @asked_to_restart[key_or_index] = true
85
- else
86
- @components.each { |c| @asked_to_restart[c] = true }
87
- end
95
+ attr_reader :components
88
96
 
89
- if @asked_to_restart.values.all?
90
- @source.restart if restart_source
91
- infer_components
92
- end
97
+ def restart(key_or_index = nil)
98
+ if key_or_index
99
+ @asked_to_restart[key_or_index] = true
100
+ else
101
+ @components.each { |c| @asked_to_restart[c] = true }
93
102
  end
94
103
 
95
- private def infer_components
96
- source = @source.instance
97
- sample = source.current_value || source.peek_next_value
104
+ if @asked_to_restart.values.all?
105
+ @source.restart
106
+ infer_components
107
+ end
108
+ end
98
109
 
99
- case sample
100
- when Array
101
- @components = (0..sample.size-1).to_a
102
- @values = []
103
- @array_mode = true
104
- @hash_mode = false
105
- when Hash
106
- @components = sample.keys.clone
107
- @values = {}
108
- @array_mode = false
109
- @hash_mode = true
110
- else
111
- @components = []
112
- @values = nil
113
- @array_mode = @hash_mode = false
114
- end
110
+ private def infer_components
111
+ source = @source.instance
112
+ sample = source.current_value || source.peek_next_value
113
+
114
+ case sample
115
+ when Array
116
+ @components = (0..sample.size-1).to_a
117
+ @values = []
118
+ @array_mode = true
119
+ @hash_mode = false
120
+ when Hash
121
+ @components = sample.keys.clone
122
+ @values = {}
123
+ @array_mode = false
124
+ @hash_mode = true
125
+ else
126
+ @components = []
127
+ @values = nil
128
+ @array_mode = @hash_mode = false
129
+ end
115
130
 
116
- @asked_to_restart = {}
131
+ @asked_to_restart = {}
117
132
 
118
- @components.each do |component|
119
- @asked_to_restart[component] = false
120
- end
133
+ @components.each do |component|
134
+ @asked_to_restart[component] = false
121
135
  end
136
+ end
137
+
138
+ def next_value(key_or_index)
139
+ if @values[key_or_index].nil? || @values[key_or_index].empty?
140
+
141
+ hash_or_array_value = @source.next_value
122
142
 
123
- def next_value(key_or_index)
124
- if @values[key_or_index].nil? || @values[key_or_index].empty?
125
-
126
- hash_or_array_value = @source.next_value
127
-
128
- case hash_or_array_value
129
- when Hash
130
- hash_or_array_value.each do |k, v|
131
- @values[k] ||= []
132
- @values[k] << v
133
- end
134
- when Array
135
- hash_or_array_value.each_index do |i|
136
- @values[i] ||= []
137
- @values[i] << hash_or_array_value[i]
138
- end
143
+ case hash_or_array_value
144
+ when Hash
145
+ hash_or_array_value.each do |k, v|
146
+ @values[k] ||= []
147
+ @values[k] << v
148
+ end
149
+ when Array
150
+ hash_or_array_value.each_index do |i|
151
+ @values[i] ||= []
152
+ @values[i] << hash_or_array_value[i]
139
153
  end
140
154
  end
155
+ end
141
156
 
142
- if @values && !@values[key_or_index].nil?
143
- @values[key_or_index].shift
144
- else
145
- nil
146
- end
157
+ if @values && !@values[key_or_index].nil?
158
+ @values[key_or_index].shift
159
+ else
160
+ nil
147
161
  end
148
162
  end
163
+ end
149
164
 
150
- class Split
151
- include Serie
152
-
153
- def initialize(proxy, key_or_index)
154
- @source = proxy
155
- @key_or_index = key_or_index
165
+ class Split
166
+ include Series::Serie.base
156
167
 
157
- mark_regarding! @source
158
- end
168
+ def initialize(proxy, key_or_index)
169
+ @proxy = proxy
170
+ @key_or_index = key_or_index
159
171
 
160
- def _restart
161
- @source.restart @key_or_index
162
- end
172
+ mark_as_instance!
173
+ end
163
174
 
164
- def _next_value
165
- @source.next_value(@key_or_index)
166
- end
175
+ private def _restart
176
+ @proxy.restart(@key_or_index)
167
177
  end
168
178
 
169
- private_constant :Split
179
+ private def _next_value
180
+ @proxy.next_value(@key_or_index)
181
+ end
170
182
  end
171
183
 
172
- private_constant :Splitter
184
+ private_constant :Split
173
185
  end
186
+
187
+ private_constant :Splitter
174
188
  end
175
189
  end