trailblazer-activity-dsl-linear 1.1.0 → 1.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.github/workflows/ci.yml +2 -5
- data/CHANGES.md +76 -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 +26 -32
- 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 +6 -8
- metadata +23 -38
- 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)
|