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.
- 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 +183 -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 +105 -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 +562 -270
- data/lib/musa-dsl/sequencer/base-sequencer-public.rb +199 -199
- 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 +99 -95
- 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,145 +1,151 @@
|
|
1
|
-
|
1
|
+
require_relative '../core-ext/with'
|
2
2
|
|
3
3
|
module Musa
|
4
|
-
|
5
|
-
|
6
|
-
|
4
|
+
module Darwin
|
5
|
+
class Darwin
|
6
|
+
def initialize(&block)
|
7
|
+
raise ArgumentError, 'block is needed' unless block
|
7
8
|
|
8
|
-
|
9
|
+
main_context = MainContext.new &block
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
11
|
+
@measures = main_context._measures
|
12
|
+
@weights = main_context._weights
|
13
|
+
end
|
13
14
|
|
14
|
-
|
15
|
-
|
15
|
+
def select(population)
|
16
|
+
measured_objects = []
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
population.each do |object|
|
19
|
+
context = MeasuresEvalContext.new
|
19
20
|
|
20
|
-
|
21
|
-
|
21
|
+
context.with object, **{}, &@measures
|
22
|
+
measure = context._measure
|
22
23
|
|
23
|
-
|
24
|
-
|
24
|
+
measured_objects << { object: object, measure: context._measure } unless measure.died?
|
25
|
+
end
|
25
26
|
|
26
|
-
|
27
|
+
limits = {}
|
27
28
|
|
28
|
-
|
29
|
-
|
29
|
+
measured_objects.each do |measured_object|
|
30
|
+
measure = measured_object[:measure]
|
30
31
|
|
31
|
-
|
32
|
-
|
32
|
+
measure.dimensions.each do |measure_name, value|
|
33
|
+
limit = limits[measure_name] ||= { min: nil, max: nil }
|
33
34
|
|
34
|
-
|
35
|
-
|
35
|
+
limit[:min] = value.to_f if limit[:min].nil? || limit[:min] > value
|
36
|
+
limit[:max] = value.to_f if limit[:max].nil? || limit[:max] < value
|
36
37
|
|
37
|
-
|
38
|
+
limit[:range] = limit[:max] - limit[:min]
|
39
|
+
end
|
38
40
|
end
|
39
|
-
end
|
40
41
|
|
41
|
-
|
42
|
+
# warn "Darwin.select: weights #{@weights}"
|
43
|
+
|
44
|
+
measured_objects.each do |measured_object|
|
45
|
+
measure = measured_object[:measure]
|
42
46
|
|
43
|
-
|
44
|
-
|
47
|
+
measure.dimensions.each do |dimension_name, value|
|
48
|
+
limit = limits[dimension_name]
|
49
|
+
measure.normalized_dimensions[dimension_name] = (value - limit[:min]) / limit[:range]
|
50
|
+
end
|
45
51
|
|
46
|
-
|
47
|
-
limit = limits[dimension_name]
|
48
|
-
measure.normalized_dimensions[dimension_name] = (value - limit[:min]) / limit[:range]
|
52
|
+
# warn "Darwin.select: #{measured_object[:object]} #{measured_object[:measure]} weight=#{measured_object[:measure].evaluate_weight(@weights).round(2)}"
|
49
53
|
end
|
50
54
|
|
51
|
-
|
52
|
-
end
|
55
|
+
measured_objects.sort! { |a, b| evaluate_weights a[:measure], b[:measure] }
|
53
56
|
|
54
|
-
|
57
|
+
measured_objects.collect { |measured_object| measured_object[:object] }
|
58
|
+
end
|
55
59
|
|
56
|
-
|
57
|
-
|
60
|
+
def evaluate_weights(measure_a, measure_b)
|
61
|
+
measure_b.evaluate_weight(@weights) <=> measure_a.evaluate_weight(@weights)
|
62
|
+
end
|
58
63
|
|
59
|
-
|
60
|
-
|
61
|
-
end
|
64
|
+
class MainContext
|
65
|
+
include Musa::Extension::With
|
62
66
|
|
63
|
-
|
64
|
-
attr_reader :_measures, :_weights
|
67
|
+
attr_reader :_measures, :_weights
|
65
68
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
69
|
+
def initialize(&block)
|
70
|
+
@_weights = {}
|
71
|
+
with &block
|
72
|
+
end
|
70
73
|
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
+
def measures(&block)
|
75
|
+
@_measures = block
|
76
|
+
end
|
74
77
|
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
+
def weight(**feature_or_dimension_weights)
|
79
|
+
feature_or_dimension_weights.each do |name, value|
|
80
|
+
@_weights[name] = value
|
81
|
+
end
|
78
82
|
end
|
79
83
|
end
|
80
|
-
end
|
81
84
|
|
82
|
-
|
83
|
-
|
84
|
-
@_features = {}
|
85
|
-
@_dimensions = {}
|
86
|
-
@_died = false
|
87
|
-
end
|
85
|
+
class MeasuresEvalContext
|
86
|
+
include Musa::Extension::With
|
88
87
|
|
89
|
-
|
90
|
-
|
91
|
-
|
88
|
+
def initialize
|
89
|
+
@_features = {}
|
90
|
+
@_dimensions = {}
|
91
|
+
@_died = false
|
92
|
+
end
|
92
93
|
|
93
|
-
|
94
|
-
|
95
|
-
|
94
|
+
def _measure
|
95
|
+
Measure.new @_features, @_dimensions, @_died
|
96
|
+
end
|
96
97
|
|
97
|
-
|
98
|
-
|
99
|
-
|
98
|
+
def feature(feature_name)
|
99
|
+
@_features[feature_name] = true
|
100
|
+
end
|
100
101
|
|
101
|
-
|
102
|
-
|
103
|
-
|
102
|
+
def dimension(dimension_name, value)
|
103
|
+
@_dimensions[dimension_name] = value
|
104
|
+
end
|
105
|
+
|
106
|
+
def die
|
107
|
+
@_died = true
|
108
|
+
end
|
104
109
|
|
105
|
-
|
106
|
-
|
110
|
+
def died?
|
111
|
+
@_died
|
112
|
+
end
|
107
113
|
end
|
108
|
-
end
|
109
114
|
|
110
|
-
|
111
|
-
|
115
|
+
class Measure
|
116
|
+
attr_reader :features, :dimensions, :normalized_dimensions
|
112
117
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
118
|
+
def initialize(features, dimensions, died)
|
119
|
+
@features = features
|
120
|
+
@dimensions = dimensions
|
121
|
+
@died = died
|
117
122
|
|
118
|
-
|
119
|
-
|
123
|
+
@normalized_dimensions = {}
|
124
|
+
end
|
120
125
|
|
121
|
-
|
122
|
-
|
123
|
-
|
126
|
+
def died?
|
127
|
+
@died
|
128
|
+
end
|
124
129
|
|
125
|
-
|
126
|
-
|
130
|
+
def evaluate_weight(weights)
|
131
|
+
total = 0.0
|
127
132
|
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
133
|
+
unless @died
|
134
|
+
weights.each do |name, weight|
|
135
|
+
total += @normalized_dimensions[name] * weight if @normalized_dimensions.key? name
|
136
|
+
total += weight if @features[name]
|
137
|
+
end
|
132
138
|
end
|
139
|
+
|
140
|
+
total
|
133
141
|
end
|
134
142
|
|
135
|
-
|
136
|
-
|
143
|
+
def inspect
|
144
|
+
"Measure features=#{@features.collect { |k, _v| k }} dimensions=#{@normalized_dimensions.collect { |k, v| [k, [@dimensions[k].round(5), v.round(2)]] }.to_h}"
|
145
|
+
end
|
137
146
|
|
138
|
-
|
139
|
-
"Measure features=#{@features.collect { |k, _v| k }} dimensions=#{@normalized_dimensions.collect { |k, v| [k, [@dimensions[k].round(5), v.round(2)]] }.to_h}"
|
147
|
+
alias to_s inspect
|
140
148
|
end
|
141
|
-
|
142
|
-
alias to_s inspect
|
143
149
|
end
|
144
150
|
end
|
145
151
|
end
|
@@ -1,14 +1,19 @@
|
|
1
1
|
module Musa
|
2
2
|
module GenerativeGrammar
|
3
|
+
extend self
|
3
4
|
|
4
5
|
def N(content = nil, **attributes, &block)
|
5
6
|
if block_given? && content.nil?
|
6
|
-
BlockNode.new(attributes, &block)
|
7
|
+
Implementation::BlockNode.new(attributes, &block)
|
7
8
|
else
|
8
|
-
FinalNode.new(content, attributes)
|
9
|
+
Implementation::FinalNode.new(content, attributes)
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
13
|
+
def PN
|
14
|
+
Implementation::ProxyNode.new
|
15
|
+
end
|
16
|
+
|
12
17
|
class OptionElement
|
13
18
|
attr_reader :content, :attributes
|
14
19
|
|
@@ -18,277 +23,267 @@ module Musa
|
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
26
|
+
module Implementation
|
27
|
+
class Node
|
28
|
+
def or(other)
|
29
|
+
OrNode.new(self, other)
|
30
|
+
end
|
25
31
|
|
26
|
-
|
32
|
+
alias_method :|, :or
|
27
33
|
|
28
|
-
|
29
|
-
|
34
|
+
def repeat(exactly = nil, min: nil, max: nil)
|
35
|
+
raise ArgumentError, 'Only exactly value or min/max values are allowed' if exactly && (min || max)
|
30
36
|
|
31
|
-
|
37
|
+
min = max = exactly if exactly
|
32
38
|
|
33
|
-
|
34
|
-
|
39
|
+
if min && min > 0
|
40
|
+
pre = self
|
35
41
|
|
36
|
-
|
37
|
-
|
42
|
+
(min - 1).times do
|
43
|
+
pre += self
|
44
|
+
end
|
38
45
|
end
|
39
|
-
end
|
40
46
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
+
if pre && max == min
|
48
|
+
pre
|
49
|
+
elsif pre && max > min
|
50
|
+
pre + RepeatNode.new(self, max - min)
|
51
|
+
else
|
52
|
+
RepeatNode.new(self, max)
|
53
|
+
end
|
47
54
|
end
|
48
|
-
end
|
49
55
|
|
50
|
-
|
51
|
-
|
56
|
+
def limit(attribute = nil, after_collect_operation = nil, comparison_method = nil, comparison_value = nil, &block)
|
57
|
+
raise ArgumentError, 'Cannot use simplified arguments and yield block at the same time' if (attribute || after_collect_operation || comparison_method || comparison_value) && @block
|
52
58
|
|
53
|
-
|
59
|
+
block ||= generate_simple_condition_block(attribute, after_collect_operation, comparison_method, comparison_value)
|
54
60
|
|
55
|
-
|
56
|
-
|
61
|
+
ConditionNode.new(self, &block)
|
62
|
+
end
|
57
63
|
|
58
|
-
|
59
|
-
|
60
|
-
|
64
|
+
def next(other)
|
65
|
+
NextNode.new(self, other)
|
66
|
+
end
|
61
67
|
|
62
|
-
|
68
|
+
alias_method :+, :next
|
63
69
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
70
|
+
def options(attribute = nil,
|
71
|
+
after_collect_operation = nil,
|
72
|
+
comparison_method = nil,
|
73
|
+
comparison_value = nil,
|
74
|
+
raw: nil,
|
75
|
+
content: nil,
|
76
|
+
&condition)
|
71
77
|
|
72
|
-
|
73
|
-
|
78
|
+
raise ArgumentError, 'Cannot use simplified arguments and yield block at the same time' if (attribute || after_collect_operation || comparison_method || comparison_value) && @condition
|
79
|
+
raise ArgumentError, 'Cannot use raw: true and content: option at the same time' if raw && content
|
74
80
|
|
75
|
-
|
76
|
-
|
81
|
+
raw ||= false
|
82
|
+
content ||= :itself
|
77
83
|
|
78
|
-
|
84
|
+
condition ||= generate_simple_condition_block(attribute, after_collect_operation, comparison_method, comparison_value)
|
79
85
|
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
86
|
+
if raw
|
87
|
+
_options(&condition)
|
88
|
+
else
|
89
|
+
_options(&condition).collect { |o| o.collect(&:content).send(content) }
|
90
|
+
end
|
84
91
|
end
|
85
|
-
end
|
86
92
|
|
87
|
-
|
88
|
-
|
89
|
-
|
93
|
+
def size
|
94
|
+
options.size
|
95
|
+
end
|
90
96
|
|
91
|
-
|
97
|
+
alias_method :length, :size
|
92
98
|
|
93
|
-
|
94
|
-
|
95
|
-
|
99
|
+
def [](index)
|
100
|
+
options[index].to_serie.to_node
|
101
|
+
end
|
96
102
|
|
97
|
-
|
98
|
-
|
103
|
+
def to_serie(flatten: nil, &condition)
|
104
|
+
flatten ||= true
|
99
105
|
|
100
|
-
|
101
|
-
|
106
|
+
serie = _options(&condition).collect { |o| o.collect(&:content) }.to_serie(of_series: true).merge
|
107
|
+
serie = serie.flatten if flatten
|
102
108
|
|
103
|
-
|
104
|
-
|
109
|
+
serie.prototype
|
110
|
+
end
|
105
111
|
|
106
|
-
|
112
|
+
alias_method :s, :to_serie
|
107
113
|
|
108
|
-
|
109
|
-
|
110
|
-
|
114
|
+
def _options(parent: nil, &condition)
|
115
|
+
raise NotImplementedError
|
116
|
+
end
|
111
117
|
|
112
|
-
|
118
|
+
protected
|
113
119
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
120
|
+
def generate_simple_condition_block(attribute = nil,
|
121
|
+
after_collect_operation = nil,
|
122
|
+
comparison_method = nil,
|
123
|
+
comparison_value = nil)
|
118
124
|
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
125
|
+
if attribute && after_collect_operation && comparison_method && comparison_value
|
126
|
+
proc do |o|
|
127
|
+
o.collect { |_| _.attributes[attribute] }
|
128
|
+
.send(after_collect_operation)
|
129
|
+
.send(comparison_method, comparison_value)
|
130
|
+
end
|
124
131
|
end
|
125
132
|
end
|
126
133
|
end
|
127
|
-
end
|
128
134
|
|
129
|
-
|
135
|
+
class ProxyNode < Node
|
136
|
+
attr_accessor :node
|
130
137
|
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
def _options(parent: nil, &condition)
|
135
|
-
@node._options parent: parent, &condition
|
138
|
+
def _options(parent: nil, &condition)
|
139
|
+
@node._options parent: parent, &condition
|
140
|
+
end
|
136
141
|
end
|
137
|
-
end
|
138
142
|
|
139
|
-
|
140
|
-
|
141
|
-
|
143
|
+
class FinalNode < Node
|
144
|
+
attr_reader :content
|
145
|
+
attr_reader :attributes
|
142
146
|
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
+
def initialize(content, attributes)
|
148
|
+
super()
|
149
|
+
@element = OptionElement.new(content, attributes)
|
150
|
+
end
|
147
151
|
|
148
|
-
|
149
|
-
|
152
|
+
def _options(parent: nil, &condition)
|
153
|
+
parent ||= []
|
150
154
|
|
151
|
-
|
152
|
-
|
153
|
-
|
155
|
+
if block_given?
|
156
|
+
if yield(parent + [@element])
|
157
|
+
[[@element]]
|
158
|
+
else
|
159
|
+
[]
|
160
|
+
end
|
154
161
|
else
|
155
|
-
[]
|
162
|
+
[[@element]]
|
156
163
|
end
|
157
|
-
else
|
158
|
-
[[@element]]
|
159
164
|
end
|
160
165
|
end
|
161
|
-
end
|
162
|
-
|
163
|
-
private_constant :FinalNode
|
164
166
|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
167
|
+
class BlockNode < Node
|
168
|
+
def initialize(attributes, &block)
|
169
|
+
@attributes = attributes
|
170
|
+
@block = block
|
171
|
+
end
|
170
172
|
|
171
|
-
|
172
|
-
|
173
|
+
def _options(parent: nil, &condition)
|
174
|
+
parent ||= []
|
173
175
|
|
174
|
-
|
175
|
-
|
176
|
+
element = @block.call(parent, @attributes)
|
177
|
+
element = OptionElement.new(element, @attributes) unless element.is_a?(OptionElement)
|
176
178
|
|
177
|
-
|
178
|
-
|
179
|
-
|
179
|
+
if block_given?
|
180
|
+
if yield(parent + [element], @attributes)
|
181
|
+
[[element]]
|
182
|
+
else
|
183
|
+
[]
|
184
|
+
end
|
180
185
|
else
|
181
|
-
[]
|
186
|
+
[[element]]
|
182
187
|
end
|
183
|
-
else
|
184
|
-
[[element]]
|
185
188
|
end
|
186
189
|
end
|
187
|
-
end
|
188
190
|
|
189
|
-
|
191
|
+
class ConditionNode < Node
|
192
|
+
def initialize(node, &block)
|
193
|
+
@node = node
|
194
|
+
@block = block
|
195
|
+
end
|
190
196
|
|
191
|
-
|
192
|
-
|
193
|
-
@node = node
|
194
|
-
@block = block
|
195
|
-
end
|
197
|
+
def _options(parent: nil, &condition)
|
198
|
+
parent ||= []
|
196
199
|
|
197
|
-
|
198
|
-
parent ||= []
|
200
|
+
r = []
|
199
201
|
|
200
|
-
|
202
|
+
@node._options(parent: parent, &condition).each do |node_option|
|
203
|
+
r << node_option if (!block_given? || yield(parent + node_option)) && @block.call(parent + node_option)
|
204
|
+
end
|
201
205
|
|
202
|
-
|
203
|
-
r << node_option if (!block_given? || yield(parent + node_option)) && @block.call(parent + node_option)
|
206
|
+
r
|
204
207
|
end
|
205
|
-
|
206
|
-
r
|
207
208
|
end
|
208
|
-
end
|
209
209
|
|
210
|
-
|
210
|
+
class OrNode < Node
|
211
|
+
def initialize(node1, node2)
|
212
|
+
@node1 = node1
|
213
|
+
@node2 = node2
|
214
|
+
super()
|
215
|
+
end
|
211
216
|
|
212
|
-
|
213
|
-
|
214
|
-
@node1 = node1
|
215
|
-
@node2 = node2
|
216
|
-
super()
|
217
|
-
end
|
217
|
+
def _options(parent: nil, &condition)
|
218
|
+
parent ||= []
|
218
219
|
|
219
|
-
|
220
|
-
parent ||= []
|
220
|
+
r = []
|
221
221
|
|
222
|
-
|
222
|
+
@node1._options(parent: parent, &condition).each do |node_option|
|
223
|
+
r << node_option if !block_given? || yield(parent + node_option)
|
224
|
+
end
|
223
225
|
|
224
|
-
|
225
|
-
|
226
|
-
|
226
|
+
@node2._options(parent: parent, &condition).each do |node_option|
|
227
|
+
r << node_option if !block_given? || yield(parent + node_option)
|
228
|
+
end
|
227
229
|
|
228
|
-
|
229
|
-
r << node_option if !block_given? || yield(parent + node_option)
|
230
|
+
r
|
230
231
|
end
|
231
|
-
|
232
|
-
r
|
233
232
|
end
|
234
|
-
end
|
235
233
|
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
super()
|
243
|
-
end
|
234
|
+
class NextNode < Node
|
235
|
+
def initialize(node, after)
|
236
|
+
@node = node
|
237
|
+
@after = after
|
238
|
+
super()
|
239
|
+
end
|
244
240
|
|
245
|
-
|
246
|
-
|
241
|
+
def _options(parent: nil, &condition)
|
242
|
+
parent ||= []
|
247
243
|
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
244
|
+
r = []
|
245
|
+
@node._options(parent: parent, &condition).each do |node_option|
|
246
|
+
@after._options(parent: parent + node_option, &condition).each do |after_option|
|
247
|
+
r << node_option + after_option unless after_option.empty?
|
248
|
+
end
|
252
249
|
end
|
250
|
+
r
|
253
251
|
end
|
254
|
-
r
|
255
252
|
end
|
256
|
-
end
|
257
|
-
|
258
|
-
private_constant :NextNode
|
259
253
|
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
254
|
+
class RepeatNode < Node
|
255
|
+
def initialize(node, max = nil)
|
256
|
+
@node = node
|
257
|
+
@max = max
|
264
258
|
|
265
|
-
|
266
|
-
|
259
|
+
super()
|
260
|
+
end
|
267
261
|
|
268
|
-
|
269
|
-
|
270
|
-
|
262
|
+
def _options(parent: nil, depth: nil, &condition)
|
263
|
+
parent ||= []
|
264
|
+
depth ||= 0
|
271
265
|
|
272
|
-
|
266
|
+
r = []
|
273
267
|
|
274
|
-
|
275
|
-
|
268
|
+
if @max.nil? || depth < @max
|
269
|
+
node_options = @node._options(parent: parent, &condition)
|
276
270
|
|
277
|
-
|
278
|
-
|
271
|
+
node_options.each do |node_option|
|
272
|
+
r << node_option
|
279
273
|
|
280
|
-
|
274
|
+
node_suboptions = _options(parent: parent + node_option, depth: depth + 1, &condition)
|
281
275
|
|
282
|
-
|
283
|
-
|
276
|
+
node_suboptions.each do |node_suboption|
|
277
|
+
r << node_option + node_suboption
|
278
|
+
end
|
284
279
|
end
|
285
280
|
end
|
286
|
-
end
|
287
281
|
|
288
|
-
|
282
|
+
r
|
283
|
+
end
|
289
284
|
end
|
290
285
|
end
|
291
286
|
|
292
|
-
private_constant :
|
287
|
+
private_constant :Implementation
|
293
288
|
end
|
294
289
|
end
|