trailblazer-activity-dsl-linear 1.1.0 → 1.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -5
- data/CHANGES.md +72 -0
- data/Gemfile +6 -3
- data/lib/trailblazer/activity/dsl/linear/feature/merge.rb +2 -2
- data/lib/trailblazer/activity/dsl/linear/feature/patch.rb +9 -9
- data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/dsl.rb +19 -29
- data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/runtime.rb +6 -8
- data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping.rb +25 -35
- data/lib/trailblazer/activity/dsl/linear/helper/path.rb +37 -18
- data/lib/trailblazer/activity/dsl/linear/helper.rb +27 -18
- data/lib/trailblazer/activity/dsl/linear/normalizer/extensions.rb +63 -0
- data/lib/trailblazer/activity/dsl/linear/normalizer/inherit.rb +90 -0
- data/lib/trailblazer/activity/dsl/linear/normalizer/output_tuples.rb +160 -0
- data/lib/trailblazer/activity/dsl/linear/normalizer/terminus.rb +26 -29
- data/lib/trailblazer/activity/dsl/linear/normalizer.rb +96 -148
- data/lib/trailblazer/activity/dsl/linear/sequence/builder.rb +3 -2
- data/lib/trailblazer/activity/dsl/linear/sequence/compiler.rb +21 -17
- data/lib/trailblazer/activity/dsl/linear/sequence/search.rb +2 -8
- data/lib/trailblazer/activity/dsl/linear/strategy.rb +17 -17
- data/lib/trailblazer/activity/dsl/linear/version.rb +1 -1
- data/lib/trailblazer/activity/dsl/linear.rb +12 -1
- data/lib/trailblazer/activity/fast_track.rb +91 -54
- data/lib/trailblazer/activity/path.rb +22 -29
- data/lib/trailblazer/activity/railway.rb +60 -54
- data/trailblazer-activity-dsl-linear.gemspec +7 -8
- metadata +21 -36
- data/.github/workflows/ci_jruby.yml +0 -19
- data/.github/workflows/ci_legacy.yml +0 -19
- data/.github/workflows/ci_truffleruby.yml +0 -19
- data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/inherit.rb +0 -38
@@ -9,12 +9,15 @@ module Trailblazer
|
|
9
9
|
#
|
10
10
|
# They're usually invoked from {Strategy#invoke_normalizer_for!}, which is called from {Path#step},
|
11
11
|
# {Railway#pass}, etc.
|
12
|
+
#
|
13
|
+
# Most parts of Normalizer are documented: https://trailblazer.to/2.1/docs/internals.html#internals-dsl-normalizer
|
12
14
|
module Normalizer
|
13
15
|
# Container for all final normalizers of a specific Strategy.
|
14
16
|
class Normalizers
|
15
17
|
def initialize(**options)
|
16
18
|
@normalizers = options
|
17
19
|
end
|
20
|
+
|
18
21
|
# Execute the specific normalizer (step, fail, pass) for a particular option set provided
|
19
22
|
# by the DSL user. Usually invoked when you call {#step}.
|
20
23
|
def call(name, ctx)
|
@@ -57,7 +60,6 @@ module Trailblazer
|
|
57
60
|
[name, new_normalizer]
|
58
61
|
end.to_h
|
59
62
|
|
60
|
-
|
61
63
|
Normalizers.new(**hsh.merge(new_normalizers))
|
62
64
|
end
|
63
65
|
end
|
@@ -75,82 +77,125 @@ module Trailblazer
|
|
75
77
|
end
|
76
78
|
|
77
79
|
# The generic normalizer not tied to `step` or friends.
|
78
|
-
def Normalizer
|
79
|
-
pipeline
|
80
|
+
def Normalizer(prepend_to_default_outputs: [])
|
81
|
+
# Adding steps to the output pipeline means they are only called when there
|
82
|
+
# are no :outputs set already.
|
83
|
+
outputs_pipeline = TaskWrap::Pipeline.new([])
|
84
|
+
prepend_to_default_outputs.each do |hsh|
|
85
|
+
outputs_pipeline = Linear::Normalizer.prepend_to(outputs_pipeline, nil, hsh) # DISCUSS: does it matter if we prepend FastTrack to Railway, etc?
|
86
|
+
end
|
87
|
+
|
88
|
+
# Call the prepend_to_outputs pipeline only if {:outputs} is not set (by Subprocess).
|
89
|
+
# too bad we don't have nesting here, yet.
|
90
|
+
defaults_for_outputs = ->(ctx, args) do
|
91
|
+
return [ctx, args] if ctx.key?(:outputs)
|
92
|
+
|
93
|
+
outputs_pipeline.(ctx, args)
|
94
|
+
end
|
95
|
+
|
96
|
+
TaskWrap::Pipeline.new(
|
80
97
|
{
|
81
|
-
"activity.normalize_step_interface" => Normalizer.Task(method(:normalize_step_interface)),
|
98
|
+
"activity.normalize_step_interface" => Normalizer.Task(method(:normalize_step_interface)), # Makes sure {:options} is always a hash.
|
99
|
+
"activity.macro_options_with_symbol_task" => Normalizer.Task(method(:macro_options_with_symbol_task)), # DISCUSS: we might deprecate {task: :instance_method}
|
100
|
+
|
82
101
|
"activity.merge_library_options" => Normalizer.Task(method(:merge_library_options)), # Merge "macro"/user options over library options.
|
83
102
|
"activity.normalize_for_macro" => Normalizer.Task(method(:merge_user_options)), # Merge user_options over "macro" options.
|
84
103
|
"activity.normalize_normalizer_options" => Normalizer.Task(method(:merge_normalizer_options)), # Merge user_options over normalizer_options.
|
85
104
|
"activity.normalize_non_symbol_options" => Normalizer.Task(method(:normalize_non_symbol_options)),
|
86
105
|
"activity.path_helper.forward_block" => Normalizer.Task(Helper::Path::Normalizer.method(:forward_block_for_path_branch)), # forward the "global" block
|
87
106
|
"activity.normalize_context" => method(:normalize_context),
|
107
|
+
"activity.id_with_inherit_and_replace" => Normalizer.Task(method(:id_with_inherit_and_replace)),
|
88
108
|
"activity.normalize_id" => Normalizer.Task(method(:normalize_id)),
|
89
|
-
"activity.normalize_override" => Normalizer.Task(method(:normalize_override)),
|
109
|
+
"activity.normalize_override" => Normalizer.Task(method(:normalize_override)), # TODO: remove!
|
90
110
|
"activity.wrap_task_with_step_interface" => Normalizer.Task(method(:wrap_task_with_step_interface)),
|
91
111
|
|
92
|
-
|
112
|
+
# Nested pipeline:
|
113
|
+
"activity.default_outputs" => defaults_for_outputs, # only {if :outputs.nil?}
|
114
|
+
|
115
|
+
"extensions.convert_extensions_option_to_tuples" => Normalizer.Task(Extensions.method(:convert_extensions_option_to_tuples)),
|
116
|
+
|
117
|
+
"inherit.recall_recorded_options" => Normalizer.Task(Inherit.method(:recall_recorded_options)),
|
93
118
|
"activity.sequence_insert" => Normalizer.Task(method(:normalize_sequence_insert)),
|
94
119
|
"activity.normalize_duplications" => Normalizer.Task(method(:normalize_duplications)),
|
95
120
|
|
96
|
-
"activity.path_helper.path_to_track"
|
97
|
-
|
98
|
-
|
121
|
+
"activity.path_helper.path_to_track" => Normalizer.Task(Helper::Path::Normalizer.method(:convert_paths_to_tracks)),
|
122
|
+
|
123
|
+
|
124
|
+
"output_tuples.normalize_output_tuples" => Normalizer.Task(OutputTuples.method(:normalize_output_tuples)), # Output(Signal, :semantic) => Id()
|
125
|
+
"output_tuples.remember_custom_output_tuples" => Normalizer.Task(OutputTuples.method(:remember_custom_output_tuples)), # Output(Signal, :semantic) => Id()
|
126
|
+
"output_tuples.register_additional_outputs" => Normalizer.Task(OutputTuples.method(:register_additional_outputs)), # Output(Signal, :semantic) => Id()
|
127
|
+
"output_tuples.filter_inherited_output_tuples" => Normalizer.Task(OutputTuples.method(:filter_inherited_output_tuples)),
|
128
|
+
|
129
|
+
"activity.wirings" => Normalizer.Task(OutputTuples::Connections.method(:compile_wirings)),
|
99
130
|
|
100
|
-
|
131
|
+
|
132
|
+
"extensions.compile_extensions" => Normalizer.Task(Extensions.method(:compile_extensions)),
|
133
|
+
"extensions.compile_recorded_extensions" => Normalizer.Task(Extensions.method(:compile_recorded_extensions)),
|
134
|
+
|
135
|
+
# DISCUSS: make this configurable? maybe lots of folks don't want {:inherit}?
|
136
|
+
"inherit.compile_recorded_options" => Normalizer.Task(Inherit.method(:compile_recorded_options)),
|
101
137
|
|
102
138
|
# TODO: make this a "Subprocess":
|
103
139
|
"activity.compile_data" => Normalizer.Task(method(:compile_data)),
|
104
140
|
"activity.create_row" => Normalizer.Task(method(:create_row)),
|
105
141
|
"activity.create_add" => Normalizer.Task(method(:create_add)),
|
106
142
|
"activity.create_adds" => Normalizer.Task(method(:create_adds)),
|
107
|
-
}
|
108
|
-
collect { |id, task| TaskWrap::Pipeline.Row(id, task) }
|
143
|
+
}
|
144
|
+
.collect { |id, task| TaskWrap::Pipeline.Row(id, task) }
|
109
145
|
)
|
146
|
+
end
|
147
|
+
|
148
|
+
# DISCUSS: should we remove this special case?
|
149
|
+
# This handles
|
150
|
+
# step task: :instance_method_exposing_circuit_interface
|
151
|
+
def macro_options_with_symbol_task(ctx, options:, **)
|
152
|
+
return if options[:wrap_task]
|
153
|
+
return unless options[:task].is_a?(Symbol)
|
110
154
|
|
111
|
-
|
155
|
+
ctx[:options] = {
|
156
|
+
**options,
|
157
|
+
wrap_task: true,
|
158
|
+
step_interface_builder: ->(task) { Trailblazer::Option(task) } # only wrap in Option, not {TaskAdapter}.
|
159
|
+
}
|
112
160
|
end
|
113
161
|
|
162
|
+
# @param {:options} The first argument passed to {#step}
|
163
|
+
# After this step, options is always a hash.
|
164
|
+
#
|
114
165
|
# Specific to the "step DSL": if the first argument is a callable, wrap it in a {step_interface_builder}
|
115
166
|
# since its interface expects the step interface, but the circuit will call it with circuit interface.
|
116
167
|
def normalize_step_interface(ctx, options:, **)
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
else
|
127
|
-
# step task: Callable, ... (Subprocess, Proc, macros etc)
|
128
|
-
options # NOOP
|
129
|
-
end
|
130
|
-
else
|
131
|
-
# Step Interface
|
132
|
-
# step :find, ...
|
133
|
-
# step Callable, ... (Method, Proc etc)
|
134
|
-
{ task: options, wrap_task: true }
|
135
|
-
end
|
136
|
-
|
137
|
-
ctx[:options] = options
|
168
|
+
return if options.is_a?(Hash)
|
169
|
+
|
170
|
+
# Step Interface
|
171
|
+
# step :find, ...
|
172
|
+
# step Callable, ... (Method, Proc etc)
|
173
|
+
ctx[:options] = {
|
174
|
+
task: options,
|
175
|
+
wrap_task: true # task exposes step interface.
|
176
|
+
}
|
138
177
|
end
|
139
178
|
|
140
|
-
|
179
|
+
# @param :wrap_task If true, the {:task} is wrapped using the step_interface_builder, meaning the
|
180
|
+
# task is expecting the step interface.
|
181
|
+
def wrap_task_with_step_interface(ctx, step_interface_builder:, task:, wrap_task: false, **)
|
141
182
|
return unless wrap_task
|
142
183
|
|
143
184
|
ctx[:task] = step_interface_builder.(task)
|
144
185
|
end
|
145
186
|
|
146
|
-
def normalize_id(ctx, id: false,
|
187
|
+
def normalize_id(ctx, task:, id: false, **)
|
147
188
|
ctx[:id] = id || task
|
148
189
|
end
|
149
190
|
|
191
|
+
# TODO: remove {#normalize_override} in 1.2.0 (Used in macro-contract tests).
|
150
192
|
# {:override} really only makes sense for {step Macro(), {override: true}} where the {user_options}
|
151
193
|
# dictate the overriding.
|
152
194
|
def normalize_override(ctx, id:, override: false, **)
|
153
195
|
return unless override
|
196
|
+
|
197
|
+
Activity::Deprecate.warn Linear::Deprecate.dsl_caller_location, "The :override option is deprecated and will be removed. Please use :replace instead."
|
198
|
+
|
154
199
|
ctx[:replace] = (id || raise)
|
155
200
|
end
|
156
201
|
|
@@ -176,20 +221,6 @@ module Trailblazer
|
|
176
221
|
return ctx, flow_options
|
177
222
|
end
|
178
223
|
|
179
|
-
# Compile the actual {Seq::Row}'s {wiring}.
|
180
|
-
# This combines {:connections} and {:outputs}
|
181
|
-
def compile_wirings(ctx, connections:, outputs:, id:, **)
|
182
|
-
ctx[:wirings] =
|
183
|
-
connections.collect do |semantic, (search_strategy_builder, *search_args)|
|
184
|
-
output = outputs[semantic] || raise("No `#{semantic}` output found for #{id.inspect} and outputs #{outputs.inspect}")
|
185
|
-
|
186
|
-
search_strategy_builder.( # return proc to be called when compiling Seq, e.g. {ById(output, :id)}
|
187
|
-
output,
|
188
|
-
*search_args
|
189
|
-
)
|
190
|
-
end
|
191
|
-
end
|
192
|
-
|
193
224
|
# Processes {:before,:after,:replace,:delete} options and
|
194
225
|
# defaults to {before: "End.success"} which, yeah.
|
195
226
|
def normalize_sequence_insert(ctx, end_id:, **)
|
@@ -205,10 +236,10 @@ module Trailblazer
|
|
205
236
|
# @private
|
206
237
|
def sequence_insert_options
|
207
238
|
{
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
239
|
+
before: :Prepend,
|
240
|
+
after: :Append,
|
241
|
+
replace: :Replace,
|
242
|
+
delete: :Delete
|
212
243
|
}
|
213
244
|
end
|
214
245
|
|
@@ -231,7 +262,6 @@ module Trailblazer
|
|
231
262
|
ctx[:task] = task.clone if sequence.find { |row| row[1] == task }
|
232
263
|
end
|
233
264
|
|
234
|
-
|
235
265
|
# Move DSL user options such as {Output(:success) => Track(:found)} to
|
236
266
|
# a new key {options[:non_symbol_options]}.
|
237
267
|
# This allows using {options} as a {**ctx}-able hash in Ruby 2.6 and 3.0.
|
@@ -243,97 +273,14 @@ module Trailblazer
|
|
243
273
|
ctx[:options] = symbol_options.merge(non_symbol_options: non_symbol_options)
|
244
274
|
end
|
245
275
|
|
246
|
-
#
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
return unless
|
251
|
-
|
252
|
-
# DISCUSS: how could we add another magnetic_to to an end?
|
253
|
-
output_configs.each do |output, cfg|
|
254
|
-
new_connections, add =
|
255
|
-
if cfg.is_a?(Linear::Track)
|
256
|
-
[output_to_track(ctx, output, cfg), cfg.adds] # FIXME: why does Track have a {adds} field? we don't use it anywhere.
|
257
|
-
elsif cfg.is_a?(Linear::Id)
|
258
|
-
[output_to_id(ctx, output, cfg.value), []]
|
259
|
-
elsif cfg.is_a?(Activity::End)
|
260
|
-
end_id = Activity::Railway.end_id(**cfg.to_h)
|
261
|
-
end_exists = Activity::Adds::Insert.find_index(ctx[:sequence], end_id)
|
262
|
-
|
263
|
-
_adds = end_exists ? [] : add_terminus(cfg, id: end_id, sequence: sequence, normalizers: normalizers)
|
264
|
-
|
265
|
-
[output_to_id(ctx, output, end_id), _adds]
|
266
|
-
else
|
267
|
-
raise cfg.inspect
|
268
|
-
end
|
269
|
-
|
270
|
-
connections = connections.merge(new_connections)
|
271
|
-
adds += add
|
272
|
-
end
|
273
|
-
|
274
|
-
ctx[:connections] = connections
|
275
|
-
ctx[:adds] = adds
|
276
|
-
end
|
277
|
-
|
278
|
-
def output_to_track(ctx, output, track)
|
279
|
-
search_strategy = track.options[:wrap_around] ? :WrapAround : :Forward
|
280
|
-
|
281
|
-
{output.value => [Linear::Sequence::Search.method(search_strategy), track.color]}
|
282
|
-
end
|
283
|
-
|
284
|
-
def output_to_id(ctx, output, target)
|
285
|
-
{output.value => [Linear::Sequence::Search.method(:ById), target]}
|
286
|
-
end
|
287
|
-
|
288
|
-
# Returns ADDS for the new terminus.
|
289
|
-
def add_terminus(end_event, id:, sequence:, normalizers:)
|
290
|
-
step_options = Linear::Sequence::Builder.invoke_normalizer_for(:terminus, end_event, {id: id}, sequence: sequence, normalizer_options: {}, normalizers: normalizers)
|
276
|
+
# Whenever {:replace} and {:inherit} are passed, automatically assign {:id}.
|
277
|
+
# DISCUSS: this step could be nested in {inherit_option}.
|
278
|
+
def id_with_inherit_and_replace(ctx, id: nil, replace: nil, inherit: nil, **)
|
279
|
+
return if id
|
280
|
+
return unless inherit # inherit: true and inherit: [] both work.
|
281
|
+
return unless replace
|
291
282
|
|
292
|
-
|
293
|
-
end
|
294
|
-
|
295
|
-
# Output(Signal, :semantic) => Id()
|
296
|
-
def normalize_outputs_from_dsl(ctx, non_symbol_options:, outputs:, **)
|
297
|
-
output_configs = non_symbol_options.find_all{ |k,v| k.kind_of?(Activity::Output) }
|
298
|
-
return unless output_configs.any?
|
299
|
-
|
300
|
-
dsl_options = {}
|
301
|
-
|
302
|
-
output_configs.collect do |output, cfg| # {cfg} = Track(:success)
|
303
|
-
outputs = outputs.merge(output.semantic => output)
|
304
|
-
dsl_options = dsl_options.merge(Linear::Strategy.Output(output.semantic) => cfg)
|
305
|
-
end
|
306
|
-
|
307
|
-
ctx[:outputs] = outputs
|
308
|
-
ctx[:non_symbol_options] = non_symbol_options.merge(dsl_options)
|
309
|
-
end
|
310
|
-
|
311
|
-
# Currently, the {:inherit} option copies over {:connections} from the original step
|
312
|
-
# and merges them with the (prolly) connections passed from the user.
|
313
|
-
def inherit_option(ctx, inherit: false, sequence:, id:, extensions: [], **)
|
314
|
-
return unless inherit === true
|
315
|
-
|
316
|
-
row = InheritOption.find_row(sequence, id) # from this row we're inheriting options.
|
317
|
-
|
318
|
-
inherited_connections = row.data[:connections]
|
319
|
-
inherited_extensions = row.data[:extensions]
|
320
|
-
|
321
|
-
ctx[:connections] = get_inheritable_connections(ctx, inherited_connections)
|
322
|
-
ctx[:extensions] = Array(inherited_extensions) + Array(extensions)
|
323
|
-
end
|
324
|
-
|
325
|
-
module InheritOption # TODO: move all inherit methods in here!
|
326
|
-
def self.find_row(sequence, id)
|
327
|
-
index = Activity::Adds::Insert.find_index(sequence, id)
|
328
|
-
sequence[index]
|
329
|
-
end
|
330
|
-
end
|
331
|
-
|
332
|
-
# return connections from {parent} step which are supported by current step
|
333
|
-
private def get_inheritable_connections(ctx, parent_connections)
|
334
|
-
return parent_connections unless ctx[:outputs]
|
335
|
-
|
336
|
-
parent_connections.slice(*ctx[:outputs].keys)
|
283
|
+
ctx[:id] = replace
|
337
284
|
end
|
338
285
|
|
339
286
|
def create_row(ctx, task:, wirings:, magnetic_to:, data:, **)
|
@@ -350,13 +297,14 @@ module Trailblazer
|
|
350
297
|
|
351
298
|
# TODO: document DataVariable() => :name
|
352
299
|
# Compile data that goes into the sequence row.
|
353
|
-
def compile_data(ctx, default_variables_for_data: [:id, :dsl_track, :
|
354
|
-
variables_for_data = non_symbol_options
|
300
|
+
def compile_data(ctx, non_symbol_options:, default_variables_for_data: [:id, :dsl_track, :extensions], **)
|
301
|
+
variables_for_data = non_symbol_options
|
302
|
+
.find_all { |k, v| k.instance_of?(Linear::DataVariableName) }
|
303
|
+
.flat_map { |k, v| Array(v) }
|
355
304
|
|
356
305
|
ctx[:data] = (default_variables_for_data + variables_for_data).collect { |key| [key, ctx[key]] }.to_h
|
357
306
|
end
|
358
307
|
end
|
359
|
-
|
360
308
|
end # Normalizer
|
361
309
|
end
|
362
310
|
end
|
@@ -13,7 +13,7 @@ module Trailblazer
|
|
13
13
|
# @private
|
14
14
|
# Run a specific normalizer (e.g. for `#step`), apply the adds to the sequence and return the latter.
|
15
15
|
# DISCUSS: where does this method belong? Sequence + Normalizers?
|
16
|
-
def self.update_sequence_for(type, task, options={}, sequence:, **kws, &block)
|
16
|
+
def self.update_sequence_for(type, task, options = {}, sequence:, **kws, &block)
|
17
17
|
step_options = invoke_normalizer_for(type, task, options, sequence: sequence, **kws, &block)
|
18
18
|
|
19
19
|
_sequence = Activity::Adds.apply_adds(sequence, step_options[:adds])
|
@@ -32,7 +32,8 @@ module Trailblazer
|
|
32
32
|
sequence: sequence,
|
33
33
|
}
|
34
34
|
|
35
|
-
_step_options = normalizers.(
|
35
|
+
_step_options = normalizers.(
|
36
|
+
type,
|
36
37
|
normalizer_options: normalizer_options, # class-level Strategy configuration, such as :step_interface_builder
|
37
38
|
options: task, # macro-options
|
38
39
|
user_options: options, # user-specified options from the DSL method
|
@@ -8,16 +8,19 @@ module Trailblazer
|
|
8
8
|
module_function
|
9
9
|
|
10
10
|
# Default strategy to find out what's a stop event is to inspect the TaskRef's {data[:stop_event]}.
|
11
|
-
def
|
12
|
-
intermediate_wiring
|
11
|
+
def find_termini(intermediate_wiring)
|
12
|
+
intermediate_wiring
|
13
|
+
.find_all { |task_ref, _| task_ref.data[:stop_event] }
|
14
|
+
.collect { |task_ref, _| [task_ref.id, task_ref.data.fetch(:semantic)] }
|
15
|
+
.to_h
|
13
16
|
end
|
14
17
|
|
15
18
|
# The first task in the wiring is the default start task.
|
16
|
-
def
|
17
|
-
|
19
|
+
def find_start_task_id(intermediate_wiring) # FIXME: shouldn't we use sequence here? and Row#id?
|
20
|
+
intermediate_wiring.first.first.id
|
18
21
|
end
|
19
22
|
|
20
|
-
def call(sequence, find_stops: method(:
|
23
|
+
def call(sequence, find_stops: method(:find_termini), find_start: method(:find_start_task_id))
|
21
24
|
_implementations, intermediate_wiring =
|
22
25
|
sequence.inject([[], []]) do |(implementations, intermediates), seq_row|
|
23
26
|
_magnetic_to, task, connections, data = seq_row
|
@@ -27,7 +30,7 @@ module Trailblazer
|
|
27
30
|
connections = find_connections(seq_row, connections, sequence)
|
28
31
|
|
29
32
|
# FIXME: {:extensions} should be initialized
|
30
|
-
implementations += [[id, Schema::Implementation::Task(task, connections.collect { |output, _| output }, data[:extensions] || [])
|
33
|
+
implementations += [[id, Schema::Implementation::Task(task, connections.collect { |output, _| output }, data[:extensions] || [])]]
|
31
34
|
|
32
35
|
intermediates += [
|
33
36
|
[
|
@@ -40,29 +43,30 @@ module Trailblazer
|
|
40
43
|
[implementations, intermediates]
|
41
44
|
end
|
42
45
|
|
43
|
-
|
44
|
-
|
46
|
+
start_task_id = find_start.(intermediate_wiring)
|
47
|
+
terminus_to_semantic = find_stops.(intermediate_wiring)
|
45
48
|
|
46
|
-
intermediate = Schema::Intermediate.new(
|
47
|
-
implementation =
|
49
|
+
intermediate = Schema::Intermediate.new(intermediate_wiring.to_h, terminus_to_semantic, start_task_id)
|
50
|
+
implementation = _implementations.to_h
|
48
51
|
|
49
|
-
Schema::Intermediate.(intermediate, implementation) # implemented in the generic {trailblazer-activity} gem.
|
52
|
+
Schema::Intermediate::Compiler.(intermediate, implementation) # implemented in the generic {trailblazer-activity} gem.
|
50
53
|
end
|
51
54
|
|
52
55
|
# private
|
53
56
|
|
54
|
-
|
55
|
-
|
57
|
+
# Execute all search strategies for a row, retrieve outputs and
|
58
|
+
# their respective target IDs.
|
59
|
+
def find_connections(seq_row, searches, sequence)
|
60
|
+
searches.collect do |search|
|
56
61
|
output, target_seq_row = search.(sequence, seq_row) # invoke the node's "connection search" strategy.
|
57
62
|
|
58
63
|
target_seq_row = sequence[-1] if target_seq_row.nil? # connect to an End if target unknown. # DISCUSS: make this configurable, maybe?
|
59
64
|
|
60
65
|
[
|
61
|
-
output,
|
62
|
-
target_seq_row
|
63
|
-
target_seq_row # DISCUSS: needed?
|
66
|
+
output,
|
67
|
+
target_seq_row.id
|
64
68
|
]
|
65
|
-
end
|
69
|
+
end
|
66
70
|
end
|
67
71
|
end # Compiler
|
68
72
|
end # Sequence
|
@@ -11,7 +11,7 @@ class Trailblazer::Activity
|
|
11
11
|
# Note that we only go forward, no back-references are done here.
|
12
12
|
def Forward(output, target_color)
|
13
13
|
->(sequence, me) do
|
14
|
-
target_seq_row = find_in_range(sequence[sequence.index(me)+1..-1], target_color)
|
14
|
+
target_seq_row = find_in_range(sequence[sequence.index(me) + 1..-1], target_color)
|
15
15
|
|
16
16
|
return output, target_seq_row
|
17
17
|
end
|
@@ -23,7 +23,7 @@ class Trailblazer::Activity
|
|
23
23
|
->(sequence, me) do
|
24
24
|
my_index = sequence.index(me)
|
25
25
|
# First, try all elements after me, then go through the elements preceding myself.
|
26
|
-
wrapped_range = sequence[my_index+1..-1] + sequence[0..my_index-1]
|
26
|
+
wrapped_range = sequence[my_index + 1..-1] + sequence[0..my_index - 1]
|
27
27
|
|
28
28
|
target_seq_row = find_in_range(wrapped_range, target_color)
|
29
29
|
|
@@ -31,12 +31,6 @@ class Trailblazer::Activity
|
|
31
31
|
end
|
32
32
|
end
|
33
33
|
|
34
|
-
def Noop(output)
|
35
|
-
->(sequence, me) do
|
36
|
-
return output, [nil,nil,nil,{}] # FIXME
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
34
|
# Find the seq_row with {id} and connect the current node to it.
|
41
35
|
def ById(output, id)
|
42
36
|
->(sequence, me) do
|
@@ -28,10 +28,15 @@ module Trailblazer
|
|
28
28
|
end
|
29
29
|
|
30
30
|
# @public
|
31
|
-
|
32
|
-
|
33
|
-
def step(*args, &block)
|
34
|
-
|
31
|
+
# We forward `step` to the Dsl (State) object.
|
32
|
+
# Recompiling the activity/sequence is a matter specific to Strategy (Railway etc).
|
33
|
+
def step(*args, &block)
|
34
|
+
recompile_activity_for(:step, *args, &block)
|
35
|
+
end
|
36
|
+
|
37
|
+
def terminus(*args)
|
38
|
+
recompile_activity_for(:terminus, *args)
|
39
|
+
end
|
35
40
|
|
36
41
|
private def recompile_activity_for(type, *args, &block)
|
37
42
|
sequence = apply_step_on_sequence_builder(type, *args, &block)
|
@@ -41,16 +46,14 @@ module Trailblazer
|
|
41
46
|
|
42
47
|
# TODO: make {rescue} optional, only in dev mode.
|
43
48
|
# @return Sequence
|
44
|
-
private def apply_step_on_sequence_builder(type, arg, options={}, &block)
|
45
|
-
|
49
|
+
private def apply_step_on_sequence_builder(type, arg, options = {}, &block)
|
50
|
+
Sequence::Builder.(type, arg, options,
|
46
51
|
sequence: @state.get(:sequence),
|
47
52
|
normalizers: @state.get(:normalizers),
|
48
53
|
|
49
54
|
normalizer_options: @state.get(:normalizer_options),
|
50
55
|
|
51
|
-
|
52
|
-
)
|
53
|
-
|
56
|
+
&block)
|
54
57
|
rescue Activity::Adds::IndexError
|
55
58
|
# re-raise this exception with activity class prepended
|
56
59
|
# to the message this time.
|
@@ -90,7 +93,7 @@ module Trailblazer
|
|
90
93
|
|
91
94
|
activity.to_h.to_h.merge(
|
92
95
|
activity: activity,
|
93
|
-
sequence: @state.get(:sequence)
|
96
|
+
sequence: @state.get(:sequence)
|
94
97
|
)
|
95
98
|
end
|
96
99
|
|
@@ -105,8 +108,8 @@ module Trailblazer
|
|
105
108
|
)
|
106
109
|
end
|
107
110
|
|
108
|
-
def invoke(*args)
|
109
|
-
TaskWrap.invoke(self, *args)
|
111
|
+
def invoke(*args, **kws)
|
112
|
+
TaskWrap.invoke(self, *args, **kws)
|
110
113
|
end
|
111
114
|
end # class << self
|
112
115
|
# FIXME: do we want class << self?!
|
@@ -124,7 +127,7 @@ module Trailblazer
|
|
124
127
|
Class.new(strategy) do
|
125
128
|
compile_strategy!(strategy::DSL, normalizers: @state.get(:normalizers), **options)
|
126
129
|
|
127
|
-
class_exec(&block) if
|
130
|
+
class_exec(&block) if block
|
128
131
|
end
|
129
132
|
end
|
130
133
|
|
@@ -153,7 +156,7 @@ module Trailblazer
|
|
153
156
|
sequence = append_terminus(sequence, task, **options_for_append_terminus, **terminus_options)
|
154
157
|
end
|
155
158
|
|
156
|
-
|
159
|
+
sequence
|
157
160
|
end
|
158
161
|
|
159
162
|
def append_terminus(sequence, task, normalizers:, **options)
|
@@ -167,7 +170,6 @@ module Trailblazer
|
|
167
170
|
end
|
168
171
|
end # DSL
|
169
172
|
|
170
|
-
|
171
173
|
# FIXME: move to State#dup
|
172
174
|
def self.copy(value, **) # DISCUSS: should that be here?
|
173
175
|
value.copy
|
@@ -195,5 +197,3 @@ module Trailblazer
|
|
195
197
|
end
|
196
198
|
end
|
197
199
|
end
|
198
|
-
|
199
|
-
|
@@ -16,6 +16,15 @@ class Trailblazer::Activity
|
|
16
16
|
Trailblazer::Activity::Adds::Insert.method(name)
|
17
17
|
end
|
18
18
|
end
|
19
|
+
|
20
|
+
module Deprecate
|
21
|
+
# Used in combination with `Activity::Deprecate.warn`. Guesses the location
|
22
|
+
# of the method call from the stacktrace.
|
23
|
+
def self.dsl_caller_location
|
24
|
+
caller_index = caller_locations.find_index { |location| location.to_s =~ /recompile_activity_for/ }
|
25
|
+
caller_index ? caller_locations[caller_index + 2] : caller_locations[0]
|
26
|
+
end
|
27
|
+
end
|
19
28
|
end # Linear
|
20
29
|
end
|
21
30
|
end
|
@@ -24,6 +33,9 @@ require "trailblazer/activity/dsl/linear/sequence"
|
|
24
33
|
require "trailblazer/activity/dsl/linear/sequence/builder"
|
25
34
|
require "trailblazer/activity/dsl/linear/sequence/search"
|
26
35
|
require "trailblazer/activity/dsl/linear/sequence/compiler"
|
36
|
+
require "trailblazer/activity/dsl/linear/normalizer/inherit" # DISCUSS. should we add normalizer/options/... or something?
|
37
|
+
require "trailblazer/activity/dsl/linear/normalizer/extensions"
|
38
|
+
require "trailblazer/activity/dsl/linear/normalizer/output_tuples"
|
27
39
|
require "trailblazer/activity/dsl/linear/normalizer"
|
28
40
|
require "trailblazer/activity/dsl/linear/normalizer/terminus"
|
29
41
|
require "trailblazer/activity/dsl/linear/helper"
|
@@ -36,7 +48,6 @@ require "trailblazer/activity/dsl/linear/feature/variable_mapping"
|
|
36
48
|
require "trailblazer/activity/dsl/linear/feature/variable_mapping/dsl"
|
37
49
|
require "trailblazer/activity/dsl/linear/feature/variable_mapping/runtime"
|
38
50
|
require "trailblazer/activity/dsl/linear/feature/patch"
|
39
|
-
require "trailblazer/activity/dsl/linear/feature/variable_mapping/inherit"
|
40
51
|
|
41
52
|
# feature/variable_mapping
|
42
53
|
Trailblazer::Activity::DSL::Linear::VariableMapping.extend!(Trailblazer::Activity::Path, :step)
|