musa-dsl 0.14.26 → 0.21.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -1
  3. data/Gemfile +0 -1
  4. data/README.md +5 -1
  5. data/lib/musa-dsl.rb +54 -11
  6. data/lib/musa-dsl/core-ext.rb +7 -13
  7. data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
  8. data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
  9. data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
  10. data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
  11. data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
  12. data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
  13. data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
  14. data/lib/musa-dsl/core-ext/with.rb +26 -0
  15. data/lib/musa-dsl/datasets.rb +8 -3
  16. data/lib/musa-dsl/datasets/dataset.rb +3 -0
  17. data/lib/musa-dsl/datasets/delta-d.rb +12 -0
  18. data/lib/musa-dsl/datasets/e.rb +61 -0
  19. data/lib/musa-dsl/datasets/gdv.rb +51 -411
  20. data/lib/musa-dsl/datasets/gdvd.rb +179 -0
  21. data/lib/musa-dsl/datasets/helper.rb +41 -0
  22. data/lib/musa-dsl/datasets/p.rb +68 -0
  23. data/lib/musa-dsl/datasets/packed-v.rb +19 -0
  24. data/lib/musa-dsl/datasets/pdv.rb +22 -15
  25. data/lib/musa-dsl/datasets/ps.rb +113 -0
  26. data/lib/musa-dsl/datasets/score.rb +210 -0
  27. data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
  28. data/lib/musa-dsl/datasets/score/render.rb +31 -0
  29. data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
  30. data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
  31. data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
  32. data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
  33. data/lib/musa-dsl/datasets/v.rb +23 -0
  34. data/lib/musa-dsl/generative.rb +5 -5
  35. data/lib/musa-dsl/generative/backboner.rb +274 -0
  36. data/lib/musa-dsl/generative/darwin.rb +102 -96
  37. data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
  38. data/lib/musa-dsl/generative/markov.rb +56 -53
  39. data/lib/musa-dsl/generative/variatio.rb +234 -222
  40. data/lib/musa-dsl/logger.rb +1 -0
  41. data/lib/musa-dsl/logger/logger.rb +31 -0
  42. data/lib/musa-dsl/matrix.rb +1 -0
  43. data/lib/musa-dsl/matrix/matrix.rb +210 -0
  44. data/lib/musa-dsl/midi.rb +2 -2
  45. data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
  46. data/lib/musa-dsl/midi/midi-voices.rb +183 -182
  47. data/lib/musa-dsl/music.rb +5 -5
  48. data/lib/musa-dsl/music/chord-definition.rb +54 -50
  49. data/lib/musa-dsl/music/chord-definitions.rb +13 -9
  50. data/lib/musa-dsl/music/chords.rb +236 -238
  51. data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
  52. data/lib/musa-dsl/music/scales.rb +331 -332
  53. data/lib/musa-dsl/musicxml.rb +1 -0
  54. data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
  55. data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
  56. data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
  57. data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
  58. data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
  59. data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
  60. data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
  61. data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
  62. data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
  63. data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
  64. data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
  65. data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
  66. data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
  67. data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
  68. data/lib/musa-dsl/neumalang.rb +1 -1
  69. data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
  70. data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
  71. data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
  72. data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
  73. data/lib/musa-dsl/neumalang/process.citrus +21 -0
  74. data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
  75. data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
  76. data/lib/musa-dsl/neumas.rb +5 -0
  77. data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
  78. data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
  79. data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
  80. data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
  81. data/lib/musa-dsl/neumas/neumas.rb +37 -0
  82. data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
  83. data/lib/musa-dsl/repl.rb +1 -1
  84. data/lib/musa-dsl/repl/repl.rb +105 -105
  85. data/lib/musa-dsl/sequencer.rb +1 -1
  86. data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
  87. data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
  88. data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +562 -270
  89. data/lib/musa-dsl/sequencer/base-sequencer-public.rb +199 -199
  90. data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +77 -0
  91. data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
  92. data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
  93. data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
  94. data/lib/musa-dsl/series.rb +1 -1
  95. data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
  96. data/lib/musa-dsl/series/base-series.rb +171 -168
  97. data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
  98. data/lib/musa-dsl/series/holder-serie.rb +1 -1
  99. data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
  100. data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
  101. data/lib/musa-dsl/series/proxy-serie.rb +6 -6
  102. data/lib/musa-dsl/series/queue-serie.rb +5 -5
  103. data/lib/musa-dsl/series/series.rb +2 -0
  104. data/lib/musa-dsl/transcription.rb +4 -0
  105. data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
  106. data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
  107. data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
  108. data/lib/musa-dsl/transcription/transcription.rb +55 -0
  109. data/lib/musa-dsl/transport.rb +6 -6
  110. data/lib/musa-dsl/transport/clock.rb +26 -26
  111. data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
  112. data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
  113. data/lib/musa-dsl/transport/input-midi-clock.rb +82 -80
  114. data/lib/musa-dsl/transport/timer-clock.rb +72 -71
  115. data/lib/musa-dsl/transport/timer.rb +28 -26
  116. data/lib/musa-dsl/transport/transport.rb +99 -95
  117. data/musa-dsl.gemspec +3 -3
  118. metadata +73 -24
  119. data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
  120. data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
  121. data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
  122. data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
  123. data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
  124. data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
  125. data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
  126. data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
  127. data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
  128. data/lib/musa-dsl/generative/rules.rb +0 -282
  129. data/lib/musa-dsl/neuma.rb +0 -1
  130. data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -0,0 +1,77 @@
1
+ module Musa
2
+ module Sequencer
3
+ class BaseSequencer
4
+ module TickBasedTiming
5
+
6
+ attr_reader :position, :ticks_per_bar, :tick_duration
7
+
8
+ def tick
9
+ if @hold_public_ticks
10
+ @hold_ticks += 1
11
+ else
12
+ _tick @position_mutex.synchronize { @position += @tick_duration }
13
+ end
14
+ end
15
+
16
+ def position=(new_position)
17
+ raise ArgumentError,
18
+ "Sequencer #{self}: cannot move back. current position: #{@position} new position: #{new_position}" \
19
+ if new_position < position
20
+
21
+ _hold_public_ticks
22
+ @on_fast_forward.each { |block| block.call(true) }
23
+
24
+ _tick(@position_mutex.synchronize { @position += @tick_duration }) while @position < new_position
25
+
26
+ @on_fast_forward.each { |block| block.call(false) }
27
+ _release_public_ticks
28
+ end
29
+
30
+ private
31
+
32
+ def _init_timing
33
+ @ticks_per_bar = Rational(beats_per_bar * ticks_per_beat)
34
+ @tick_duration = Rational(1, @ticks_per_bar)
35
+
36
+ @hold_public_ticks = false
37
+ @hold_ticks = 0
38
+ end
39
+
40
+ def _reset_timing
41
+ @position = @position_mutex.synchronize { 1r - @tick_duration }
42
+ end
43
+
44
+ def _check_position(position)
45
+ ticks_position = position / @tick_duration
46
+
47
+ if ticks_position.round != ticks_position
48
+ original_position = position
49
+ position = ticks_position.round * @tick_duration
50
+
51
+ if @do_log
52
+ _log "BaseSequencer._numeric_at: warning: rounding "\
53
+ "position #{position} (#{original_position.to_f.round(5)}) "\
54
+ "to tick precision: #{position} (#{position.to_f.round(5)})"
55
+ end
56
+ end
57
+
58
+ position
59
+ end
60
+
61
+ def _quantize(position)
62
+ (position / @tick_duration).round * @tick_duration
63
+ end
64
+
65
+ def _hold_public_ticks
66
+ @hold_public_ticks = true
67
+ end
68
+
69
+ def _release_public_ticks
70
+ @hold_ticks.times { _tick(@position_mutex.synchronize { @position += @tick_duration }) }
71
+ @hold_ticks = 0
72
+ @hold_public_ticks = false
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,75 @@
1
+ module Musa
2
+ module Sequencer
3
+ class BaseSequencer
4
+ module TicklessBasedTiming
5
+
6
+ attr_reader :position
7
+
8
+ def ticks_per_bar
9
+ Float::INFINITY
10
+ end
11
+
12
+ def tick_duration
13
+ 0r
14
+ end
15
+
16
+ # TODO implementar hold_public_ticks adaptado a modo tickless para permitir que una operación de asignación de
17
+ # TODO posición con .position = X, finalice antes de comenzar a procesar el resto de ticks en un contexto multithread.
18
+ # TODO pero tiene sentido cuando el modo tickless se usa SOLO con .run?
19
+ # TODO tendría sentido sólo si también se usa con ticks temporizados, lo cual ocurriría si se reimplementa el modo tickbased
20
+ # TODO a partir del modo tickless.
21
+
22
+ def tick
23
+ _tick @position_mutex.synchronize { @position = @timeslots.first_after(@position) }
24
+ end
25
+
26
+ # TODO puede pensarse que un sequencer tickbased es como un ticklessbased en que cada tick se aavanza el position en 1 / ticks_per_bar
27
+ # TODO esto haría que los eventos que cayeran en posiciones no cuantizadas por la resolución en ticks_per_bar se ejecutarían en el siguiente
28
+ # TODO lo cual sería una ventaja porque eliminaría la necesidad de cuantizar en el _at.
29
+ # TODO Por otro lado cuando se cuantiza en _at se redondea al más cercano, mientras que el modelo basado en avanzar redondea siempre hacia arriba,
30
+ # TODO pero esto podría resolverse con una opción de cuantización opcional que en _at ajustara la posición a la más cercana.
31
+
32
+ def position=(new_position)
33
+ raise ArgumentError, "Sequencer #{self}: cannot move back. current position: #{@position} new position: #{new_position}" if new_position < @position
34
+
35
+ @on_fast_forward.each { |block| block.call(true) }
36
+
37
+ loop do
38
+ next_position = nil
39
+
40
+ @position_mutex.synchronize do
41
+ next_position = @timeslots.first_after(@position)
42
+ end
43
+
44
+ if next_position <= new_position
45
+ _tick next_position
46
+ else
47
+ break
48
+ end
49
+ end
50
+
51
+ @position = new_position
52
+
53
+ @on_fast_forward.each { |block| block.call(false) }
54
+ end
55
+
56
+ private
57
+
58
+ def _init_timing
59
+ end
60
+
61
+ def _reset_timing
62
+ @position = nil
63
+ end
64
+
65
+ def _check_position(position)
66
+ position
67
+ end
68
+
69
+ def _quantize(position)
70
+ position
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
@@ -1,94 +1,114 @@
1
1
  require 'forwardable'
2
2
 
3
- class Musa::Sequencer
4
- extend Forwardable
5
-
6
- def_delegators :@sequencer, :raw_at, :tick, :on_debug_at, :on_block_error, :on_fast_forward, :before_tick
7
- def_delegators :@sequencer, :beats_per_bar, :ticks_per_beat, :ticks_per_bar, :tick_duration, :round, :position=, :size, :event_handler, :empty?
8
-
9
- def_delegators :@context, :position, :log
10
- def_delegators :@context, :with, :now, :at, :wait, :play, :every, :move
11
- def_delegators :@context, :everying, :playing, :moving
12
- def_delegators :@context, :launch, :on
13
-
14
- def initialize(beats_per_bar, ticks_per_beat, sequencer: nil, do_log: nil, &block)
15
- @sequencer ||= Musa::BaseSequencer.new beats_per_bar, ticks_per_beat, do_log: do_log
16
- @context = DSLContext.new @sequencer
17
-
18
- with &block if block
19
- end
20
-
21
- def reset
22
- @sequencer.reset
23
- end
24
-
25
- class DSLContext
26
- extend Forwardable
27
-
28
- attr_reader :sequencer
29
-
30
- def_delegators :@sequencer, :launch, :on,
31
- :position, :everying, :playing, :moving,
32
- :ticks_per_bar, :round, :log, :inspect
33
-
34
- def initialize(sequencer)
35
- @sequencer = sequencer
36
- end
37
-
38
- def with(*value_parameters, **key_parameters, &block)
39
- block ||= proc {}
40
-
41
- _as_context_run block, value_parameters, key_parameters
42
- end
43
-
44
- def now(*value_parameters, **key_parameters, &block)
45
- block ||= proc {}
46
-
47
- @sequencer.now *value_parameters, **key_parameters do |*value_args, **key_args|
48
- _as_context_run block, value_args, key_args
49
- end
50
- end
51
-
52
- def at(*value_parameters, **key_parameters, &block)
53
- block ||= proc {}
54
-
55
- @sequencer.at *value_parameters, **key_parameters do |*value_args, **key_args|
56
- _as_context_run block, value_args, key_args
57
- end
58
- end
59
-
60
- def wait(*value_parameters, **key_parameters, &block)
61
- block ||= proc {}
62
-
63
- @sequencer.wait *value_parameters, **key_parameters do | *values, **key_values |
64
- _as_context_run block, values, key_values
65
- end
66
- end
67
-
68
- def play(*value_parameters, **key_parameters, &block)
69
- block ||= proc {}
70
-
71
- @sequencer.play *value_parameters, **key_parameters do |*value_args, **key_args|
72
- _as_context_run block, value_args, key_args
3
+ require_relative '../core-ext/with'
4
+
5
+ module Musa
6
+ module Sequencer
7
+ class Sequencer
8
+ extend Forwardable
9
+
10
+ def_delegators :@sequencer,
11
+ :beats_per_bar, :ticks_per_beat, :ticks_per_bar, :tick_duration,
12
+ :size, :empty?,
13
+ :on_debug_at, :on_error, :on_fast_forward, :before_tick,
14
+ :raw_at,
15
+ :tick,
16
+ :reset,
17
+ :position=,
18
+ :event_handler
19
+
20
+ def_delegators :@context, :position, :logger, :debug
21
+ def_delegators :@context, :with, :now, :at, :wait, :play, :every, :move
22
+ def_delegators :@context, :everying, :playing, :moving
23
+ def_delegators :@context, :launch, :on
24
+ def_delegators :@context, :run
25
+
26
+ def initialize(beats_per_bar, ticks_per_beat,
27
+ sequencer: nil,
28
+ logger: nil,
29
+ do_log: nil, do_error_log: nil, log_position_format: nil,
30
+ &block)
31
+
32
+ @sequencer = sequencer
33
+ @sequencer ||= BaseSequencer.new beats_per_bar, ticks_per_beat,
34
+ logger: logger,
35
+ do_log: do_log,
36
+ do_error_log: do_error_log,
37
+ log_position_format: log_position_format
38
+
39
+ @context = DSLContext.new @sequencer
40
+
41
+ with &block if block_given?
73
42
  end
74
- end
75
43
 
76
- def every(*value_parameters, **key_parameters, &block)
77
- block ||= proc {}
78
-
79
- @sequencer.every *value_parameters, **key_parameters do |*value_args, **key_args|
80
- _as_context_run block, value_args, KeyParametersProcedureBinder.new(block).apply(key_args)
44
+ class DSLContext
45
+ extend Forwardable
46
+ include Musa::Extension::SmartProcBinder
47
+ include Musa::Extension::With
48
+
49
+ attr_reader :sequencer
50
+
51
+ def_delegators :@sequencer,
52
+ :launch, :on,
53
+ :position, :size, :everying, :playing, :moving,
54
+ :ticks_per_bar, :logger, :debug, :inspect,
55
+ :run
56
+
57
+ def initialize(sequencer)
58
+ @sequencer = sequencer
59
+ end
60
+
61
+ def now(*value_parameters, **key_parameters, &block)
62
+ block ||= proc {}
63
+
64
+ @sequencer.now *value_parameters, **key_parameters do |*value_args, **key_args|
65
+ with *value_args, **key_args, &block
66
+ end
67
+ end
68
+
69
+ def at(*value_parameters, **key_parameters, &block)
70
+ block ||= proc {}
71
+
72
+ @sequencer.at *value_parameters, **key_parameters do |*value_args, **key_args|
73
+ with *value_args, **key_args, &block
74
+ end
75
+ end
76
+
77
+ def wait(*value_parameters, **key_parameters, &block)
78
+ block ||= proc {}
79
+ @sequencer.wait *value_parameters, **key_parameters do | *values, **key_values |
80
+ with *values, **key_values, &block
81
+ end
82
+ end
83
+
84
+ def play(*value_parameters, **key_parameters, &block)
85
+ block ||= proc {}
86
+
87
+ @sequencer.play *value_parameters, **key_parameters do |*value_args, **key_args|
88
+ with *value_args, **key_args, &block
89
+ end
90
+ end
91
+
92
+ def every(*value_parameters, **key_parameters, &block)
93
+ block ||= proc {}
94
+
95
+ @sequencer.every *value_parameters, **key_parameters do |*value_args, **key_args|
96
+ args = SmartProcBinder.new(block)._apply(value_args, key_args)
97
+ with *args.first, **args.last, &block
98
+ end
99
+ end
100
+
101
+ def move(*value_parameters, **key_parameters, &block)
102
+ block ||= proc {}
103
+
104
+ @sequencer.move *value_parameters, **key_parameters do |*value_args, **key_args|
105
+ with *value_args, **key_args, &block
106
+ end
107
+ end
81
108
  end
82
- end
83
109
 
84
- def move(*value_parameters, **key_parameters, &block)
85
- block ||= proc {}
86
-
87
- @sequencer.move *value_parameters, **key_parameters do |*value_args, **key_args|
88
- _as_context_run block, value_args, key_args
89
- end
110
+ private_constant :DSLContext
90
111
  end
91
112
  end
92
-
93
- private_constant :DSLContext
94
113
  end
114
+
@@ -0,0 +1,34 @@
1
+ require 'set'
2
+
3
+ module Musa
4
+ module Sequencer
5
+ class BaseSequencer
6
+ class Timeslots < Hash
7
+
8
+ def initialize(*several_variants)
9
+ super
10
+ @sorted_keys = SortedSet.new
11
+ end
12
+
13
+ def []=(key, value)
14
+ super
15
+ @sorted_keys << key
16
+ end
17
+
18
+ def delete(key)
19
+ super
20
+ @sorted_keys.delete key
21
+
22
+ end
23
+
24
+ def first_after(position)
25
+ if position.nil?
26
+ @sorted_keys.first
27
+ else
28
+ @sorted_keys.find { |k| k >= position }
29
+ end
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -1 +1 @@
1
- require 'musa-dsl/series/series'
1
+ require_relative 'series/series'
@@ -1,4 +1,4 @@
1
- require 'musa-dsl/series'
1
+ require_relative '../series'
2
2
 
3
3
  class Array
4
4
  def to_serie(of_series: nil, recursive: nil)
@@ -1,245 +1,248 @@
1
- require 'musa-dsl/core-ext/duplicate'
2
- require 'musa-dsl/generative/generative-grammar'
1
+ require_relative '../core-ext/deep-copy'
2
+ require_relative '../generative/generative-grammar'
3
+
4
+ using Musa::Extension::DeepCopy
3
5
 
4
6
  module Musa
5
- module SerieOperations end
7
+ module Series
8
+ module SerieOperations end
6
9
 
7
- module SeriePrototyping
8
- def prototype?
9
- @is_instance ? false : true
10
- end
10
+ module SeriePrototyping
11
+ def prototype?
12
+ @is_instance ? false : true
13
+ end
11
14
 
12
- def instance?
13
- @is_instance ? true : false
14
- end
15
+ def instance?
16
+ @is_instance ? true : false
17
+ end
15
18
 
16
- def prototype
17
- if @is_instance
18
- @instance_of || (@instance_of = clone.tap(&:_prototype).mark_as_prototype!)
19
- else
20
- self
19
+ def prototype
20
+ if @is_instance
21
+ @instance_of || (@instance_of = clone.tap(&:_prototype).mark_as_prototype!)
22
+ else
23
+ self
24
+ end
21
25
  end
22
- end
23
26
 
24
- def _prototype
25
- nil
26
- end
27
+ def _prototype
28
+ nil
29
+ end
27
30
 
28
- alias_method :p, :prototype
31
+ alias_method :p, :prototype
29
32
 
30
- def mark_as_prototype!
31
- @is_instance = nil
32
- freeze
33
- end
33
+ def mark_as_prototype!
34
+ @is_instance = nil
35
+ freeze
36
+ end
34
37
 
35
- protected :_prototype, :mark_as_prototype!
38
+ protected :_prototype, :mark_as_prototype!
36
39
 
37
- def mark_regarding!(source)
38
- if source.prototype?
39
- mark_as_prototype!
40
- else
41
- mark_as_instance!
40
+ def mark_regarding!(source)
41
+ if source.prototype?
42
+ mark_as_prototype!
43
+ else
44
+ mark_as_instance!
45
+ end
42
46
  end
43
- end
44
47
 
45
- protected :mark_regarding!
48
+ protected :mark_regarding!
46
49
 
47
- def instance
48
- if @is_instance
49
- self
50
- else
51
- clone(freeze: false).tap(&:_instance).mark_as_instance!(self)
50
+ def instance
51
+ if @is_instance
52
+ self
53
+ else
54
+ clone(freeze: false).tap(&:_instance).mark_as_instance!(self)
55
+ end
52
56
  end
53
- end
54
57
 
55
- alias_method :i, :instance
58
+ alias_method :i, :instance
56
59
 
57
- def _instance
58
- nil
59
- end
60
+ def _instance
61
+ nil
62
+ end
60
63
 
61
- def mark_as_instance!(prototype = nil)
62
- @instance_of = prototype
63
- @is_instance = true
64
- self
65
- end
64
+ def mark_as_instance!(prototype = nil)
65
+ @instance_of = prototype
66
+ @is_instance = true
67
+ self
68
+ end
66
69
 
67
- protected :_instance, :mark_as_instance!
70
+ protected :_instance, :mark_as_instance!
68
71
 
69
- class PrototypingSerieError < RuntimeError
70
- def initialize(message = nil)
71
- message ||= 'This serie is a prototype serie: cannot be consumed. To consume the serie use an instance serie via .instance method'
72
- super message
72
+ class PrototypingSerieError < RuntimeError
73
+ def initialize(message = nil)
74
+ message ||= 'This serie is a prototype serie: cannot be consumed. To consume the serie use an instance serie via .instance method'
75
+ super message
76
+ end
73
77
  end
74
78
  end
75
- end
76
79
 
77
- module Serie
78
- include SeriePrototyping
79
- include SerieOperations
80
+ module Serie
81
+ include SeriePrototyping
82
+ include SerieOperations
80
83
 
81
- def restart
82
- raise PrototypingSerieError unless @is_instance
84
+ def restart
85
+ raise PrototypingSerieError unless @is_instance
83
86
 
84
- @_have_peeked_next_value = false
85
- @_peeked_next_value = nil
86
- @_have_current_value = false
87
- @_current_value = nil
87
+ @_have_peeked_next_value = false
88
+ @_peeked_next_value = nil
89
+ @_have_current_value = false
90
+ @_current_value = nil
88
91
 
89
- _restart if respond_to? :_restart
92
+ _restart if respond_to? :_restart
90
93
 
91
- self
92
- end
94
+ self
95
+ end
93
96
 
94
- def next_value
95
- raise PrototypingSerieError unless @is_instance
97
+ def next_value
98
+ raise PrototypingSerieError unless @is_instance
96
99
 
97
- unless @_have_current_value && @_current_value.nil?
98
- if @_have_peeked_next_value
99
- @_have_peeked_next_value = false
100
- @_current_value = @_peeked_next_value
101
- else
102
- @_current_value = _next_value
100
+ unless @_have_current_value && @_current_value.nil?
101
+ if @_have_peeked_next_value
102
+ @_have_peeked_next_value = false
103
+ @_current_value = @_peeked_next_value
104
+ else
105
+ @_current_value = _next_value
106
+ end
103
107
  end
104
- end
105
108
 
106
- propagate_value @_current_value
109
+ propagate_value @_current_value
107
110
 
108
- @_current_value
109
- end
111
+ @_current_value
112
+ end
110
113
 
111
- alias_method :v, :next_value
114
+ alias_method :v, :next_value
112
115
 
113
- def peek_next_value
114
- raise PrototypingSerieError unless @is_instance
116
+ def peek_next_value
117
+ raise PrototypingSerieError unless @is_instance
115
118
 
116
- unless @_have_peeked_next_value
117
- @_have_peeked_next_value = true
118
- @_peeked_next_value = _next_value
119
+ unless @_have_peeked_next_value
120
+ @_have_peeked_next_value = true
121
+ @_peeked_next_value = _next_value
122
+ end
123
+
124
+ @_peeked_next_value
119
125
  end
120
126
 
121
- @_peeked_next_value
122
- end
127
+ def current_value
128
+ raise PrototypingSerieError unless @is_instance
123
129
 
124
- def current_value
125
- raise PrototypingSerieError unless @is_instance
130
+ @_current_value
131
+ end
126
132
 
127
- @_current_value
128
- end
133
+ def infinite?
134
+ false
135
+ end
129
136
 
130
- def infinite?
131
- false
132
- end
137
+ def to_a(recursive: nil, duplicate: nil, restart: nil, dr: nil)
138
+ recursive ||= false
133
139
 
134
- def to_a(recursive: nil, duplicate: nil, restart: nil, dr: nil)
135
- recursive ||= false
140
+ dr ||= instance?
136
141
 
137
- dr ||= instance?
142
+ duplicate = dr if duplicate.nil?
143
+ restart = dr if restart.nil?
138
144
 
139
- duplicate = dr if duplicate.nil?
140
- restart = dr if restart.nil?
145
+ raise 'Cannot convert to array an infinite serie' if infinite?
141
146
 
142
- raise 'Cannot convert to array an infinite serie' if infinite?
147
+ array = []
143
148
 
144
- array = []
149
+ serie = instance
145
150
 
146
- serie = instance
151
+ serie = serie.clone(deep: true) if duplicate
152
+ serie = serie.restart if restart
147
153
 
148
- serie = serie.duplicate if duplicate
149
- serie = serie.restart if restart
154
+ while value = serie.next_value
155
+ array << if recursive
156
+ process_for_to_a(value)
157
+ else
158
+ value
159
+ end
160
+ end
150
161
 
151
- while value = serie.next_value
152
- array << if recursive
153
- process_for_to_a(value)
154
- else
155
- value
156
- end
162
+ array
157
163
  end
158
164
 
159
- array
160
- end
165
+ alias_method :a, :to_a
161
166
 
162
- alias_method :a, :to_a
163
-
164
- def to_node(**attributes)
165
- Nodificator.to_node(self, **attributes)
166
- end
167
+ def to_node(**attributes)
168
+ Nodificator.to_node(self, **attributes)
169
+ end
167
170
 
168
- alias_method :node, :to_node
171
+ alias_method :node, :to_node
169
172
 
170
- class Nodificator
171
- extend Musa::GenerativeGrammar
173
+ class Nodificator
174
+ extend Musa::GenerativeGrammar
172
175
 
173
- def self.to_node(serie, **attributes)
174
- N(serie, **attributes)
176
+ def self.to_node(serie, **attributes)
177
+ N(serie, **attributes)
178
+ end
175
179
  end
176
- end
177
180
 
178
- private_constant :Nodificator
181
+ private_constant :Nodificator
179
182
 
180
- protected
183
+ protected
181
184
 
182
- def propagate_value(value)
183
- @_slaves.each { |s| s.push_next_value value } if @_slaves
184
- end
185
+ def propagate_value(value)
186
+ @_slaves.each { |s| s.push_next_value value } if @_slaves
187
+ end
185
188
 
186
- private
187
-
188
- def process_for_to_a(value)
189
- case value
190
- when Serie
191
- value.to_a(recursive: true, restart: false, duplicate: false)
192
- when Array
193
- a = value.clone
194
- a.collect! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
195
- when Hash
196
- h = value.clone
197
- h.transform_values! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
198
- else
199
- value
189
+ private
190
+
191
+ def process_for_to_a(value)
192
+ case value
193
+ when Serie
194
+ value.to_a(recursive: true, restart: false, duplicate: false)
195
+ when Array
196
+ a = value.clone
197
+ a.collect! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
198
+ when Hash
199
+ h = value.clone
200
+ h.transform_values! { |v| v.is_a?(Serie) ? v.to_a(recursive: true, restart: false, duplicate: false) : process_for_to_a(v) }
201
+ else
202
+ value
203
+ end
200
204
  end
201
205
  end
202
206
 
203
- end
207
+ class Slave
208
+ include Serie
204
209
 
205
- class Slave
206
- include Serie
210
+ attr_reader :master
207
211
 
208
- attr_reader :master
209
-
210
- def initialize(master)
211
- @master = master
212
- @next_value = []
213
- end
212
+ def initialize(master)
213
+ @master = master
214
+ @next_value = []
215
+ end
214
216
 
215
- def _restart
216
- throw OperationNotAllowedError, "SlaveSerie #{self}: slave series cannot be restarted"
217
- end
217
+ def _restart
218
+ throw OperationNotAllowedError, "SlaveSerie #{self}: slave series cannot be restarted"
219
+ end
218
220
 
219
- def next_value
220
- value = @next_value.shift
221
+ def next_value
222
+ value = @next_value.shift
221
223
 
222
- raise "Warning: slave serie #{self} has lost sync with his master serie #{@master}" if value.nil? && !@master.peek_next_value.nil?
224
+ raise "Warning: slave serie #{self} has lost sync with his master serie #{@master}" if value.nil? && !@master.peek_next_value.nil?
223
225
 
224
- propagate_value value
226
+ propagate_value value
225
227
 
226
- value
227
- end
228
+ value
229
+ end
228
230
 
229
- def peek_next_value
230
- value = @next_value.first
231
+ def peek_next_value
232
+ value = @next_value.first
231
233
 
232
- raise "Warning: slave serie #{self} has lost sync with his master serie #{@master}" if value.nil? && !@master.peek_next_value.nil?
234
+ raise "Warning: slave serie #{self} has lost sync with his master serie #{@master}" if value.nil? && !@master.peek_next_value.nil?
233
235
 
234
- value
235
- end
236
+ value
237
+ end
236
238
 
237
- def infinite?
238
- @master.infinite?
239
- end
239
+ def infinite?
240
+ @master.infinite?
241
+ end
240
242
 
241
- def push_next_value(value)
242
- @next_value << value
243
+ def push_next_value(value)
244
+ @next_value << value
245
+ end
243
246
  end
244
247
  end
245
248
  end