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.
@@ -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