musa-dsl 0.14.29 → 0.21.3
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +3 -1
- data/Gemfile +0 -1
- data/README.md +5 -1
- data/lib/musa-dsl.rb +54 -11
- data/lib/musa-dsl/core-ext.rb +7 -13
- data/lib/musa-dsl/core-ext/array-explode-ranges.rb +15 -23
- data/lib/musa-dsl/core-ext/arrayfy.rb +30 -12
- data/lib/musa-dsl/core-ext/attribute-builder.rb +194 -0
- data/lib/musa-dsl/core-ext/deep-copy.rb +185 -0
- data/lib/musa-dsl/core-ext/dynamic-proxy.rb +44 -40
- data/lib/musa-dsl/core-ext/inspect-nice.rb +40 -22
- data/lib/musa-dsl/core-ext/smart-proc-binder.rb +108 -0
- data/lib/musa-dsl/core-ext/with.rb +26 -0
- data/lib/musa-dsl/datasets.rb +8 -3
- data/lib/musa-dsl/datasets/dataset.rb +3 -0
- data/lib/musa-dsl/datasets/delta-d.rb +12 -0
- data/lib/musa-dsl/datasets/e.rb +61 -0
- data/lib/musa-dsl/datasets/gdv.rb +51 -411
- data/lib/musa-dsl/datasets/gdvd.rb +179 -0
- data/lib/musa-dsl/datasets/helper.rb +41 -0
- data/lib/musa-dsl/datasets/p.rb +68 -0
- data/lib/musa-dsl/datasets/packed-v.rb +19 -0
- data/lib/musa-dsl/datasets/pdv.rb +22 -15
- data/lib/musa-dsl/datasets/ps.rb +113 -0
- data/lib/musa-dsl/datasets/score.rb +210 -0
- data/lib/musa-dsl/datasets/score/queriable.rb +48 -0
- data/lib/musa-dsl/datasets/score/render.rb +31 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-pdv.rb +160 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-ps.rb +51 -0
- data/lib/musa-dsl/datasets/score/to-mxml/process-time.rb +153 -0
- data/lib/musa-dsl/datasets/score/to-mxml/to-mxml.rb +158 -0
- data/lib/musa-dsl/datasets/v.rb +23 -0
- data/lib/musa-dsl/generative.rb +5 -5
- data/lib/musa-dsl/generative/backboner.rb +274 -0
- data/lib/musa-dsl/generative/darwin.rb +102 -96
- data/lib/musa-dsl/generative/generative-grammar.rb +182 -187
- data/lib/musa-dsl/generative/markov.rb +56 -53
- data/lib/musa-dsl/generative/variatio.rb +234 -222
- data/lib/musa-dsl/logger.rb +1 -0
- data/lib/musa-dsl/logger/logger.rb +31 -0
- data/lib/musa-dsl/matrix.rb +1 -0
- data/lib/musa-dsl/matrix/matrix.rb +210 -0
- data/lib/musa-dsl/midi.rb +2 -2
- data/lib/musa-dsl/midi/midi-recorder.rb +54 -52
- data/lib/musa-dsl/midi/midi-voices.rb +187 -182
- data/lib/musa-dsl/music.rb +5 -5
- data/lib/musa-dsl/music/chord-definition.rb +54 -50
- data/lib/musa-dsl/music/chord-definitions.rb +13 -9
- data/lib/musa-dsl/music/chords.rb +236 -238
- data/lib/musa-dsl/music/equally-tempered-12-tone-scale-system.rb +187 -183
- data/lib/musa-dsl/music/scales.rb +331 -332
- data/lib/musa-dsl/musicxml.rb +1 -0
- data/lib/musa-dsl/musicxml/builder/attributes.rb +155 -0
- data/lib/musa-dsl/musicxml/builder/backup-forward.rb +45 -0
- data/lib/musa-dsl/musicxml/builder/direction.rb +322 -0
- data/lib/musa-dsl/musicxml/builder/helper.rb +90 -0
- data/lib/musa-dsl/musicxml/builder/measure.rb +137 -0
- data/lib/musa-dsl/musicxml/builder/note-complexities.rb +152 -0
- data/lib/musa-dsl/musicxml/builder/note.rb +577 -0
- data/lib/musa-dsl/musicxml/builder/part-group.rb +44 -0
- data/lib/musa-dsl/musicxml/builder/part.rb +67 -0
- data/lib/musa-dsl/musicxml/builder/pitched-note.rb +126 -0
- data/lib/musa-dsl/musicxml/builder/rest.rb +117 -0
- data/lib/musa-dsl/musicxml/builder/score-partwise.rb +120 -0
- data/lib/musa-dsl/musicxml/builder/typed-text.rb +43 -0
- data/lib/musa-dsl/musicxml/builder/unpitched-note.rb +112 -0
- data/lib/musa-dsl/neumalang.rb +1 -1
- data/lib/musa-dsl/neumalang/datatypes.citrus +79 -0
- data/lib/musa-dsl/neumalang/neuma.citrus +165 -0
- data/lib/musa-dsl/neumalang/neumalang.citrus +32 -242
- data/lib/musa-dsl/neumalang/neumalang.rb +373 -142
- data/lib/musa-dsl/neumalang/process.citrus +21 -0
- data/lib/musa-dsl/neumalang/terminals.citrus +67 -0
- data/lib/musa-dsl/neumalang/vectors.citrus +23 -0
- data/lib/musa-dsl/neumas.rb +5 -0
- data/lib/musa-dsl/neumas/array-to-neumas.rb +34 -0
- data/lib/musa-dsl/neumas/neuma-decoder.rb +63 -0
- data/lib/musa-dsl/neumas/neuma-gdv-decoder.rb +57 -0
- data/lib/musa-dsl/neumas/neuma-gdvd-decoder.rb +15 -0
- data/lib/musa-dsl/neumas/neumas.rb +37 -0
- data/lib/musa-dsl/neumas/string-to-neumas.rb +34 -0
- data/lib/musa-dsl/repl.rb +1 -1
- data/lib/musa-dsl/repl/repl.rb +128 -105
- data/lib/musa-dsl/sequencer.rb +1 -1
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-control.rb +163 -136
- data/lib/musa-dsl/sequencer/base-sequencer-implementation-play-helper.rb +301 -286
- data/lib/musa-dsl/sequencer/base-sequencer-implementation.rb +552 -308
- data/lib/musa-dsl/sequencer/base-sequencer-public.rb +198 -176
- data/lib/musa-dsl/sequencer/base-sequencer-tick-based.rb +77 -0
- data/lib/musa-dsl/sequencer/base-sequencer-tickless-based.rb +75 -0
- data/lib/musa-dsl/sequencer/sequencer-dsl.rb +105 -85
- data/lib/musa-dsl/sequencer/timeslots.rb +34 -0
- data/lib/musa-dsl/series.rb +1 -1
- data/lib/musa-dsl/{core-ext → series}/array-to-serie.rb +1 -1
- data/lib/musa-dsl/series/base-series.rb +171 -168
- data/lib/musa-dsl/series/hash-serie-splitter.rb +134 -132
- data/lib/musa-dsl/series/holder-serie.rb +1 -1
- data/lib/musa-dsl/series/main-serie-constructors.rb +6 -1
- data/lib/musa-dsl/series/main-serie-operations.rb +807 -797
- data/lib/musa-dsl/series/proxy-serie.rb +6 -6
- data/lib/musa-dsl/series/queue-serie.rb +5 -5
- data/lib/musa-dsl/series/series.rb +2 -0
- data/lib/musa-dsl/transcription.rb +4 -0
- data/lib/musa-dsl/transcription/from-gdv-to-midi.rb +227 -0
- data/lib/musa-dsl/transcription/from-gdv-to-musicxml.rb +36 -0
- data/lib/musa-dsl/transcription/from-gdv.rb +17 -0
- data/lib/musa-dsl/transcription/transcription.rb +55 -0
- data/lib/musa-dsl/transport.rb +6 -6
- data/lib/musa-dsl/transport/clock.rb +26 -26
- data/lib/musa-dsl/transport/dummy-clock.rb +32 -30
- data/lib/musa-dsl/transport/external-tick-clock.rb +21 -20
- data/lib/musa-dsl/transport/input-midi-clock.rb +82 -80
- data/lib/musa-dsl/transport/timer-clock.rb +72 -71
- data/lib/musa-dsl/transport/timer.rb +28 -26
- data/lib/musa-dsl/transport/transport.rb +111 -93
- data/musa-dsl.gemspec +3 -3
- metadata +73 -24
- data/lib/musa-dsl/core-ext/array-apply-get.rb +0 -18
- data/lib/musa-dsl/core-ext/array-to-neumas.rb +0 -28
- data/lib/musa-dsl/core-ext/as-context-run.rb +0 -44
- data/lib/musa-dsl/core-ext/duplicate.rb +0 -134
- data/lib/musa-dsl/core-ext/key-parameters-procedure-binder.rb +0 -85
- data/lib/musa-dsl/core-ext/proc-nice.rb +0 -13
- data/lib/musa-dsl/core-ext/send-nice.rb +0 -21
- data/lib/musa-dsl/core-ext/string-to-neumas.rb +0 -27
- data/lib/musa-dsl/datasets/gdv-decorators.rb +0 -221
- data/lib/musa-dsl/generative/rules.rb +0 -282
- data/lib/musa-dsl/neuma.rb +0 -1
- data/lib/musa-dsl/neuma/neuma.rb +0 -181
@@ -1,282 +0,0 @@
|
|
1
|
-
require 'musa-dsl/core-ext/as-context-run'
|
2
|
-
require 'musa-dsl/core-ext/key-parameters-procedure-binder'
|
3
|
-
|
4
|
-
module Musa
|
5
|
-
class Rules
|
6
|
-
def initialize(&block)
|
7
|
-
@context = RulesEvalContext.new.tap { |_| _._as_context_run block }
|
8
|
-
end
|
9
|
-
|
10
|
-
def generate_possibilities(object, confirmed_node = nil, node = nil, rules = nil)
|
11
|
-
node ||= Node.new
|
12
|
-
rules ||= @context._rules
|
13
|
-
|
14
|
-
history = confirmed_node.history if confirmed_node
|
15
|
-
history ||= []
|
16
|
-
|
17
|
-
rules = rules.clone
|
18
|
-
rule = rules.shift
|
19
|
-
|
20
|
-
if rule
|
21
|
-
rule.generate_possibilities(object, history).each do |new_object|
|
22
|
-
new_node = Node.new new_object, node
|
23
|
-
new_node.mark_as_ended! if @context._ended? new_object
|
24
|
-
|
25
|
-
rejection = @context._rejections.find { |rejection| rejection.rejects?(new_object, history) }
|
26
|
-
# TODO: include rejection secondary reasons in rejection message
|
27
|
-
|
28
|
-
new_node.reject! rejection if rejection
|
29
|
-
|
30
|
-
node.children << new_node
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
unless rules.empty?
|
35
|
-
node.children.each do |node|
|
36
|
-
generate_possibilities node.object, confirmed_node, node, rules unless node.rejected || node.ended?
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
node
|
41
|
-
end
|
42
|
-
|
43
|
-
def apply(object_or_list, node = nil)
|
44
|
-
list = object_or_list.arrayfy.clone
|
45
|
-
|
46
|
-
node ||= Node.new
|
47
|
-
|
48
|
-
seed = list.shift
|
49
|
-
|
50
|
-
if seed
|
51
|
-
result = generate_possibilities seed, node
|
52
|
-
|
53
|
-
fished = result.fish
|
54
|
-
|
55
|
-
node.reject! 'All children are rejected' if fished.empty?
|
56
|
-
|
57
|
-
fished.each do |object|
|
58
|
-
subnode = node.add(object).mark_as_ended!
|
59
|
-
apply list, subnode
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
node
|
64
|
-
end
|
65
|
-
|
66
|
-
class RulesEvalContext
|
67
|
-
attr_reader :_rules, :_ended_when, :_rejections
|
68
|
-
|
69
|
-
def rule(name, &block)
|
70
|
-
@_rules ||= []
|
71
|
-
@_rules << Rule.new(name, self, block)
|
72
|
-
self
|
73
|
-
end
|
74
|
-
|
75
|
-
def ended_when(&block)
|
76
|
-
@_ended_when = block
|
77
|
-
self
|
78
|
-
end
|
79
|
-
|
80
|
-
def rejection(reason, &block)
|
81
|
-
@_rejections ||= []
|
82
|
-
@_rejections << Rejection.new(reason, self, block)
|
83
|
-
self
|
84
|
-
end
|
85
|
-
|
86
|
-
def _ended?(object)
|
87
|
-
as_context_run @_ended_when, object
|
88
|
-
end
|
89
|
-
|
90
|
-
class Rule
|
91
|
-
attr_reader :name
|
92
|
-
|
93
|
-
def initialize(name, context, block)
|
94
|
-
@name = name
|
95
|
-
@context = context
|
96
|
-
@block = block
|
97
|
-
end
|
98
|
-
|
99
|
-
def generate_possibilities(object, history)
|
100
|
-
# TODO: optimize context using only one instance for all genereate_possibilities calls
|
101
|
-
context = RuleEvalContext.new @context
|
102
|
-
context.as_context_run @block, object, history
|
103
|
-
|
104
|
-
context._possibilities
|
105
|
-
end
|
106
|
-
|
107
|
-
class RuleEvalContext
|
108
|
-
attr_reader :_possibilities
|
109
|
-
|
110
|
-
def initialize(parent_context)
|
111
|
-
@_parent_context = parent_context
|
112
|
-
@_possibilities = []
|
113
|
-
end
|
114
|
-
|
115
|
-
def possibility(object)
|
116
|
-
@_possibilities << object
|
117
|
-
self
|
118
|
-
end
|
119
|
-
|
120
|
-
private
|
121
|
-
|
122
|
-
def method_missing(method_name, *args, **key_args, &block)
|
123
|
-
if @_parent_context.respond_to? method_name
|
124
|
-
@_parent_context.send_nice method_name, *args, **key_args, &block
|
125
|
-
else
|
126
|
-
super
|
127
|
-
end
|
128
|
-
end
|
129
|
-
|
130
|
-
def respond_to_missing?(method_name, include_private)
|
131
|
-
@_parent_context.respond_to?(method_name, include_private) || super
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
private_constant :RuleEvalContext
|
136
|
-
end
|
137
|
-
|
138
|
-
private_constant :Rule
|
139
|
-
|
140
|
-
class Rejection
|
141
|
-
attr_reader :reason
|
142
|
-
|
143
|
-
def initialize(reason, context = nil, block = nil)
|
144
|
-
@reason = reason
|
145
|
-
@context = context
|
146
|
-
@block = block
|
147
|
-
end
|
148
|
-
|
149
|
-
def rejects?(object, history)
|
150
|
-
# TODO: optimize context using only one instance for all rejects? checks
|
151
|
-
context = RejectionEvalContext.new @context
|
152
|
-
context.as_context_run @block, object, history
|
153
|
-
|
154
|
-
reasons = context._secondary_reasons.collect { |_| ("#{@reason} (#{_})" if _) || @reason }
|
155
|
-
|
156
|
-
reasons.empty? ? nil : reasons
|
157
|
-
end
|
158
|
-
|
159
|
-
class RejectionEvalContext
|
160
|
-
attr_reader :_secondary_reasons
|
161
|
-
|
162
|
-
def initialize(parent_context)
|
163
|
-
@_parent_context = parent_context
|
164
|
-
@_secondary_reasons = []
|
165
|
-
end
|
166
|
-
|
167
|
-
def reject(secondary_reason = nil)
|
168
|
-
@_secondary_reasons << secondary_reason
|
169
|
-
self
|
170
|
-
end
|
171
|
-
|
172
|
-
private
|
173
|
-
|
174
|
-
def method_missing(method_name, *args, **key_args, &block)
|
175
|
-
if @_parent_context.respond_to? method_name
|
176
|
-
@_parent_context.send_nice method_name, *args, **key_args, &block
|
177
|
-
else
|
178
|
-
super
|
179
|
-
end
|
180
|
-
end
|
181
|
-
|
182
|
-
def respond_to_missing?(method_name, include_private)
|
183
|
-
@_parent_context.respond_to?(method_name, include_private) || super
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
|
-
private_constant :RejectionEvalContext
|
188
|
-
end
|
189
|
-
|
190
|
-
private_constant :Rejection
|
191
|
-
end
|
192
|
-
|
193
|
-
private_constant :RulesEvalContext
|
194
|
-
|
195
|
-
class Node
|
196
|
-
attr_reader :parent, :children, :object, :rejected
|
197
|
-
|
198
|
-
def initialize(object = nil, parent = nil)
|
199
|
-
@parent = parent
|
200
|
-
@children = []
|
201
|
-
@object = object
|
202
|
-
|
203
|
-
@ended = false
|
204
|
-
@rejected = nil
|
205
|
-
end
|
206
|
-
|
207
|
-
def add(object)
|
208
|
-
Node.new(object, self).tap { |n| @children << n }
|
209
|
-
end
|
210
|
-
|
211
|
-
def reject!(rejection)
|
212
|
-
@rejected = rejection
|
213
|
-
self
|
214
|
-
end
|
215
|
-
|
216
|
-
def mark_as_ended!
|
217
|
-
@children.each(&:update_rejection_by_children!)
|
218
|
-
|
219
|
-
if !@children.empty? && !@children.find { |n| !n.rejected }
|
220
|
-
reject! Rejection::AllChildrenRejected
|
221
|
-
end
|
222
|
-
|
223
|
-
@ended = true
|
224
|
-
|
225
|
-
self
|
226
|
-
end
|
227
|
-
|
228
|
-
def ended?
|
229
|
-
@ended
|
230
|
-
end
|
231
|
-
|
232
|
-
def history
|
233
|
-
objects = []
|
234
|
-
n = self
|
235
|
-
while n && n.object
|
236
|
-
objects << n.object
|
237
|
-
n = n.parent
|
238
|
-
end
|
239
|
-
|
240
|
-
objects.reverse
|
241
|
-
end
|
242
|
-
|
243
|
-
def fish
|
244
|
-
fished = []
|
245
|
-
|
246
|
-
@children.each do |node|
|
247
|
-
unless node.rejected
|
248
|
-
if node.ended?
|
249
|
-
fished << node.object
|
250
|
-
else
|
251
|
-
fished += node.fish
|
252
|
-
end
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
fished
|
257
|
-
end
|
258
|
-
|
259
|
-
def combinations(parent_combination = nil)
|
260
|
-
parent_combination ||= []
|
261
|
-
|
262
|
-
combinations = []
|
263
|
-
|
264
|
-
unless rejected
|
265
|
-
if @children.empty?
|
266
|
-
combinations << parent_combination
|
267
|
-
else
|
268
|
-
@children.each do |node|
|
269
|
-
node.combinations(parent_combination + [node.object]).each do |object|
|
270
|
-
combinations << object
|
271
|
-
end
|
272
|
-
end
|
273
|
-
end
|
274
|
-
end
|
275
|
-
|
276
|
-
combinations
|
277
|
-
end
|
278
|
-
end
|
279
|
-
|
280
|
-
private_constant :Node
|
281
|
-
end
|
282
|
-
end
|
data/lib/musa-dsl/neuma.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
require 'musa-dsl/neuma/neuma'
|
data/lib/musa-dsl/neuma/neuma.rb
DELETED
@@ -1,181 +0,0 @@
|
|
1
|
-
module Musa::Neumalang
|
2
|
-
module Neumas # Neumas serie
|
3
|
-
# TODO implementar | ???? neumas | neumas = parallel neumas, no?
|
4
|
-
end
|
5
|
-
|
6
|
-
module Neuma
|
7
|
-
module Parallel
|
8
|
-
include Neuma
|
9
|
-
end
|
10
|
-
|
11
|
-
def |(other)
|
12
|
-
if is_a?(Parallel)
|
13
|
-
clone.tap { |_| _[:parallel] << convert_to_parallel_element(other) }.extend(Parallel)
|
14
|
-
else
|
15
|
-
{ kind: :parallel,
|
16
|
-
parallel: [clone, convert_to_parallel_element(other)]
|
17
|
-
}.extend(Parallel)
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
private
|
22
|
-
|
23
|
-
def convert_to_parallel_element(e)
|
24
|
-
case e
|
25
|
-
when String then { kind: :serie, serie: e.to_neumas }.extend(Neuma)
|
26
|
-
else
|
27
|
-
raise ArgumentError, "Dont know how to convert to neuma #{e}"
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
module Dataset
|
33
|
-
class Decorator
|
34
|
-
def process(element, base_duration:, tick_duration:)
|
35
|
-
element
|
36
|
-
end
|
37
|
-
|
38
|
-
def check(value_or_array, &block)
|
39
|
-
if block_given?
|
40
|
-
if value_or_array.is_a?(Array)
|
41
|
-
value_or_array.each { |value| yield value }
|
42
|
-
else
|
43
|
-
yield value_or_array
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
class TwoNeumasDecorator < Decorator
|
50
|
-
def process(element1, element2, base_duration:, tick_duration:)
|
51
|
-
element2
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
class Decorators
|
56
|
-
attr_reader :decorators
|
57
|
-
attr_accessor :appogiatura_decorator
|
58
|
-
|
59
|
-
def initialize(*decorators, appogiatura_decorator: nil, base_duration: nil, tick_duration: nil)
|
60
|
-
@base_duration = 1/4r
|
61
|
-
@tick_duration = tick_duration || 1/96r
|
62
|
-
|
63
|
-
@appogiatura_decorator = appogiatura_decorator
|
64
|
-
@decorators = decorators
|
65
|
-
end
|
66
|
-
|
67
|
-
def process(element)
|
68
|
-
if @appogiatura_decorator
|
69
|
-
element = @appogiatura_decorator.process(element, base_duration: @base_duration, tick_duration: @tick_duration)
|
70
|
-
end
|
71
|
-
|
72
|
-
@decorators.each do |processor|
|
73
|
-
if element
|
74
|
-
if element.is_a?(Array)
|
75
|
-
element = element.collect { |element_i| processor.process(element_i, base_duration: @base_duration, tick_duration: @tick_duration) }.flatten(1)
|
76
|
-
else
|
77
|
-
element = processor.process(element, base_duration: @base_duration, tick_duration: @tick_duration)
|
78
|
-
end
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
element
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
protected
|
87
|
-
|
88
|
-
def positive_sign_of(x)
|
89
|
-
x >= 0 ? '+' : ''
|
90
|
-
end
|
91
|
-
|
92
|
-
def sign_of(x)
|
93
|
-
'++-'[x <=> 0]
|
94
|
-
end
|
95
|
-
|
96
|
-
def velocity_of(x)
|
97
|
-
%w[ppp pp p mp mf f ff fff][x + 3]
|
98
|
-
end
|
99
|
-
|
100
|
-
def modificator_string(modificator, parameter_or_parameters)
|
101
|
-
case parameter_or_parameters
|
102
|
-
when true
|
103
|
-
modificator.to_s
|
104
|
-
when Array
|
105
|
-
"#{modificator.to_s}(#{parameter_or_parameters.collect { |p| parameter_to_string(p) }.join(', ')})"
|
106
|
-
else
|
107
|
-
"#{modificator.to_s}(#{parameter_to_string(parameter_or_parameters)})"
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
private
|
112
|
-
|
113
|
-
def parameter_to_string(parameter)
|
114
|
-
case parameter
|
115
|
-
when String
|
116
|
-
"\"#{parameter}\""
|
117
|
-
when Numeric
|
118
|
-
"#{parameter}"
|
119
|
-
when Symbol
|
120
|
-
"#{parameter}"
|
121
|
-
end
|
122
|
-
end
|
123
|
-
end
|
124
|
-
|
125
|
-
class ProtoDecoder
|
126
|
-
def subcontext
|
127
|
-
self
|
128
|
-
end
|
129
|
-
|
130
|
-
def decode(_element)
|
131
|
-
raise NotImplementedError
|
132
|
-
end
|
133
|
-
end
|
134
|
-
|
135
|
-
class DifferentialDecoder < ProtoDecoder
|
136
|
-
def decode(attributes)
|
137
|
-
parse attributes
|
138
|
-
end
|
139
|
-
|
140
|
-
def parse(_attributes)
|
141
|
-
raise NotImplementedError
|
142
|
-
end
|
143
|
-
end
|
144
|
-
|
145
|
-
class Decoder < DifferentialDecoder
|
146
|
-
def initialize(base, processor: nil)
|
147
|
-
@base = base
|
148
|
-
@last = base.clone
|
149
|
-
|
150
|
-
@processor = processor
|
151
|
-
end
|
152
|
-
|
153
|
-
attr_accessor :processor
|
154
|
-
attr_reader :base
|
155
|
-
|
156
|
-
def base=(base)
|
157
|
-
@base = base
|
158
|
-
@last = base.clone
|
159
|
-
end
|
160
|
-
|
161
|
-
def subcontext
|
162
|
-
Decoder.new @base
|
163
|
-
end
|
164
|
-
|
165
|
-
def decode(attributes)
|
166
|
-
result = apply parse(attributes), on: @last
|
167
|
-
|
168
|
-
@last = result.clone
|
169
|
-
|
170
|
-
if @processor
|
171
|
-
@processor.process(result)
|
172
|
-
else
|
173
|
-
result
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
def apply(_action, on:)
|
178
|
-
raise NotImplementedError
|
179
|
-
end
|
180
|
-
end
|
181
|
-
end
|