musa-dsl 0.22.6 → 0.23.4

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,6 +1,6 @@
1
1
  module Musa
2
2
  module Series
3
- module SerieOperations
3
+ module Operations
4
4
  def autorestart
5
5
  Autorestart.new self
6
6
  end
@@ -108,12 +108,16 @@ module Musa
108
108
 
109
109
  alias_method :eval, :with
110
110
 
111
- def map(&yield_block)
112
- ProcessWith.new self, &yield_block
111
+ def map(&block)
112
+ ProcessWith.new self, &block
113
113
  end
114
114
 
115
- def anticipate(&yield_block)
116
- Anticipate.new self, &yield_block
115
+ def anticipate(&block)
116
+ Anticipate.new self, &block
117
+ end
118
+
119
+ def lazy(&block)
120
+ LazySerieEval.new self, &block
117
121
  end
118
122
 
119
123
  ###
@@ -121,34 +125,36 @@ module Musa
121
125
  ###
122
126
 
123
127
  class ProcessWith
124
- include Musa::Extension::SmartProcBinder
125
- include Serie
126
-
127
- attr_reader :source, :on_restart, :block
128
- def with_sources; @sources; end
128
+ include Serie.with(source: true, sources: true, sources_as: :with_sources, smart_block: true)
129
129
 
130
130
  def initialize(serie, with_series = nil, on_restart = nil, &block)
131
- @source = serie
132
- @sources = with_series || {}
133
- @on_restart = on_restart
134
- @block = SmartProcBinder.new(block) if block_given?
131
+ self.source = serie
132
+ self.with_sources = with_series || {}
133
+ self.on_restart = on_restart
134
+ self.proc = block if block
135
135
 
136
- if @source.prototype?
137
- @sources = @sources.transform_values { |s| s.prototype }.freeze
136
+ init
137
+ end
138
+
139
+ def on_restart(&block)
140
+ if block
141
+ @on_restart = block
138
142
  else
139
- @sources = @sources.transform_values { |s| s.instance }
143
+ @on_restart
140
144
  end
145
+ end
141
146
 
142
- mark_regarding! @source
147
+ def on_restart=(block)
148
+ @on_restart = block
143
149
  end
144
150
 
145
- def _restart
151
+ private def _restart
146
152
  @source.restart
147
- @sources.values.each { |s| s.restart }
153
+ @sources.values.each(&:restart)
148
154
  @on_restart.call if @on_restart
149
155
  end
150
156
 
151
- def _next_value
157
+ private def _next_value
152
158
  main = @source.next_value
153
159
  others = @sources.transform_values { |v| v.next_value }
154
160
 
@@ -173,23 +179,20 @@ module Musa
173
179
  private_constant :ProcessWith
174
180
 
175
181
  class Anticipate
176
- include Musa::Extension::SmartProcBinder
177
- include Serie
178
-
179
- attr_reader :source, :block
182
+ include Serie.with(source: true, block: true)
180
183
 
181
184
  def initialize(serie, &block)
182
- @source = serie
183
- @block = block
185
+ self.source = serie
186
+ self.proc = block
184
187
 
185
- mark_regarding! @source
188
+ init
186
189
  end
187
190
 
188
- def _restart
191
+ private def _restart
189
192
  @source.restart
190
193
  end
191
194
 
192
- def _next_value
195
+ private def _next_value
193
196
  previous_value = @source.current_value
194
197
  value = @source.next_value
195
198
  peek_next_value = @source.peek_next_value
@@ -209,30 +212,16 @@ module Musa
209
212
  private_constant :Anticipate
210
213
 
211
214
  class Switcher
212
- include Serie
213
-
214
- attr_accessor :sources
215
- def selector; @source; end
215
+ include Serie.with(source: true, sources: true, sources_as: :options)
216
216
 
217
217
  def initialize(selector, indexed_series, hash_series)
218
+ self.source = selector
219
+ self.options = indexed_series || hash_series
218
220
 
219
- @source = selector
220
- get = @source.prototype? ? :prototype : :instance
221
-
222
- if indexed_series && !indexed_series.empty?
223
- @sources = indexed_series.collect(&get)
224
- elsif hash_series && !hash_series.empty?
225
- @sources = hash_series.clone.transform_values(&get)
226
- end
227
-
228
- if get == :prototype!
229
- @sources.freeze
230
- end
231
-
232
- mark_regarding! @source
221
+ init
233
222
  end
234
223
 
235
- def _restart
224
+ private def _restart
236
225
  @source.restart
237
226
  if @sources.is_a? Array
238
227
  @sources.each(&:restart)
@@ -241,7 +230,7 @@ module Musa
241
230
  end
242
231
  end
243
232
 
244
- def _next_value
233
+ private def _next_value
245
234
  value = nil
246
235
 
247
236
  index_or_key = @source.next_value
@@ -259,46 +248,31 @@ module Musa
259
248
  private_constant :Switcher
260
249
 
261
250
  class MultiplexSelector
262
- include Serie
263
-
264
- def selector; @source; end
265
- attr_accessor :sources
251
+ include Serie.with(source: true, sources: true, sources_as: :options)
266
252
 
267
253
  def initialize(selector, indexed_series, hash_series)
268
- @source = selector
269
- get = @source.prototype? ? :prototype : :instance
254
+ self.source = selector
255
+ self.options = indexed_series || hash_series
270
256
 
271
- if indexed_series && !indexed_series.empty?
272
- @sources = indexed_series.collect(&get)
273
- elsif hash_series && !hash_series.empty?
274
- @sources = hash_series.clone.transform_values(&get)
275
- end
276
-
277
- _restart false
278
-
279
- if get == :prototype
280
- @sources.freeze
281
- end
282
-
283
- mark_regarding! @source
257
+ init
284
258
  end
285
259
 
286
- def _restart(restart_sources = true)
260
+ private def _init
287
261
  @current_value = nil
262
+ @first = true
263
+ end
288
264
 
289
- if restart_sources
290
- @source.restart
291
- if @sources.is_a? Array
292
- @sources.each(&:restart)
293
- elsif @sources.is_a? Hash
294
- @sources.each { |_key, serie| serie.restart }
295
- end
296
- end
265
+ private def _restart
266
+ @source.restart
297
267
 
298
- @first = true
268
+ if @sources.is_a? Array
269
+ @sources.each(&:restart)
270
+ elsif @sources.is_a? Hash
271
+ @sources.values.each(&:restart)
272
+ end
299
273
  end
300
274
 
301
- def _next_value
275
+ private def _next_value
302
276
  @current_value =
303
277
  if @first || !@current_value.nil?
304
278
  @first = false
@@ -318,34 +292,21 @@ module Musa
318
292
  private_constant :MultiplexSelector
319
293
 
320
294
  class SwitchFullSerie
321
- include Serie
322
-
323
- def selector; @source; end
324
- attr_accessor :sources
295
+ include Serie.with(source: true, sources: true, sources_as: :options)
325
296
 
326
297
  def initialize(selector, indexed_series, hash_series)
327
- @source = selector
328
- get = @source.prototype? ? :prototype : :instance
298
+ self.source = selector
299
+ self.options = indexed_series || hash_series
329
300
 
330
- if indexed_series && !indexed_series.empty?
331
- @sources = indexed_series.collect(&get)
332
- elsif hash_series && !hash_series.empty?
333
- @sources = hash_series.clone.transform_values(&get)
334
- end
335
-
336
- if get == :prototype
337
- @sources.freeze
338
- end
339
-
340
- mark_regarding! @source
301
+ init
341
302
  end
342
303
 
343
- def _restart
304
+ private def _restart
344
305
  @source.restart
345
306
  @sources.each(&:restart)
346
307
  end
347
308
 
348
- def _next_value
309
+ private def _next_value
349
310
  value = nil
350
311
 
351
312
  value = @sources[@index_or_key].next_value unless @index_or_key.nil?
@@ -367,21 +328,18 @@ module Musa
367
328
  private_constant :SwitchFullSerie
368
329
 
369
330
  class InfiniteRepeater
370
- include Serie
371
-
372
- attr_reader :source
331
+ include Serie.with(source: true)
373
332
 
374
333
  def initialize(serie)
375
- @source = serie
376
-
377
- mark_regarding! @source
334
+ self.source = serie
335
+ init
378
336
  end
379
337
 
380
- def _restart
338
+ private def _restart
381
339
  @source.restart
382
340
  end
383
341
 
384
- def _next_value
342
+ private def _next_value
385
343
  value = @source.next_value
386
344
 
387
345
  if value.nil?
@@ -400,38 +358,47 @@ module Musa
400
358
  private_constant :InfiniteRepeater
401
359
 
402
360
  class Repeater
403
- include Serie
404
-
405
- attr_reader :source, :times, :condition
361
+ include Serie.with(source: true)
406
362
 
407
363
  def initialize(serie, times = nil, &condition)
408
- @source = serie
364
+ self.source = serie
365
+ self.times = times
366
+ self.condition = condition
409
367
 
410
- @times = times
411
- @external_condition = condition
368
+ init
369
+ end
412
370
 
413
- _restart false
414
- @condition = calculate_condition
371
+ attr_reader :times
415
372
 
416
- mark_regarding! @source
373
+ def times=(value)
374
+ @times = value
375
+ calculate_condition
417
376
  end
418
377
 
419
- def _prototype!
420
- super
421
- @condition = calculate_condition
378
+ def condition(&block)
379
+ if block
380
+ @external_condition = block
381
+ calculate_condition
382
+ else
383
+ @external_condition
384
+ end
422
385
  end
423
386
 
424
- def _instance!
425
- super
426
- @condition = calculate_condition
387
+ def condition=(block)
388
+ @external_condition = block
389
+ calculate_condition
427
390
  end
428
391
 
429
- def _restart(restart_sources = true)
392
+ private def _init
430
393
  @count = 0
431
- @source.restart if restart_sources
394
+ calculate_condition
432
395
  end
433
396
 
434
- def _next_value
397
+ private def _restart
398
+ @source.restart
399
+ end
400
+
401
+ private def _next_value
435
402
  value = @source.next_value
436
403
 
437
404
  if value.nil?
@@ -451,38 +418,39 @@ module Musa
451
418
  end
452
419
 
453
420
  private def calculate_condition
454
- if @external_condition
455
- @external_condition
456
- elsif @times
457
- proc { @count < @times }
458
- else
459
- proc { false }
460
- end
421
+ @condition = if @external_condition
422
+ @external_condition
423
+ elsif @times
424
+ proc { @count < @times }
425
+ else
426
+ proc { false }
427
+ end
461
428
  end
462
429
  end
463
430
 
464
431
  private_constant :Repeater
465
432
 
466
433
  class LengthLimiter
467
- include Serie
468
-
469
- attr_reader :source, :length
434
+ include Serie.with(source: true)
470
435
 
471
436
  def initialize(serie, length)
472
- @source = serie
473
- @length = length
437
+ self.source = serie
438
+ self.length = length
474
439
 
475
- _restart false
476
-
477
- mark_regarding! @source
440
+ init
478
441
  end
479
442
 
480
- def _restart(restart_sources = true)
443
+ attr_accessor :length
444
+
445
+ private def _init
481
446
  @position = 0
482
- @source.restart if restart_sources
483
447
  end
484
448
 
485
- def _next_value
449
+ private def _restart
450
+ @source.restart
451
+ end
452
+
453
+ private def _next_value
486
454
  if @position < @length
487
455
  @position += 1
488
456
  @source.next_value
@@ -497,25 +465,26 @@ module Musa
497
465
  private_constant :LengthLimiter
498
466
 
499
467
  class Skipper
500
- include Serie
501
-
502
- attr_reader :source, :length
468
+ include Serie.with(source: true)
503
469
 
504
470
  def initialize(serie, length)
505
- @source = serie
506
- @length = length
507
-
508
- _restart false
471
+ self.source = serie
472
+ self.length = length
509
473
 
510
- mark_regarding! @source
474
+ init
511
475
  end
512
476
 
513
- def _restart(restart_sources = true)
514
- @source.restart if restart_sources
477
+ attr_accessor :length
478
+
479
+ private def _init
515
480
  @first = true
516
481
  end
517
482
 
518
- def _next_value
483
+ private def _restart
484
+ @source.restart
485
+ end
486
+
487
+ private def _next_value
519
488
  @length.times { @source.next_value } if @first
520
489
  @first = nil
521
490
 
@@ -530,40 +499,25 @@ module Musa
530
499
  private_constant :Skipper
531
500
 
532
501
  class Flattener
533
- include Serie
534
-
535
- attr_reader :source
502
+ include Serie.base
536
503
 
537
504
  def initialize(serie)
538
505
  @source = serie
539
-
540
- _restart false
541
-
542
506
  mark_regarding! @source
507
+ init
543
508
  end
544
509
 
545
- def _prototype!
546
- super
547
- _restart false
548
- end
549
-
550
- def _instance!
551
- super
552
- _restart false
510
+ private def _init
511
+ @stack = [@source]
512
+ @restart_each_serie = false
553
513
  end
554
514
 
555
- def _restart(restart_sources = true)
556
- if restart_sources
557
- @source.restart
558
- @restart_each_serie = true
559
- else
560
- @restart_each_serie = false
561
- end
562
-
563
- @stack = [@source]
515
+ private def _restart
516
+ @source.restart
517
+ @restart_each_serie = true
564
518
  end
565
519
 
566
- def _next_value
520
+ private def _next_value
567
521
  if @stack.last
568
522
  value = @stack.last.next_value
569
523
 
@@ -590,26 +544,24 @@ module Musa
590
544
  private_constant :Flattener
591
545
 
592
546
  class MergeSerieOfSeries
593
- include Serie
594
-
595
- attr_reader :source
547
+ include Serie.with(source: true)
596
548
 
597
549
  def initialize(serie)
598
- @source = serie
599
- _restart false
600
-
601
- mark_regarding! @source
550
+ self.source = serie
551
+ init
602
552
  end
603
553
 
604
- def _restart(restart_sources = true)
605
- if restart_sources
606
- @source.restart
607
- @restart_each_serie = true
608
- end
554
+ private def _init
609
555
  @current_serie = nil
556
+ @restart_each_serie = false
557
+ end
558
+
559
+ private def _restart
560
+ @source.restart
561
+ @restart_each_serie = true
610
562
  end
611
563
 
612
- def _next_value
564
+ private def _next_value
613
565
  value = nil
614
566
 
615
567
  restart_current_serie_if_needed = false
@@ -646,27 +598,28 @@ module Musa
646
598
  private_constant :MergeSerieOfSeries
647
599
 
648
600
  class Processor
649
- include Musa::Extension::SmartProcBinder
650
- include Serie
651
-
652
- attr_reader :source
601
+ include Serie.with(source: true, smart_block: true)
653
602
 
654
603
  def initialize(serie, parameters, &processor)
655
- @source = serie
656
- @parameters = parameters
657
- @processor = SmartProcBinder.new(processor)
604
+ self.source = serie
658
605
 
659
- _restart false
606
+ self.parameters = parameters
607
+ self.proc = processor if processor
660
608
 
661
- mark_regarding! @source
609
+ init
662
610
  end
663
611
 
664
- def _restart(restart_source = true)
665
- @source.restart if restart_source
612
+ attr_accessor :parameters
613
+
614
+ private def _init
666
615
  @pending_values = []
667
616
  end
668
617
 
669
- def _next_value
618
+ private def _restart
619
+ @source.restart
620
+ end
621
+
622
+ private def _next_value
670
623
  if @pending_values.empty?
671
624
 
672
625
  v = @source.next_value
@@ -674,7 +627,7 @@ module Musa
674
627
  if v.nil?
675
628
  nil
676
629
  else
677
- value = @processor.call(v, **@parameters)
630
+ value = @block.call(v, **@parameters)
678
631
 
679
632
  if value.is_a?(Array)
680
633
  @pending_values = value
@@ -700,23 +653,22 @@ module Musa
700
653
  end
701
654
 
702
655
  class Autorestart
703
- include Serie
704
-
705
- attr_reader :source
656
+ include Serie.with(source: true)
706
657
 
707
658
  def initialize(serie)
708
- @source = serie
659
+ self.source = serie
660
+ init
661
+ end
709
662
 
663
+ private def _init
710
664
  @restart_on_next = false
711
-
712
- mark_regarding! @source
713
665
  end
714
666
 
715
- def _restart
667
+ private def _restart
716
668
  @source.restart
717
669
  end
718
670
 
719
- def _next_value
671
+ private def _next_value
720
672
  if @restart_on_next
721
673
  @source.restart
722
674
  @restart_on_next = false
@@ -733,53 +685,59 @@ module Musa
733
685
  private_constant :Autorestart
734
686
 
735
687
  class Cutter
736
- include Serie
737
-
738
- attr_reader :source, :length
688
+ include Serie.with(source: true)
739
689
 
740
690
  def initialize(serie, length)
741
- @source = serie
742
- @length = length
691
+ self.source = serie
692
+ self.length = length
693
+ init
694
+ end
743
695
 
744
- mark_regarding! @source
696
+ def source=(serie)
697
+ super
698
+ @previous&.source = serie
745
699
  end
746
700
 
747
- def _restart
748
- @source.restart
701
+ attr_reader :length
702
+
703
+ def length=(value)
704
+ @length = value
705
+ @previous&.length = value
749
706
  end
750
707
 
751
- def _next_value
752
- @previous.materialize if @previous
708
+ private def _restart
709
+ @source.restart
710
+ end
753
711
 
712
+ private def _next_value
713
+ @previous&.materialize
754
714
  @previous = CutSerie.new @source, @length if @source.peek_next_value
755
715
  end
756
716
 
757
- private
758
-
759
717
  class CutSerie
760
- include Serie
718
+ include Serie.with(source: true)
761
719
 
762
720
  def initialize(serie, length)
763
- @source = serie
764
- @length = length
721
+ self.source = serie.instance
722
+ self.length = length
765
723
 
766
724
  @values = []
767
- _restart
768
-
769
- mark_as_instance!
725
+ init
770
726
  end
771
727
 
728
+ attr_accessor :length
729
+
772
730
  def _prototype!
773
731
  # TODO review why cannot get prototype of a cut serie
774
- raise PrototypingSerieError, 'Cannot get prototype of a cut serie'
732
+ raise PrototypingError, 'Cannot get prototype of a cut serie'
775
733
  end
776
734
 
777
- def _restart
735
+ private def _init
778
736
  @count = 0
779
737
  end
780
738
 
781
- def _next_value
782
- value ||= @values[@count]
739
+ private def _next_value
740
+ value = @values[@count]
783
741
  value ||= @values[@count] = @source.next_value if @count < @length
784
742
 
785
743
  @count += 1
@@ -791,30 +749,29 @@ module Musa
791
749
  (@values.size..@length - 1).each { |i| @values[i] = @source.next_value }
792
750
  end
793
751
  end
752
+
753
+ private_constant :CutSerie
794
754
  end
795
755
 
796
756
  private_constant :Cutter
797
757
 
798
758
  class Locker
799
- include Serie
800
-
801
- attr_reader :source
759
+ include Serie.with(source: true)
802
760
 
803
761
  def initialize(serie)
804
- @source = serie
762
+ self.source = serie
763
+
805
764
  @values = []
806
765
  @first_round = true
807
766
 
808
- _restart
809
-
810
- mark_regarding! @source
767
+ init
811
768
  end
812
769
 
813
- def _restart
770
+ private def _init
814
771
  @index = 0
815
772
  end
816
773
 
817
- def _next_value
774
+ private def _next_value
818
775
  if @first_round
819
776
  value = @source.next_value
820
777
 
@@ -836,34 +793,33 @@ module Musa
836
793
  private_constant :Locker
837
794
 
838
795
  class Reverser
839
- include Serie
840
-
841
- attr_reader :source
796
+ include Serie.with(source: true)
842
797
 
843
798
  def initialize(serie)
844
- @source = serie
845
- _restart false, false
846
-
847
- mark_regarding! @source
799
+ self.source = serie
800
+ init
848
801
  end
849
802
 
850
- def _instance!
803
+ def source=(serie)
804
+ raise ArgumentError, "A serie to reverse can't be infinite" if serie.infinite?
851
805
  super
852
- _restart false, true
806
+ init
853
807
  end
854
808
 
855
- def _restart(restart_sources = true, get_reversed = true)
856
- @source.restart if restart_sources
857
- @reversed = FromArray.new(next_values_array_of(@source).reverse).instance if get_reversed
809
+ private def _init
810
+ @reversed = nil
858
811
  end
859
812
 
860
- def _next_value
861
- @reversed.next_value
813
+ private def _restart
814
+ @source.restart
862
815
  end
863
816
 
864
- private
817
+ private def _next_value
818
+ @reversed ||= Constructors.S(*next_values_array_of(@source).reverse).instance
819
+ @reversed.next_value
820
+ end
865
821
 
866
- def next_values_array_of(serie)
822
+ private def next_values_array_of(serie)
867
823
  array = []
868
824
 
869
825
  until (value = serie.next_value).nil?
@@ -877,25 +833,27 @@ module Musa
877
833
  private_constant :Reverser
878
834
 
879
835
  class Randomizer
880
- include Serie
881
-
882
- attr_reader :source, :random
836
+ include Serie.with(source: true)
883
837
 
884
838
  def initialize(serie, random)
885
- @source = serie
886
- @random = random
839
+ self.source = serie
840
+ self.random = random
841
+
842
+ init
843
+ end
887
844
 
888
- _restart false
845
+ attr_accessor :random
889
846
 
890
- mark_regarding! @source
847
+ private def _init
848
+ @values = @source.to_a(duplicate: false, restart: false)
891
849
  end
892
850
 
893
- def _restart(restart_sources = true)
894
- @source.restart if restart_sources
895
- @values = @source.to_a
851
+ private def _restart
852
+ @source.restart
853
+ @values = @source.to_a(duplicate: false, restart: false)
896
854
  end
897
855
 
898
- def _next_value
856
+ private def _next_value
899
857
  if !@values.empty?
900
858
  position = @random.rand(0...@values.size)
901
859
  value = @values[position]
@@ -912,30 +870,46 @@ module Musa
912
870
  private_constant :Randomizer
913
871
 
914
872
  class Shifter
915
- include Serie
916
-
917
- attr_reader :source, :shift
873
+ include Serie.with(source: true)
918
874
 
919
875
  def initialize(serie, shift)
920
- raise ArgumentError, "cannot shift to right an infinite serie #{serie}" if shift > 0 && serie.infinite?
921
- raise ArgumentError, 'cannot shift to right: function not yet implemented' if shift > 0
922
-
923
- @source = serie
924
- @shift = shift
876
+ self.source = serie
877
+ self.shift = shift
925
878
 
926
- _restart false
879
+ init
880
+ end
927
881
 
928
- mark_regarding! @source
882
+ def source=(serie)
883
+ raise ArgumentError, "cannot shift to right an infinite serie" if @shift > 0 && serie.infinite?
884
+ super
885
+ # should _restart(false) ??? if so, we lost the shifted values of the previous serie; if not we don't shift the new serie values
886
+ # I think it's better to not _restart unless it's explicitly called by the caller
929
887
  end
930
888
 
931
- def _restart(restart_sources = true)
932
- @source.restart if restart_sources
889
+ attr_reader :shift
933
890
 
891
+ def shift=(value)
892
+ raise ArgumentError, "cannot shift to right an infinite serie" if value > 0 && @source&.infinite?
893
+ raise NotImplementedError, 'cannot shift to right: function not yet implemented' if value > 0
894
+
895
+ @shift = value
896
+ end
897
+
898
+ private def _init
934
899
  @shifted = []
935
- @shift.abs.times { @shifted << @source.next_value } if @shift < 0
900
+ @first = true
901
+ end
902
+
903
+ private def _restart
904
+ @source.restart
936
905
  end
937
906
 
938
- def _next_value
907
+ private def _next_value
908
+ if @first
909
+ @shift.abs.times { @shifted << @source.next_value } if @shift < 0
910
+ @first = false
911
+ end
912
+
939
913
  value = @source.next_value
940
914
  return value unless value.nil?
941
915
 
@@ -946,26 +920,26 @@ module Musa
946
920
  private_constant :Shifter
947
921
 
948
922
  class Remover
949
- include Serie
950
-
951
- attr_reader :source
923
+ include Serie.with(source: true, block: true)
952
924
 
953
925
  def initialize(serie, &block)
954
- @source = serie
955
- @block = block
956
- @history = []
926
+ self.source = serie
927
+ self.proc = block
957
928
 
958
- _restart false
929
+ @history = []
959
930
 
960
- mark_regarding! @source
931
+ init
961
932
  end
962
933
 
963
- def _restart(restart_sources = true)
964
- @source.restart if restart_sources
934
+ private def _init
965
935
  @history.clear
966
936
  end
967
937
 
968
- def _next_value
938
+ private def _restart
939
+ @source.restart
940
+ end
941
+
942
+ private def _next_value
969
943
  if value = @source.next_value
970
944
  while value && @block.call(value, @history)
971
945
  @history << value
@@ -980,24 +954,20 @@ module Musa
980
954
  private_constant :Remover
981
955
 
982
956
  class Selector
983
- include Serie
984
-
985
- attr_reader :source
957
+ include Serie.with(source: true, block: true)
986
958
 
987
959
  def initialize(serie, &block)
988
- @source = serie
989
- @block = block
960
+ self.source = serie
961
+ self.proc = block
990
962
 
991
- _restart false
992
-
993
- mark_regarding! @source
963
+ init
994
964
  end
995
965
 
996
- def _restart(restart_sources = true)
997
- @source.restart if restart_sources
966
+ private def _restart
967
+ @source.restart
998
968
  end
999
969
 
1000
- def _next_value
970
+ private def _next_value
1001
971
  value = @source.next_value
1002
972
  until value.nil? || @block.call(value)
1003
973
  value = @source.next_value
@@ -1009,23 +979,22 @@ module Musa
1009
979
  private_constant :Selector
1010
980
 
1011
981
  class HashFromSeriesArray
1012
- include Serie
1013
-
1014
- attr_reader :source, :keys
982
+ include Serie.with(source: true)
1015
983
 
1016
984
  def initialize(serie, keys)
1017
- @source = serie
1018
- @keys = keys
1019
- _restart false
985
+ self.source = serie
986
+ self.keys = keys
1020
987
 
1021
- mark_regarding! @source
988
+ init
1022
989
  end
1023
990
 
1024
- def _restart(restart_sources = true)
1025
- @source.restart if restart_sources
991
+ attr_accessor :keys
992
+
993
+ private def _restart
994
+ @source.restart
1026
995
  end
1027
996
 
1028
- def _next_value
997
+ private def _next_value
1029
998
  array = @source.next_value
1030
999
 
1031
1000
  return nil unless array
@@ -1041,6 +1010,45 @@ module Musa
1041
1010
  end
1042
1011
 
1043
1012
  private_constant :HashFromSeriesArray
1013
+
1014
+ class LazySerieEval
1015
+ include Serie.with(source: true, block: true)
1016
+
1017
+ def initialize(serie, &block)
1018
+ self.source = serie
1019
+ self.proc = block
1020
+
1021
+ init
1022
+ end
1023
+
1024
+ def source=(serie)
1025
+ super
1026
+ @processed = nil
1027
+ end
1028
+
1029
+ def proc(&block)
1030
+ super
1031
+ @processed = nil if block
1032
+ end
1033
+
1034
+ def proc=(block)
1035
+ super
1036
+ @processed = nil if block
1037
+ end
1038
+
1039
+ private def _restart
1040
+ @processed = nil
1041
+ @source.restart
1042
+ end
1043
+
1044
+ private def _next_value
1045
+ @processed ||= @block.call(@source)
1046
+ @processed.next_value
1047
+ end
1048
+ end
1049
+
1050
+ private_constant :LazySerieEval
1044
1051
  end
1052
+
1045
1053
  end
1046
1054
  end