musa-dsl 0.14.16

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.
Files changed (72) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +10 -0
  3. data/Gemfile +20 -0
  4. data/LICENSE.md +157 -0
  5. data/README.md +8 -0
  6. data/lib/musa-dsl/core-ext/array-apply-get.rb +18 -0
  7. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +29 -0
  8. data/lib/musa-dsl/core-ext/array-to-neumas.rb +28 -0
  9. data/lib/musa-dsl/core-ext/array-to-serie.rb +20 -0
  10. data/lib/musa-dsl/core-ext/arrayfy.rb +15 -0
  11. data/lib/musa-dsl/core-ext/as-context-run.rb +44 -0
  12. data/lib/musa-dsl/core-ext/duplicate.rb +134 -0
  13. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +55 -0
  14. data/lib/musa-dsl/core-ext/inspect-nice.rb +28 -0
  15. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +85 -0
  16. data/lib/musa-dsl/core-ext/proc-nice.rb +13 -0
  17. data/lib/musa-dsl/core-ext/send-nice.rb +21 -0
  18. data/lib/musa-dsl/core-ext/string-to-neumas.rb +27 -0
  19. data/lib/musa-dsl/core-ext.rb +13 -0
  20. data/lib/musa-dsl/datasets/gdv-decorators.rb +221 -0
  21. data/lib/musa-dsl/datasets/gdv.rb +499 -0
  22. data/lib/musa-dsl/datasets/pdv.rb +44 -0
  23. data/lib/musa-dsl/datasets.rb +5 -0
  24. data/lib/musa-dsl/generative/darwin.rb +145 -0
  25. data/lib/musa-dsl/generative/generative-grammar.rb +294 -0
  26. data/lib/musa-dsl/generative/markov.rb +78 -0
  27. data/lib/musa-dsl/generative/rules.rb +282 -0
  28. data/lib/musa-dsl/generative/variatio.rb +331 -0
  29. data/lib/musa-dsl/generative.rb +5 -0
  30. data/lib/musa-dsl/midi/midi-recorder.rb +83 -0
  31. data/lib/musa-dsl/midi/midi-voices.rb +274 -0
  32. data/lib/musa-dsl/midi.rb +2 -0
  33. data/lib/musa-dsl/music/chord-definition.rb +99 -0
  34. data/lib/musa-dsl/music/chord-definitions.rb +13 -0
  35. data/lib/musa-dsl/music/chords.rb +326 -0
  36. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +204 -0
  37. data/lib/musa-dsl/music/scales.rb +584 -0
  38. data/lib/musa-dsl/music.rb +6 -0
  39. data/lib/musa-dsl/neuma/neuma.rb +181 -0
  40. data/lib/musa-dsl/neuma.rb +1 -0
  41. data/lib/musa-dsl/neumalang/neumalang.citrus +294 -0
  42. data/lib/musa-dsl/neumalang/neumalang.rb +179 -0
  43. data/lib/musa-dsl/neumalang.rb +3 -0
  44. data/lib/musa-dsl/repl/repl.rb +143 -0
  45. data/lib/musa-dsl/repl.rb +1 -0
  46. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +189 -0
  47. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +354 -0
  48. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +382 -0
  49. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +261 -0
  50. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +94 -0
  51. data/lib/musa-dsl/sequencer/sequencer.rb +3 -0
  52. data/lib/musa-dsl/sequencer.rb +1 -0
  53. data/lib/musa-dsl/series/base-series.rb +245 -0
  54. data/lib/musa-dsl/series/hash-serie-splitter.rb +194 -0
  55. data/lib/musa-dsl/series/holder-serie.rb +87 -0
  56. data/lib/musa-dsl/series/main-serie-constructors.rb +726 -0
  57. data/lib/musa-dsl/series/main-serie-operations.rb +1151 -0
  58. data/lib/musa-dsl/series/proxy-serie.rb +69 -0
  59. data/lib/musa-dsl/series/queue-serie.rb +94 -0
  60. data/lib/musa-dsl/series/series.rb +8 -0
  61. data/lib/musa-dsl/series.rb +1 -0
  62. data/lib/musa-dsl/transport/clock.rb +36 -0
  63. data/lib/musa-dsl/transport/dummy-clock.rb +47 -0
  64. data/lib/musa-dsl/transport/external-tick-clock.rb +31 -0
  65. data/lib/musa-dsl/transport/input-midi-clock.rb +124 -0
  66. data/lib/musa-dsl/transport/timer-clock.rb +102 -0
  67. data/lib/musa-dsl/transport/timer.rb +40 -0
  68. data/lib/musa-dsl/transport/transport.rb +137 -0
  69. data/lib/musa-dsl/transport.rb +9 -0
  70. data/lib/musa-dsl.rb +17 -0
  71. data/musa-dsl.gemspec +17 -0
  72. metadata +174 -0
@@ -0,0 +1,1151 @@
1
+ module Musa
2
+ module SerieOperations
3
+
4
+ def autorestart
5
+ Autorestart.new self
6
+ end
7
+
8
+ def repeat(times = nil, condition: nil, &condition_block)
9
+ condition ||= condition_block
10
+
11
+ if times || condition
12
+ Repeater.new self, times, &condition
13
+ else
14
+ InfiniteRepeater.new self
15
+ end
16
+ end
17
+
18
+ def max_size(length)
19
+ LengthLimiter.new self, length
20
+ end
21
+
22
+ def skip(length)
23
+ Skipper.new self, length
24
+ end
25
+
26
+ def flatten
27
+ Flattener.new self
28
+ end
29
+
30
+ def process_with(**parameters, &processor)
31
+ Processor.new self, parameters, &processor
32
+ end
33
+
34
+ # TODO: test case
35
+ def hashify(*keys)
36
+ HashFromSeriesArray.new self, keys
37
+ end
38
+
39
+ # TODO: test case
40
+ def shift(shift)
41
+ Shifter.new self, shift
42
+ end
43
+
44
+ # TODO: test case
45
+ def lock
46
+ Locker.new self
47
+ end
48
+
49
+ # TODO: test case
50
+ def reverse
51
+ Reverser.new self
52
+ end
53
+
54
+ # TODO: test case
55
+ def randomize(random: nil)
56
+ random ||= Random.new
57
+ Randomizer.new self, random
58
+ end
59
+
60
+ def remove(block = nil, &yield_block)
61
+ # TODO make history an optional block parameter (via keyparametersprocedurebinder)
62
+ block ||= yield_block
63
+ Remover.new self, &block
64
+ end
65
+
66
+ def select(block = nil, &yield_block)
67
+ # TODO add optional history (via keyparametersprocedurebinder)
68
+ block ||= yield_block
69
+ Selector.new self, &block
70
+ end
71
+
72
+ # TODO: test case
73
+ def switch(*indexed_series, **hash_series)
74
+ Switcher.new self, indexed_series, hash_series
75
+ end
76
+
77
+ def multiplex(*indexed_series, **hash_series)
78
+ MultiplexSelector.new self, indexed_series, hash_series
79
+ end
80
+
81
+ # TODO: test case
82
+ def switch_serie(*indexed_series, **hash_series)
83
+ SwitchFullSerie.new self, indexed_series, hash_series
84
+ end
85
+
86
+ def after(*series)
87
+ Sequence.new [self, *series]
88
+ end
89
+
90
+ def +(other)
91
+ Sequence.new [self, other]
92
+ end
93
+
94
+ def cut(length)
95
+ Cutter.new self, length
96
+ end
97
+
98
+ def merge
99
+ MergeSerieOfSeries.new self
100
+ end
101
+
102
+ def with(block = nil, on_restart: nil, **with_series, &yield_block)
103
+ block ||= yield_block
104
+ ProcessWith.new self, with_series, on_restart, &block
105
+ end
106
+
107
+ alias_method :eval, :with
108
+
109
+ def map(&yield_block)
110
+ ProcessWith.new self, &yield_block
111
+ end
112
+
113
+ # TODO: test case
114
+ def slave
115
+ slave_serie = Slave.new self
116
+
117
+ @_slaves ||= []
118
+ @_slaves << slave_serie
119
+
120
+ slave_serie
121
+ end
122
+
123
+ ###
124
+ ### Implementation
125
+ ###
126
+
127
+ class ProcessWith
128
+ include Serie
129
+
130
+ attr_reader :source, :with_sources, :on_restart, :block
131
+
132
+ def initialize(serie, with_series = nil, on_restart = nil, &block)
133
+ @source = serie
134
+ @with_sources = with_series || {}
135
+ @on_restart = on_restart
136
+ @block = KeyParametersProcedureBinder.new(block) if block_given?
137
+
138
+ if @source.prototype?
139
+ @with_sources = @with_sources.transform_values { |s| s.prototype }
140
+ else
141
+ @with_sources = @with_sources.transform_values { |s| s.instance }
142
+ end
143
+
144
+ mark_regarding! @source
145
+ end
146
+
147
+ def _prototype
148
+ @source = @source.prototype
149
+ @with_sources = @with_sources.transform_values { |s| s.prototype }
150
+ end
151
+
152
+ def _instance
153
+ @source = @source.instance
154
+ @with_sources = @with_sources.transform_values { |s| s.instance }
155
+ end
156
+
157
+ def _restart
158
+ @source.restart
159
+ @with_sources.values.each { |s| s.restart }
160
+ @on_restart.call if @on_restart
161
+ end
162
+
163
+ def _next_value
164
+ main = @source.next_value
165
+ others = @with_sources.transform_values { |v| v.next_value }
166
+
167
+ value = nil
168
+
169
+ if main && !others.values.include?(nil)
170
+ if @block
171
+ value = @block._call([main], others)
172
+ else
173
+ value = [main, others]
174
+ end
175
+ end
176
+
177
+ value
178
+ end
179
+
180
+ def infinite?
181
+ @source.infinite? && !@with_sources.values.find { |s| !s.infinite? }
182
+ end
183
+ end
184
+
185
+ private_constant :ProcessWith
186
+
187
+ class Switcher
188
+ include Serie
189
+
190
+ attr_accessor :selector, :sources
191
+
192
+ def initialize(selector, indexed_series, hash_series)
193
+
194
+ @selector = selector
195
+ get = @selector.prototype? ? :prototype : :instance
196
+
197
+ if indexed_series && !indexed_series.empty?
198
+ @sources = indexed_series.collect(&get)
199
+ elsif hash_series && !hash_series.empty?
200
+ @sources = hash_series.clone.transform_values(&get)
201
+ end
202
+
203
+ if get == :_prototype
204
+ @sources.freeze
205
+ end
206
+
207
+ mark_regarding! @selector
208
+ end
209
+
210
+ def _prototype
211
+ @selector = @selector.prototype
212
+ @sources = @sources.collect(&:prototype).freeze if @sources.is_a? Array
213
+ @sources.transform_values(&:prototype).freeze if @sources.is_a? Hash
214
+ end
215
+
216
+ def _instance
217
+ @selector = @selector.instance
218
+ @sources = @sources.collect(&:instance) if @sources.is_a? Array
219
+ @sources.transform_values(&:_instance) if @sources.is_a? Hash
220
+ end
221
+
222
+ def _restart
223
+ @selector.restart
224
+ @sources.each(&:restart) if @sources.is_a? Array
225
+ @sources.each { |_key, serie| serie.restart } if @sources.is_a? Hash
226
+ end
227
+
228
+ def _next_value
229
+ value = nil
230
+
231
+ index_or_key = @selector.next_value
232
+
233
+ value = @sources[index_or_key].next_value unless index_or_key.nil?
234
+
235
+ value
236
+ end
237
+
238
+ def infinite?
239
+ @selector.infinite? && @sources.any? { |serie| serie.infinite? }
240
+ end
241
+ end
242
+
243
+ private_constant :Switcher
244
+
245
+ class MultiplexSelector
246
+ include Serie
247
+
248
+ attr_accessor :selector, :sources
249
+
250
+ def initialize(selector, indexed_series, hash_series)
251
+ @selector = selector
252
+ get = @selector.prototype? ? :prototype : :instance
253
+
254
+ if indexed_series && !indexed_series.empty?
255
+ @sources = indexed_series.collect(&get)
256
+ elsif hash_series && !hash_series.empty?
257
+ @sources = hash_series.clone.transform_values(&get)
258
+ end
259
+
260
+ _restart false
261
+
262
+ if get == :_prototype
263
+ @sources.freeze
264
+ end
265
+
266
+ mark_regarding! @selector
267
+ end
268
+
269
+ def _prototype
270
+ @selector = @selector.prototype
271
+ @sources = @sources.collect(&:prototype).freeze if @sources.is_a? Array
272
+ @sources.transform_values(&:prototype).freeze if @sources.is_a? Hash
273
+ end
274
+
275
+ def _instance
276
+ @selector = @selector.instance
277
+ @sources = @sources.collect(&:instance) if @sources.is_a? Array
278
+ @sources.transform_values(&:_instance) if @sources.is_a? Hash
279
+ end
280
+
281
+ def _restart(restart_sources = true)
282
+ @current_value = nil
283
+
284
+ if restart_sources
285
+ @selector.restart
286
+ @sources.each(&:restart) if @sources.is_a? Array
287
+ @sources.each { |_key, serie| serie.restart } if @sources.is_a? Hash
288
+ end
289
+
290
+ @first = true
291
+ end
292
+
293
+ def _next_value
294
+ @current_value =
295
+ if @first || !@current_value.nil?
296
+ @first = false
297
+ index_or_key = @selector.next_value
298
+ unless index_or_key.nil?
299
+ @sources.each(&:next_value)
300
+ @sources[index_or_key].current_value
301
+ end
302
+ end
303
+ end
304
+
305
+ def infinite?
306
+ @selector.infinite? && @sources.any? { |serie| serie.infinite? }
307
+ end
308
+ end
309
+
310
+ private_constant :MultiplexSelector
311
+
312
+ class SwitchFullSerie
313
+ include Serie
314
+
315
+ attr_accessor :selector, :sources
316
+
317
+ def initialize(selector, indexed_series, hash_series)
318
+ @selector = selector
319
+ get = @selector.prototype? ? :prototype : :instance
320
+
321
+ if indexed_series && !indexed_series.empty?
322
+ @sources = indexed_series.collect(&get)
323
+ elsif hash_series && !hash_series.empty?
324
+ @sources = hash_series.clone.transform_values(&get)
325
+ end
326
+
327
+ if get == :_prototype
328
+ @sources.freeze
329
+ end
330
+
331
+ mark_regarding! @selector
332
+ end
333
+
334
+ def _prototype
335
+ @selector = @selector.prototype
336
+ @sources = @sources.collect(&:prototype).freeze if @sources.is_a? Array
337
+ @sources.transform_values(&:prototype).freeze if @sources.is_a? Hash
338
+ end
339
+
340
+ def _instance
341
+ @selector = @selector.instance
342
+ @sources = @sources.collect(&:instance) if @sources.is_a? Array
343
+ @sources.transform_values(&:_instance) if @sources.is_a? Hash
344
+ end
345
+
346
+ def _restart
347
+ @selector.restart
348
+ @sources.each(&:restart)
349
+ end
350
+
351
+ def _next_value
352
+ value = nil
353
+
354
+ value = @sources[@index_or_key].next_value unless @index_or_key.nil?
355
+
356
+ if value.nil?
357
+ @index_or_key = @selector.next_value
358
+
359
+ value = next_value unless @index_or_key.nil?
360
+ end
361
+
362
+ value
363
+ end
364
+
365
+ def infinite?
366
+ !!(@selector.infinite? || @sources.find(&:infinite?))
367
+ end
368
+ end
369
+
370
+ private_constant :SwitchFullSerie
371
+
372
+ class InfiniteRepeater
373
+ include Serie
374
+
375
+ attr_reader :source
376
+
377
+ def initialize(serie)
378
+ @source = serie
379
+
380
+ mark_regarding! @source
381
+ end
382
+
383
+ def _prototype
384
+ @source = @source.prototype
385
+ end
386
+
387
+ def _instance
388
+ @source = @source.instance
389
+ end
390
+
391
+ def _restart
392
+ @source.restart
393
+ end
394
+
395
+ def _next_value
396
+ value = @source.next_value
397
+
398
+ if value.nil?
399
+ @source.restart
400
+ value = @source.next_value
401
+ end
402
+
403
+ value
404
+ end
405
+
406
+ def infinite?
407
+ true
408
+ end
409
+ end
410
+
411
+ private_constant :InfiniteRepeater
412
+
413
+ class Repeater
414
+ include Serie
415
+
416
+ attr_reader :source, :times, :condition
417
+
418
+ def initialize(serie, times = nil, &condition_block)
419
+ @source = serie
420
+
421
+ @times = times
422
+ @condition = condition_block
423
+
424
+ update_condition
425
+ _restart false
426
+
427
+ mark_regarding! @source
428
+ end
429
+
430
+ def _prototype
431
+ @source = @source.prototype
432
+ end
433
+
434
+ def _instance
435
+ @source = @source.instance
436
+ end
437
+
438
+ def _restart(restart_sources = true)
439
+ @count = 0
440
+ @source.restart if restart_sources
441
+ end
442
+
443
+ def _next_value
444
+ value = @source.next_value
445
+
446
+ if value.nil?
447
+ @count += 1
448
+
449
+ if instance_eval &@condition
450
+ @source.restart
451
+ value = @source.next_value
452
+ end
453
+ end
454
+
455
+ value
456
+ end
457
+
458
+ def infinite?
459
+ @source.infinite?
460
+ end
461
+
462
+ private
463
+
464
+ def update_condition
465
+ @condition = proc { @count < @times } if @times && !@condition
466
+ @condition ||= proc { false }
467
+ end
468
+ end
469
+
470
+ private_constant :Repeater
471
+
472
+ class LengthLimiter
473
+ include Serie
474
+
475
+ attr_reader :source, :length
476
+
477
+ def initialize(serie, length)
478
+ @source = serie
479
+ @length = length
480
+
481
+ _restart false
482
+
483
+ mark_regarding! @source
484
+ end
485
+
486
+ def _prototype
487
+ @source = @source.prototype
488
+ end
489
+
490
+ def _instance
491
+ @source = @source.instance
492
+ end
493
+
494
+ def _restart(restart_sources = true)
495
+ @position = 0
496
+ @source.restart if restart_sources
497
+ end
498
+
499
+ def _next_value
500
+ if @position < @length
501
+ @position += 1
502
+ @source.next_value
503
+ end
504
+ end
505
+
506
+ def infinite?
507
+ false
508
+ end
509
+ end
510
+
511
+ private_constant :LengthLimiter
512
+
513
+ class Skipper
514
+ include Serie
515
+
516
+ attr_reader :source, :length
517
+
518
+ def initialize(serie, length)
519
+ @source = serie
520
+ @length = length
521
+
522
+ _restart false
523
+
524
+ mark_regarding! @source
525
+ end
526
+
527
+ def _prototype
528
+ @source = @source.prototype
529
+ end
530
+
531
+ def _instance
532
+ @source = @source.instance
533
+ end
534
+
535
+ def _restart(restart_sources = true)
536
+ @source.restart if restart_sources
537
+ @first = true
538
+ end
539
+
540
+ def _next_value
541
+ @length.times { @source.next_value } if @first
542
+ @first = nil
543
+
544
+ @source.next_value
545
+ end
546
+
547
+ def infinite?
548
+ @source.infinite?
549
+ end
550
+ end
551
+
552
+ private_constant :Skipper
553
+
554
+ class Flattener
555
+ include Serie
556
+
557
+ attr_reader :source
558
+
559
+ def initialize(serie)
560
+ @source = serie
561
+
562
+ _restart false
563
+
564
+ mark_regarding! @source
565
+ end
566
+
567
+ def _prototype
568
+ @source = @source.prototype
569
+ _restart false
570
+ end
571
+
572
+ def _instance
573
+ @source = @source.instance
574
+ _restart false
575
+ end
576
+
577
+ def _restart(restart_sources = true)
578
+ if restart_sources
579
+ @source.restart
580
+ @restart_each_serie = true
581
+ else
582
+ @restart_each_serie = false
583
+ end
584
+
585
+ @stack = [@source]
586
+ end
587
+
588
+ def _next_value
589
+ if @stack.last
590
+ value = @stack.last.next_value
591
+
592
+ case value
593
+ when Serie
594
+ value = value.instance
595
+ value.restart if @restart_each_serie
596
+ @stack.push(value)
597
+ _next_value
598
+ when nil
599
+ @stack.pop
600
+ _next_value
601
+ else
602
+ value
603
+ end
604
+ end
605
+ end
606
+
607
+ def infinite?
608
+ @source.infinite? # TODO revisar porque las series hijas sí que pueden ser infinitas
609
+ end
610
+ end
611
+
612
+ private_constant :Flattener
613
+
614
+ class MergeSerieOfSeries
615
+ include Serie
616
+
617
+ attr_reader :source
618
+
619
+ def initialize(serie)
620
+ @source = serie
621
+ _restart false
622
+
623
+ mark_regarding! @source
624
+ end
625
+
626
+ def _prototype
627
+ @source = @source.prototype
628
+ end
629
+
630
+ def _instance
631
+ @source = @source.instance
632
+ end
633
+
634
+ def _restart(restart_sources = true)
635
+ if restart_sources
636
+ @source.restart
637
+ @restart_each_serie = true
638
+ end
639
+ @current_serie = nil
640
+ end
641
+
642
+ def _next_value
643
+ value = nil
644
+
645
+ restart_current_serie_if_needed = false
646
+
647
+ if @current_serie.nil?
648
+ @current_serie = @source.next_value
649
+ @current_serie = @current_serie.instance if @current_serie
650
+
651
+ if @restart_each_serie
652
+ @current_serie.restart if @current_serie
653
+ else
654
+ restart_current_serie_if_needed = true
655
+ end
656
+ end
657
+
658
+ if @current_serie
659
+ value = @current_serie.next_value
660
+
661
+ if value.nil?
662
+ if restart_current_serie_if_needed
663
+ @current_serie.restart
664
+ else
665
+ @current_serie = nil
666
+ end
667
+
668
+ value = _next_value
669
+ end
670
+ end
671
+
672
+ value
673
+ end
674
+ end
675
+
676
+ private_constant :MergeSerieOfSeries
677
+
678
+ class Processor
679
+ include Serie
680
+
681
+ attr_reader :source
682
+
683
+ def initialize(serie, parameters, &processor)
684
+ @source = serie
685
+ @parameters = parameters
686
+ @processor = KeyParametersProcedureBinder.new(processor)
687
+
688
+ _restart false
689
+
690
+ mark_regarding! @source
691
+ end
692
+
693
+ def _prototype
694
+ @source = @source.prototype
695
+ end
696
+
697
+ def _instance
698
+ @source = @source.instance
699
+ end
700
+
701
+ def _restart(restart_source = true)
702
+ @source.restart if restart_source
703
+ @pending_values = []
704
+ end
705
+
706
+ def _next_value
707
+ if @pending_values.empty?
708
+
709
+ v = @source.next_value
710
+
711
+ if v.nil?
712
+ nil
713
+ else
714
+ value = @processor.call(v, **@parameters)
715
+
716
+ if value.is_a?(Array)
717
+ @pending_values = value
718
+ value = _next_value
719
+ end
720
+
721
+ value
722
+ end
723
+ else
724
+ value = @pending_values.shift
725
+
726
+ if value.nil?
727
+ value = _next_value
728
+ end
729
+
730
+ value
731
+ end
732
+ end
733
+
734
+ def infinite?
735
+ @source.infinite?
736
+ end
737
+ end
738
+
739
+ class Autorestart
740
+ include Serie
741
+
742
+ attr_reader :source
743
+
744
+ def initialize(serie)
745
+ @source = serie
746
+
747
+ @restart_on_next = false
748
+
749
+ mark_regarding! @source
750
+ end
751
+
752
+ def _prototype
753
+ @source = @source.prototype
754
+ end
755
+
756
+ def _instance
757
+ @source = @source.instance
758
+ end
759
+
760
+ def _restart
761
+ @source.restart
762
+ end
763
+
764
+ def _next_value
765
+ if @restart_on_next
766
+ @source.restart
767
+ @restart_on_next = false
768
+ end
769
+
770
+ value = @source.next_value
771
+
772
+ @restart_on_next = value.nil?
773
+
774
+ value
775
+ end
776
+ end
777
+
778
+ private_constant :Autorestart
779
+
780
+ class Cutter
781
+ include Serie
782
+
783
+ attr_reader :source, :length
784
+
785
+ def initialize(serie, length)
786
+ @source = serie
787
+ @length = length
788
+
789
+ mark_regarding! @source
790
+ end
791
+
792
+ def _prototype
793
+ @source = @source.prototype
794
+ end
795
+
796
+ def _instance
797
+ @source = @source.instance
798
+ end
799
+
800
+ def _restart
801
+ @source.restart
802
+ end
803
+
804
+ def _next_value
805
+ @previous.materialize if @previous
806
+
807
+ @previous = CutSerie.new @source, @length if @source.peek_next_value
808
+ end
809
+
810
+ private
811
+
812
+ class CutSerie
813
+ include Serie
814
+
815
+ def initialize(serie, length)
816
+ @source = serie
817
+ @length = length
818
+
819
+ @values = []
820
+ _restart
821
+
822
+ mark_as_instance!
823
+ end
824
+
825
+ def _prototype
826
+ raise PrototypingSerieError, 'Cannot get prototype of a cut serie'
827
+ end
828
+
829
+ def _restart
830
+ @count = 0
831
+ end
832
+
833
+ def _next_value
834
+ value ||= @values[@count]
835
+ value ||= @values[@count] = @source.next_value if @count < @length
836
+
837
+ @count += 1
838
+
839
+ value
840
+ end
841
+
842
+ def materialize
843
+ (@values.size..@length - 1).each { |i| @values[i] = @source.next_value }
844
+ end
845
+ end
846
+ end
847
+
848
+ private_constant :Cutter
849
+
850
+ class Locker
851
+ include Serie
852
+
853
+ attr_reader :source
854
+
855
+ def initialize(serie)
856
+ @source = serie
857
+ @values = []
858
+ @first_round = true
859
+
860
+ _restart
861
+
862
+ mark_regarding! @source
863
+ end
864
+
865
+ def _prototype
866
+ @source = @source.prototype
867
+ end
868
+
869
+ def _instance
870
+ @source = @source.instance
871
+ end
872
+
873
+ def _restart
874
+ @index = 0
875
+ end
876
+
877
+ def _next_value
878
+ if @first_round
879
+ value = @source.next_value
880
+
881
+ @first_round = false if value.nil?
882
+ @values << value unless value.nil?
883
+ else
884
+ if @index < @values.size
885
+ value = @values[@index]
886
+ @index += 1
887
+ else
888
+ value = nil
889
+ end
890
+ end
891
+
892
+ value
893
+ end
894
+ end
895
+
896
+ private_constant :Locker
897
+
898
+ class Reverser
899
+ include Serie
900
+
901
+ attr_reader :source
902
+
903
+ def initialize(serie)
904
+ @source = serie
905
+ _restart false, false
906
+
907
+ mark_regarding! @source
908
+ end
909
+
910
+ def _prototype
911
+ @source = @source.prototype
912
+ end
913
+
914
+ def _instance
915
+ @source = @source.instance
916
+ _restart false, true
917
+ end
918
+
919
+ def _restart(restart_sources = true, get_reversed = true)
920
+ @source.restart if restart_sources
921
+ @reversed = FromArray.new(next_values_array_of(@source).reverse).instance if get_reversed
922
+ end
923
+
924
+ def _next_value
925
+ @reversed.next_value
926
+ end
927
+
928
+ private
929
+
930
+ def next_values_array_of(serie)
931
+ array = []
932
+
933
+ until (value = serie.next_value).nil?
934
+ array << value
935
+ end
936
+
937
+ array
938
+ end
939
+ end
940
+
941
+ private_constant :Reverser
942
+
943
+ class Randomizer
944
+ include Serie
945
+
946
+ attr_reader :source, :random
947
+
948
+ def initialize(serie, random)
949
+ @source = serie
950
+ @random = random
951
+
952
+ _restart false
953
+
954
+ mark_regarding! @source
955
+ end
956
+
957
+ def _prototype
958
+ @source = @source.prototype
959
+ end
960
+
961
+ def _instance
962
+ @source = @source.instance
963
+ end
964
+
965
+ def _restart(restart_sources = true)
966
+ @source.restart if restart_sources
967
+ @values = @source.to_a
968
+ end
969
+
970
+ def _next_value
971
+ _restart(false) if @needs_restart
972
+
973
+ if !@values.empty?
974
+ position = @random.rand(0...@values.size)
975
+ value = @values[position]
976
+
977
+ @values.delete_at position
978
+ else
979
+ value = nil
980
+ end
981
+
982
+ value
983
+ end
984
+ end
985
+
986
+ private_constant :Randomizer
987
+
988
+ class Shifter
989
+ include Serie
990
+
991
+ attr_reader :source, :shift
992
+
993
+ def initialize(serie, shift)
994
+ raise ArgumentError, "cannot shift to right an infinite serie #{serie}" if shift > 0 && serie.infinite?
995
+ raise ArgumentError, 'cannot shift to right: function not yet implemented' if shift > 0
996
+
997
+ @source = serie
998
+ @shift = shift
999
+
1000
+ _restart false
1001
+
1002
+ mark_regarding! @source
1003
+ end
1004
+
1005
+ def _prototype
1006
+ @source = @source.prototype
1007
+ end
1008
+
1009
+ def _instance
1010
+ @source = @source.instance
1011
+ end
1012
+
1013
+ def _restart(restart_sources = true)
1014
+ @source.restart if restart_sources
1015
+
1016
+ @shifted = []
1017
+ @shift.abs.times { @shifted << @source.next_value } if @shift < 0
1018
+ end
1019
+
1020
+ def _next_value
1021
+ value = @source.next_value
1022
+ return value unless value.nil?
1023
+
1024
+ @shifted.shift
1025
+ end
1026
+ end
1027
+
1028
+ private_constant :Shifter
1029
+
1030
+ class Remover
1031
+ include Serie
1032
+
1033
+ attr_reader :source
1034
+
1035
+ def initialize(serie, &block)
1036
+ @source = serie
1037
+ @block = block
1038
+ @history = []
1039
+
1040
+ _restart false
1041
+
1042
+ mark_regarding! @source
1043
+ end
1044
+
1045
+ def _prototype
1046
+ @source = @source.prototype
1047
+ end
1048
+
1049
+ def _instance
1050
+ @source = @source.instance
1051
+ end
1052
+
1053
+ def _restart(restart_sources = true)
1054
+ @source.restart if restart_sources
1055
+ @history.clear
1056
+ end
1057
+
1058
+ def _next_value
1059
+ if value = @source.next_value
1060
+ while @block.call(value, @history)
1061
+ @history << value
1062
+ value = @source.next_value
1063
+ end
1064
+ @history << value
1065
+ end
1066
+ value
1067
+ end
1068
+ end
1069
+
1070
+ private_constant :Remover
1071
+
1072
+ class Selector
1073
+ include Serie
1074
+
1075
+ attr_reader :source
1076
+
1077
+ def initialize(serie, &block)
1078
+ @source = serie
1079
+ @block = block
1080
+
1081
+ _restart false
1082
+
1083
+ mark_regarding! @source
1084
+ end
1085
+
1086
+ def _prototype
1087
+ @source = @source.prototype
1088
+ end
1089
+
1090
+ def _instance
1091
+ @source = @source.instance
1092
+ end
1093
+
1094
+ def _restart(restart_sources = true)
1095
+ @source.restart if restart_sources
1096
+ end
1097
+
1098
+ def _next_value
1099
+ value = @source.next_value
1100
+ until value.nil? || @block.call(value)
1101
+ value = @source.next_value
1102
+ end
1103
+ value
1104
+ end
1105
+ end
1106
+
1107
+ private_constant :Selector
1108
+
1109
+ class HashFromSeriesArray
1110
+ include Serie
1111
+
1112
+ attr_reader :source, :keys
1113
+
1114
+ def initialize(serie, keys)
1115
+ @source = serie
1116
+ @keys = keys
1117
+ _restart false
1118
+
1119
+ mark_regarding! @source
1120
+ end
1121
+
1122
+ def _prototype
1123
+ @source = @source.prototype
1124
+ end
1125
+
1126
+ def _instance
1127
+ @source = @source.instance
1128
+ end
1129
+
1130
+ def _restart(restart_sources = true)
1131
+ @source.restart if restart_sources
1132
+ end
1133
+
1134
+ def _next_value
1135
+ array = @source.next_value
1136
+
1137
+ return nil unless array
1138
+
1139
+ value = array.length.times.collect { |i| [@keys[i], array[i]] }.to_h
1140
+
1141
+ if value.find { |_key, value| value.nil? }
1142
+ nil
1143
+ else
1144
+ value
1145
+ end
1146
+ end
1147
+ end
1148
+
1149
+ private_constant :HashFromSeriesArray
1150
+ end
1151
+ end