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.
Files changed (31) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -5
  3. data/CHANGES.md +72 -0
  4. data/Gemfile +6 -3
  5. data/lib/trailblazer/activity/dsl/linear/feature/merge.rb +2 -2
  6. data/lib/trailblazer/activity/dsl/linear/feature/patch.rb +9 -9
  7. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/dsl.rb +19 -29
  8. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/runtime.rb +6 -8
  9. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping.rb +25 -35
  10. data/lib/trailblazer/activity/dsl/linear/helper/path.rb +37 -18
  11. data/lib/trailblazer/activity/dsl/linear/helper.rb +27 -18
  12. data/lib/trailblazer/activity/dsl/linear/normalizer/extensions.rb +63 -0
  13. data/lib/trailblazer/activity/dsl/linear/normalizer/inherit.rb +90 -0
  14. data/lib/trailblazer/activity/dsl/linear/normalizer/output_tuples.rb +160 -0
  15. data/lib/trailblazer/activity/dsl/linear/normalizer/terminus.rb +26 -29
  16. data/lib/trailblazer/activity/dsl/linear/normalizer.rb +96 -148
  17. data/lib/trailblazer/activity/dsl/linear/sequence/builder.rb +3 -2
  18. data/lib/trailblazer/activity/dsl/linear/sequence/compiler.rb +21 -17
  19. data/lib/trailblazer/activity/dsl/linear/sequence/search.rb +2 -8
  20. data/lib/trailblazer/activity/dsl/linear/strategy.rb +17 -17
  21. data/lib/trailblazer/activity/dsl/linear/version.rb +1 -1
  22. data/lib/trailblazer/activity/dsl/linear.rb +12 -1
  23. data/lib/trailblazer/activity/fast_track.rb +91 -54
  24. data/lib/trailblazer/activity/path.rb +22 -29
  25. data/lib/trailblazer/activity/railway.rb +60 -54
  26. data/trailblazer-activity-dsl-linear.gemspec +7 -8
  27. metadata +21 -36
  28. data/.github/workflows/ci_jruby.yml +0 -19
  29. data/.github/workflows/ci_legacy.yml +0 -19
  30. data/.github/workflows/ci_truffleruby.yml +0 -19
  31. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/inherit.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 87302630d03df0e0e40ad7e7b9902744a1b9d7586e157018eab7652c6ad7276c
4
- data.tar.gz: 10a821885b6a9e4228a0e04545d28689d28f4d3470f74b5f597f6d9bc1b4dd50
3
+ metadata.gz: 555d1c8af700e756c437e913546c302f4630cb0ba3066b97cae7deb67e25f055
4
+ data.tar.gz: e0fc5141498776365ff62c873d9d379bbd2f3bbfebc177939e7e18057503ee6c
5
5
  SHA512:
6
- metadata.gz: '08a071547063505433e4400c7f5e23c8203c72f125397bf71af8402050d728e1e5995fc71f5cd23a8da362c277bedb16a71e9d4f0b5f1c439d96eed82c4589fc'
7
- data.tar.gz: 11e54d0175baa4fa338605faf1ac44ef1ef891a763890730c44119a239f11ea2f37497c80156bc2895a11b7b0a6ce58e9349e4a44e49f90c3dc48535ff179b57
6
+ metadata.gz: 7d57fa76cde08343769eb8d5feba10f830635738db77c6c732c3df1adadd13e0a6b865a3e5ff2ba6b6cdb3f4adce898f163fb8614e318d9070c98ef896c7322e
7
+ data.tar.gz: d2691ec2bf75287fd88b089d3764baccdfb2eaa0234b11a2954afae891e63e7262979004eb81d8fc7b204ba2c415f70a75177594400acb1a2ef736050b008864
@@ -1,6 +1,3 @@
1
- ## This file is managed by Terraform.
2
- ## Do not modify this file directly, as it may be overwritten.
3
- ## Please open an issue instead.
4
1
  name: CI
5
2
  on: [push, pull_request]
6
3
  jobs:
@@ -8,12 +5,12 @@ jobs:
8
5
  strategy:
9
6
  fail-fast: false
10
7
  matrix:
11
- ruby: [2.7, '3.0', '3.1']
8
+ ruby: [2.5, 2.6, 2.7, '3.0', '3.1', '3.2', 'head', 'jruby']
12
9
  runs-on: ubuntu-latest
13
10
  steps:
14
11
  - uses: actions/checkout@v3
15
12
  - uses: ruby/setup-ruby@v1
16
13
  with:
17
14
  ruby-version: ${{ matrix.ruby }}
18
- bundler-cache: true
15
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
19
16
  - run: bundle exec rake
data/CHANGES.md CHANGED
@@ -1,3 +1,75 @@
1
+ # 1.2
2
+
3
+ ## Introspect
4
+
5
+ * As `Activity::Introspect::TaskMap` got removed, use `Activity::Introspect.Nodes(activity)` for introspecting. See https://trailblazer.to/2.1/docs/activity#activity-internals-introspection-api
6
+
7
+ ## Normalizer
8
+
9
+ * Extract `normalizer/extension.rb` to implement `Extension() => myext`
10
+ * Extract `normalizer/inherit.rb` to implement `inherit: true`.
11
+ * Extract `normalizer/output_tuples.rb` which represents code for the Wiring API.
12
+ * Connectors (`Track()`, `Id()` and `End()`) now contain the logic that returns the search builder. This used to sit in `#normalize_connections_from_dsl`.
13
+ * What used to be the `"path.outputs"` step is now a separate, nested pipeline named `"activity.default_outputs"`. See https://trailblazer.to/2.1/docs/internals#internals-wiring-api-outputs-defaulting
14
+ Basically, The default step's outputs are set in that separate pipeline under `"activity.default_outputs"`.
15
+ * Rename `"path.connections"` to `"path.step.add_success_connector"` for consistency.
16
+ * Move `Railway::DSL::NormalizerForPass` to `Railway::DSL::Pass::Normalizer` (same for `Fail`).
17
+ * Move `FastTrack::DSL::NormalizerForPass` to `FastTrack::DSL::Pass::Normalizer` (same for `Fail`).
18
+ * Remove `"activity.normalize_outputs_from_dsl"` as this all happens in `#compile_wirings` now.
19
+
20
+ ## Various
21
+
22
+ * Deprecate `Path(end_id:, end_task:)` options in favor of `Path(terminus: :semantic)`.
23
+ * `FastTrack` outputs for non-`Subprocess()` are only added when `fast_track: true` is set.
24
+ As a result, this will throw an exception `No `pass_fast` output found for :find_model`.
25
+
26
+ ```ruby
27
+ step :find_model, Output(:pass_fast) # throws "no output" exception.
28
+ ```
29
+
30
+ and needs to be changed to
31
+
32
+ ```ruby
33
+ step :find_model,
34
+ fast_track: true,
35
+ Output(:pass_fast)
36
+ ```
37
+ * Fixed a bug where `Subprocess(Path)` would accidentially add a `:failure` connection.
38
+ As a result, this doesn't work anymore
39
+
40
+ ```ruby
41
+ step Subprocess(Path), Output(:failure) => ...
42
+ ```
43
+ * Allow inheriting of `:fail_fast`, `:pass_fast` and `:fast_track`.
44
+ * The `:outputs` option for `#step` is now a private concept. When passed explicitely to the normalizer (as it happens with `Subprocess()`) it's no longer extended or defaulted.
45
+ * `Strategy.End()` now returns an `OutputTuples::End` instance. Use `Activity.End()` for the original behavior.
46
+ * Removed the `:connections` option in favor of simply using output tuples for setting connections. We also don't inherit `:connections` anymore, but the output tuples.
47
+ * Removed the `VariableMapping::Inherit` module as we can use generic inheritance logic.
48
+ * Finally add the `Extension() => my_ext` option to painlessly add extensions. This means you don't have to manually merge `:extensions` anymore.
49
+ * Extensions are now properly inherited (if `generic?` is false) using the universal inheritance mechanism.
50
+ * `Strategy.invoke` now passes on keyword arguments, too.
51
+ * A terminus step no longer maintains any wirings (as per `trailblazer-activity-0.16.0`), resulting in a terminus `Sequence` row as follows.
52
+
53
+ ```ruby
54
+ [
55
+ :success,
56
+ implementing::Success,
57
+ [], # no outputs anymore!
58
+ {id: "End.success", stop_event: true, semantic: :success}, # instead, {:semantic} is passed as a data option.
59
+ ]
60
+ ```
61
+ * Remove `Search::Noop` as an empty wirings array in `Sequence` are allowed now.
62
+
63
+ # 1.1.1
64
+
65
+ * When using `step ..., inherit: true, replace: :find_model` you can now omit `:id`. The ID from
66
+ `:replace` is used automatically in that case.
67
+ * Deprecate `:override` option for `#step`.
68
+ * Simplify `inherit: [:variable_mapping]` by recording the `:in_filters` and `:out_filters` variables
69
+ instead of the compiled pipelines. This fixes #61.
70
+ * Introduce `#patch` to simplify modifying nested activities. Instead of `Subprocess(<activity>, patch: ...)` you can use
71
+ the dedicated DSL function.
72
+
1
73
  # 1.1.0
2
74
 
3
75
  * Use `trailblazer-activity` 0.15.0.
data/Gemfile CHANGED
@@ -5,11 +5,14 @@ gemspec
5
5
 
6
6
  gem "minitest-line"
7
7
 
8
- # gem "trailblazer-developer", path: "../trailblazer-developer"
8
+ # gem "trailblazer-developer", path: "../trailblazer-developer"
9
9
  # gem "trailblazer-developer", github: "trailblazer/trailblazer-developer"
10
10
  # gem "trailblazer-declarative", path: "../trailblazer-declarative"
11
- # gem "trailblazer-activity", path: "../trailblazer-activity"
11
+ # gem "trailblazer-activity", path: "../trailblazer-activity"
12
12
  # gem "trailblazer-activity", github: "trailblazer/trailblazer-activity"
13
13
  # gem "trailblazer-activity", path: "../circuit"
14
- gem "benchmark-ips"
14
+
15
+ # gem "benchmark-ips"
16
+ # gem "stackprof"
17
+ # gem "standard"
15
18
  # gem "trailblazer-core-utils", path: "../trailblazer-core-utils"
@@ -21,14 +21,14 @@ class Trailblazer::Activity
21
21
 
22
22
  _seq = Adds.apply_adds(
23
23
  old_seq,
24
- new_seq.collect { |row| {insert: [Adds::Insert.method(:Prepend), end_id], row: row } }
24
+ new_seq.collect { |row| {insert: [Adds::Insert.method(:Prepend), end_id], row: row} }
25
25
  )
26
26
  end
27
27
 
28
28
  def self.strip_start_and_ends(seq, end_id:)
29
29
  cut_off_index = end_id.nil? ? seq.size : Adds::Insert.find_index(seq, end_id) # find the "first" end.
30
30
 
31
- seq[1..cut_off_index-1]
31
+ seq[1..cut_off_index - 1]
32
32
  end
33
33
  end # Merge
34
34
  end
@@ -1,16 +1,11 @@
1
1
  class Trailblazer::Activity
2
2
  module DSL
3
3
  module Linear
4
- def self.Patch(activity, instructions)
5
- Patch.customize(activity, options: instructions)
6
- end
7
-
8
4
  module Patch
9
- # DISCUSS: we could make this a generic DSL option, not just for Subprocess().
10
5
  # Currently, this is called from the Subprocess() helper.
11
6
  def self.customize(activity, options:)
12
7
  options = options.is_a?(Proc) ?
13
- { [] => options } : # hash-wrapping with empty path, for patching given activity itself
8
+ {[] => options} : # hash-wrapping with empty path, for patching given activity itself
14
9
  options
15
10
 
16
11
  options.each do |path, patch|
@@ -20,12 +15,12 @@ class Trailblazer::Activity
20
15
  activity
21
16
  end
22
17
 
23
- def self.call(activity, path, customization)
18
+ def self.call(activity, path, customization, patched_activity: Class.new(activity))
24
19
  task_id, *path = path
25
20
 
26
21
  patch =
27
22
  if task_id
28
- segment_activity = Introspect::TaskMap(activity).find_by_id(task_id).task
23
+ segment_activity = Introspect.Nodes(activity, id: task_id).task
29
24
  patched_segment_activity = call(segment_activity, path, customization)
30
25
 
31
26
  # Replace the patched subprocess.
@@ -34,10 +29,15 @@ class Trailblazer::Activity
34
29
  customization # apply the *actual* patch from the Subprocess() call.
35
30
  end
36
31
 
37
- patched_activity = Class.new(activity)
38
32
  patched_activity.class_exec(&patch)
39
33
  patched_activity
40
34
  end
35
+
36
+ module DSL
37
+ def patch(*path, &block)
38
+ Patch.call(self, path, block, patched_activity: self)
39
+ end
40
+ end
41
41
  end # Patch
42
42
  end
43
43
  end
@@ -11,11 +11,9 @@ module Trailblazer
11
11
  module_function
12
12
 
13
13
  # Compute pipeline for In() and Inject().
14
- # We allow to inject {:initial_input_pipeline} here in order to skip creating a new input pipeline and instead
15
- # use the inherit one.
16
14
  def pipe_for_composable_input(in_filters: [], initial_input_pipeline: initial_input_pipeline_for(in_filters), **)
17
15
  in_filters = DSL::Tuple.filters_from_options(in_filters)
18
- pipeline = add_filter_steps(initial_input_pipeline, in_filters)
16
+ _pipeline = add_filter_steps(initial_input_pipeline, in_filters)
19
17
  end
20
18
 
21
19
  # initial pipleline depending on whether or not we got any In() filters.
@@ -25,7 +23,6 @@ module Trailblazer
25
23
  initial_input_pipeline(add_default_ctx: is_inject_only)
26
24
  end
27
25
 
28
-
29
26
  # Adds the default_ctx step as per option {:add_default_ctx}
30
27
  def initial_input_pipeline(add_default_ctx: false)
31
28
  # No In() or {:input}. Use default ctx, which is the original ctxx.
@@ -33,10 +30,10 @@ module Trailblazer
33
30
  default_ctx_row =
34
31
  add_default_ctx ? Activity::TaskWrap::Pipeline.Row(*default_input_ctx_config) : nil
35
32
 
36
- pipe = Activity::TaskWrap::Pipeline.new(
33
+ Activity::TaskWrap::Pipeline.new(
37
34
  [
38
35
  default_ctx_row,
39
- Activity::TaskWrap::Pipeline.Row("input.scope", VariableMapping.method(:scope)), # last step
36
+ Activity::TaskWrap::Pipeline.Row("input.scope", VariableMapping.method(:scope)), # last step
40
37
  ].compact
41
38
  )
42
39
  end
@@ -45,7 +42,7 @@ module Trailblazer
45
42
  ["input.default_input", VariableMapping.method(:default_input_ctx)]
46
43
  end
47
44
 
48
- # Handle {:input} and {:inject} option, the "old" interface.
45
+ # Handle {:input} and {:inject} option, the "old" interface.
49
46
  def add_steps_for_input_option(pipeline, input:)
50
47
  tuple = DSL.In() # simulate {In() => input}
51
48
  input_filter = DSL::Tuple.filters_from_options([[tuple, input]])
@@ -85,7 +82,7 @@ module Trailblazer
85
82
  Activity::Adds.apply_adds(pipeline, adds)
86
83
  end
87
84
 
88
- # Returns array of step rows ("sequence").
85
+ # Returns array of step rows ("sequence").
89
86
  # @param filters [Array] List of {Filter} objects
90
87
  def add_variables_steps_for_filters(filters, path_prefix:)
91
88
  filters.collect do |filter|
@@ -93,7 +90,6 @@ module Trailblazer
93
90
  end
94
91
  end
95
92
 
96
-
97
93
  # Keeps user's DSL configuration for a particular io-pipe step.
98
94
  # Implements the interface for the actual I/O code and is DSL code happening in the normalizer.
99
95
  # The actual I/O code expects {DSL::In} and {DSL::Out} objects to generate the two io-pipes.
@@ -102,7 +98,7 @@ module Trailblazer
102
98
  # This is also the reason why a lot of options computation such as {:with_outer_ctx} happens here and not in the IO code.
103
99
 
104
100
  class Tuple
105
- def initialize(variable_name, add_variables_class, filters_builder, add_variables_class_for_callable=nil, insert_args: nil, **options)
101
+ def initialize(variable_name, add_variables_class, filters_builder, add_variables_class_for_callable = nil, insert_args: nil, **options)
106
102
  @options =
107
103
  {
108
104
  variable_name: variable_name,
@@ -121,7 +117,7 @@ module Trailblazer
121
117
  end
122
118
 
123
119
  def self.filters_from_options(tuples_to_user_filters)
124
- tuples_to_user_filters.collect { |tuple, user_filter| tuple.(user_filter) }.flatten(1)
120
+ tuples_to_user_filters.flat_map { |tuple, user_filter| tuple.(user_filter) }
125
121
  end
126
122
 
127
123
  # @return [Filter] Filter instance that keeps {name} and {aggregate_step}.
@@ -161,14 +157,14 @@ module Trailblazer
161
157
  end
162
158
 
163
159
  # callable, producing a hash!
164
-
165
- return build_for_option(user_filter,
166
- name: Filter.name_for(type, user_filter.object_id, :add_variables),
167
- write_name: nil,
168
- read_name: nil,
169
- add_variables_class: add_variables_class_for_callable, # for example, {AddVariables::Output}
170
- **options
171
- )
160
+ build_for_option(
161
+ user_filter,
162
+ name: Filter.name_for(type, user_filter.object_id, :add_variables),
163
+ write_name: nil,
164
+ read_name: nil,
165
+ add_variables_class: add_variables_class_for_callable, # for example, {AddVariables::Output}
166
+ **options
167
+ )
172
168
  # TODO: remove {add_variables_class_for_callable} and make everything SetVariable.
173
169
  end # call
174
170
 
@@ -192,16 +188,13 @@ module Trailblazer
192
188
  class FiltersBuilder
193
189
  def self.call(user_filter, with_outer_ctx:, **options)
194
190
  if with_outer_ctx
195
- callable = user_filter # FIXME: :instance_method, for fuck's sake.
191
+ callable = user_filter # FIXME: :instance_method
196
192
  call_method = callable.respond_to?(:arity) ? callable : callable.method(:call)
197
193
 
198
194
  options =
199
195
  # TODO: remove {if} and only leave {else}.
200
196
  if call_method.arity == 3
201
- index = caller_locations.find_index { |location| location.to_s =~ /recompile_activity_for/ }
202
- caller_location = caller_locations[index+2]
203
-
204
- Activity::Deprecate.warn caller_location,
197
+ Activity::Deprecate.warn Linear::Deprecate.dsl_caller_location,
205
198
  "The positional argument `outer_ctx` is deprecated, please use the `:outer_ctx` keyword argument.\n#{VariableMapping.deprecation_link}"
206
199
 
207
200
  options.merge(
@@ -234,7 +227,6 @@ module Trailblazer
234
227
  add_variables_class,
235
228
  filter_builder,
236
229
  add_variables_class_for_callable,
237
-
238
230
  with_outer_ctx: with_outer_ctx,
239
231
  )
240
232
  end
@@ -292,7 +284,6 @@ module Trailblazer
292
284
  )
293
285
  end
294
286
 
295
-
296
287
  # Build {SetVariable::Default}
297
288
  # {user_filter} is one of the following
298
289
  # :instance_method
@@ -349,7 +340,7 @@ module Trailblazer
349
340
  end
350
341
 
351
342
  def self.build_filters_for_hash(user_filter, **options)
352
- return user_filter.collect do |from_name, to_name|
343
+ user_filter.collect do |from_name, to_name|
353
344
  options = yield(options, from_name, to_name)
354
345
 
355
346
  Filter.build_for_reading(
@@ -363,11 +354,10 @@ module Trailblazer
363
354
  ary.collect { |name| [name, name] }.to_h
364
355
  end
365
356
 
366
- def self.name_for(type, name, specifier=nil)
357
+ def self.name_for(type, name, specifier = nil)
367
358
  [type, specifier].compact.join(".") + "{#{name}}"
368
359
  end
369
360
  end # Filter
370
-
371
361
  end # DSL
372
362
  end
373
363
  end
@@ -33,10 +33,10 @@ module Trailblazer
33
33
  # output_ctx = @filter.(returned_ctx, [original_ctx, returned_flow_options], **original_circuit_options)
34
34
  # Returns {output_ctx} that is used after taskWrap finished.
35
35
  class Output < Input
36
- def call(wrap_ctx, original_args)
37
- returned_ctx, returned_flow_options = wrap_ctx[:return_args] # this is the Context returned from {call}ing the wrapped user task.
38
- original_ctx = wrap_ctx[@id] # grab the original ctx from before which was set in the {:input} filter.
39
- _, original_circuit_options = original_args
36
+ def call(wrap_ctx, original_args)
37
+ returned_ctx, returned_flow_options = wrap_ctx[:return_args] # this is the Context returned from {call}ing the wrapped user task.
38
+ original_ctx = wrap_ctx[@id] # grab the original ctx from before which was set in the {:input} filter.
39
+ _, original_circuit_options = original_args
40
40
 
41
41
  # let user compute the output.
42
42
  pipe_ctx, _ = @pipe.({original_ctx: original_ctx, returned_ctx: returned_ctx, aggregate: {}}, [[original_ctx, returned_flow_options], original_circuit_options])
@@ -97,8 +97,7 @@ module Trailblazer
97
97
 
98
98
  attr_reader :name # TODO: used when adding to pipeline, change to to_h
99
99
 
100
- def call(wrap_ctx, original_args, filter=@filter)
101
-
100
+ def call(wrap_ctx, original_args, filter = @filter)
102
101
  wrap_ctx = self.class.set_variable_for_filter(filter, @write_name, wrap_ctx, original_args)
103
102
 
104
103
  return wrap_ctx, original_args
@@ -193,8 +192,7 @@ module Trailblazer
193
192
  end
194
193
  end # SetVariable
195
194
 
196
-
197
- # AddVariables: I call something with an Option-interface and run the return value through merge_variables().
195
+ # AddVariables: I call something with an Option-interface and run the return value through merge_variables().
198
196
  # works on {:aggregate} by (usually) producing a hash fragment that is merged with the existing {:aggregate}
199
197
 
200
198
  # Add a hash of variables to aggregate after running a filter (which returns a hash!).
@@ -5,11 +5,10 @@ module Trailblazer
5
5
  # Normalizer-steps to implement {:input} and {:output}
6
6
  # Returns an Extension instance to be thrown into the `step` DSL arguments.
7
7
  def self.VariableMapping(input_id: "task_wrap.input", output_id: "task_wrap.output", **options)
8
- input, output, normalizer_options, non_symbol_options = VariableMapping.merge_instructions_from_dsl(**options)
8
+ input, output = VariableMapping.merge_instructions_from_dsl(**options)
9
+ extension = VariableMapping.Extension(input, output)
9
10
 
10
- extension = VariableMapping.Extension(input, output)
11
-
12
- return TaskWrap::Extension::WrapStatic.new(extension: extension), normalizer_options, non_symbol_options
11
+ TaskWrap::Extension::WrapStatic.new(extension: extension)
13
12
  end
14
13
 
15
14
  module VariableMapping
@@ -20,7 +19,7 @@ module Trailblazer
20
19
  normalizer,
21
20
  "activity.wirings",
22
21
  {
23
- # In(), Out(), {:input}, Inject() feature
22
+ # In(), Out(), {:input}, Inject() feature
24
23
  "activity.convert_symbol_options" => Linear::Normalizer.Task(VariableMapping::Normalizer.method(:convert_symbol_options)),
25
24
  "activity.normalize_input_output_filters" => Linear::Normalizer.Task(VariableMapping::Normalizer.method(:normalize_input_output_filters)),
26
25
  "activity.input_output_dsl" => Linear::Normalizer.Task(VariableMapping::Normalizer.method(:input_output_dsl)),
@@ -60,7 +59,7 @@ module Trailblazer
60
59
  inject.collect do |filter|
61
60
  filter = filter.is_a?(Symbol) ? [filter] : filter
62
61
 
63
- dsl_options.merge!(VariableMapping::DSL.Inject() => filter)
62
+ dsl_options.merge!(VariableMapping::DSL.Inject() => filter)
64
63
  end
65
64
  end
66
65
 
@@ -72,43 +71,44 @@ module Trailblazer
72
71
 
73
72
  # Process {In() => [:model], Inject() => [:current_user], Out() => [:model]}
74
73
  def self.normalize_input_output_filters(ctx, non_symbol_options:, input_output_inject_options: [], **)
75
- in_exts = non_symbol_options.find_all { |k,v| k.is_a?(VariableMapping::DSL::In) || k.is_a?(VariableMapping::DSL::Inject) }
76
- output_exts = non_symbol_options.find_all { |k,v| k.is_a?(VariableMapping::DSL::Out) }
74
+ in_exts = non_symbol_options.find_all { |k, v| k.is_a?(VariableMapping::DSL::In) || k.is_a?(VariableMapping::DSL::Inject) }
75
+ output_exts = non_symbol_options.find_all { |k, v| k.is_a?(VariableMapping::DSL::Out) }
77
76
 
78
77
  return unless in_exts.any? || output_exts.any?
79
78
 
80
79
  deprecate_input_output_inject_option(input_output_inject_options, in_exts, output_exts)
81
80
 
82
- ctx[:in_filters] = in_exts
83
- ctx[:out_filters] = output_exts
81
+ ctx[:in_filters] = in_exts
82
+ ctx[:out_filters] = output_exts
84
83
  end
85
84
 
86
- def self.input_output_dsl(ctx, extensions: [], **options)
85
+ def self.input_output_dsl(ctx, non_symbol_options:, in_filters: nil, out_filters: nil, **options)
87
86
  # no :input/:output/:inject/Input()/Output() passed.
88
- return if (options.keys & [:in_filters, :output_filters]).empty?
87
+ return unless in_filters || out_filters
88
+
89
+ extension = Linear.VariableMapping(in_filters: in_filters, out_filters: out_filters, **options)
90
+
91
+ record = Linear::Normalizer::Inherit.Record((in_filters + out_filters).to_h, type: :variable_mapping)
89
92
 
90
- extension, normalizer_options, non_symbol_options = Linear.VariableMapping(**options)
93
+ non_symbol_options = non_symbol_options.merge(record)
94
+ non_symbol_options = non_symbol_options.merge(Linear::Strategy.Extension(is_generic: true) => extension)
91
95
 
92
- ctx[:extensions] = extensions + [extension] # FIXME: allow {Extension() => extension}
93
- ctx.merge!(**normalizer_options) # DISCUSS: is there another way of merging variables into ctx?
94
- ctx[:non_symbol_options].merge!(non_symbol_options)
96
+ ctx.merge!(
97
+ non_symbol_options: non_symbol_options
98
+ )
95
99
  end
96
100
 
97
101
  # TODO: remove for TRB 2.2.
98
102
  def self.deprecate_input_output_inject_option(input_output_inject_options, *composable_options)
99
103
  return unless input_output_inject_options.any?
100
- options, dsl_options = input_output_inject_options
104
+ options, _dsl_options = input_output_inject_options
101
105
 
102
- deprecated_options_count = options.find_all { |(name, option)| option }.count + (options[:inject] ? options[:inject].count-1 : 0)
106
+ deprecated_options_count = options.find_all { |(name, option)| option }.count + (options[:inject] ? options[:inject].count - 1 : 0)
103
107
  composable_options_count = composable_options.collect { |options| options.size }.sum
104
108
 
105
109
  return if composable_options_count == deprecated_options_count
106
110
 
107
- # for deprecation warnings, guess the location if {:input} from the stack.
108
- caller_index = caller_locations.find_index { |location| location.to_s =~ /recompile_activity_for/ }
109
- caller_location = caller_index ? caller_locations[caller_index+2] : caller_locations[0]
110
-
111
- Activity::Deprecate.warn caller_location, %{You are mixing #{options.inspect} with In(), Out() and Inject().\n#{VariableMapping.deprecation_link}}
111
+ Activity::Deprecate.warn Linear::Deprecate.dsl_caller_location, %(You are mixing #{options.inspect} with In(), Out() and Inject().\n#{VariableMapping.deprecation_link})
112
112
  end
113
113
  end
114
114
 
@@ -129,21 +129,11 @@ module Trailblazer
129
129
  output_pipeline = DSL.pipe_for_composable_output(**options)
130
130
  output = Pipe::Output.new(output_pipeline)
131
131
 
132
- return input, output,
133
- # normalizer_options:
134
- {
135
- variable_mapping_pipelines: [pipeline, output_pipeline],
136
- },
137
- # non_symbol_options:
138
- {
139
- Linear::Strategy.DataVariable() => :variable_mapping_pipelines # we want to store {:variable_mapping_pipelines} in {Row.data} for later reference.
140
- }
141
- # DISCUSS: should we remember the pure pipelines or get it from the compiled extension?
142
- # store pipe in the extension (via TW::Extension.data)?
132
+ return input, output
143
133
  end
144
134
 
145
135
  def deprecation_link
146
- %{Please refer to https://trailblazer.to/2.1/docs/activity.html#activity-variable-mapping-deprecation-notes and have a nice day.}
136
+ %(Please refer to https://trailblazer.to/2.1/docs/activity.html#activity-variable-mapping-deprecation-notes and have a nice day.)
147
137
  end
148
138
  end # VariableMapping
149
139
  end
@@ -3,7 +3,7 @@ module Trailblazer
3
3
  module DSL
4
4
  module Linear
5
5
  module Helper
6
- # Normalizer logic for {Path() do end}.
6
+ # Normalizer logic for {Path() do ... end}.
7
7
  #
8
8
  # TODO: it would be cool to be able to connect an (empty) path to specific termini,
9
9
  # this would work if we could add multiple magnetic_to.
@@ -11,6 +11,7 @@ module Trailblazer
11
11
  # Normalizer steps to handle Path() macro.
12
12
  module Normalizer
13
13
  module_function
14
+
14
15
  # Replace a block-expecting {PathBranch} instance with another one that's holding
15
16
  # the global {:block} from {#step ... do end}.
16
17
  def forward_block_for_path_branch(ctx, options:, normalizer_options:, library_options:, **)
@@ -20,12 +21,12 @@ module Trailblazer
20
21
  return unless block
21
22
 
22
23
  output, path_branch =
23
- non_symbol_options.find { |output, cfg| cfg.kind_of?(Linear::PathBranch) }
24
+ non_symbol_options.find { |output, cfg| cfg.is_a?(Linear::PathBranch) }
24
25
 
25
26
  path_branch_with_block = Linear::PathBranch.new(
26
- normalizer_options.
27
- merge(path_branch.options).
28
- merge(block: block)
27
+ normalizer_options
28
+ .merge(path_branch.options)
29
+ .merge(block: block)
29
30
  )
30
31
 
31
32
  ctx[:options] = ctx[:options].merge(non_symbol_options: non_symbol_options.merge(output => path_branch_with_block))
@@ -35,10 +36,10 @@ module Trailblazer
35
36
  # The {Track} instance contains all additional {adds} steps and
36
37
  # is picked up in {Normalizer.normalize_connections_from_dsl}.
37
38
  def convert_paths_to_tracks(ctx, non_symbol_options:, block: false, **)
38
- new_tracks = non_symbol_options.
39
- find_all { |output, cfg| cfg.kind_of?(Linear::PathBranch) }.
40
- collect { |output, cfg| [output, Path.convert_path_to_track(block: ctx[:block], **cfg.options)] }.
41
- to_h
39
+ new_tracks = non_symbol_options
40
+ .find_all { |output, cfg| cfg.is_a?(Linear::PathBranch) }
41
+ .collect { |output, cfg| [output, Path.convert_path_to_track(block: block, **cfg.options)] }
42
+ .to_h
42
43
 
43
44
  ctx[:non_symbol_options] = non_symbol_options.merge(new_tracks)
44
45
  end
@@ -46,7 +47,27 @@ module Trailblazer
46
47
 
47
48
  module_function
48
49
 
49
- def convert_path_to_track(track_color: "track_#{rand}", connect_to: nil, before: false, block: nil, **options)
50
+ def convert_path_to_track(track_color: "track_#{rand}", connect_to: nil, before: false, block: nil, terminus: nil, **options)
51
+ options =
52
+ if end_task = options[:end_task] # TODO: remove in 2.0.
53
+ Activity::Deprecate.warn Linear::Deprecate.dsl_caller_location,
54
+ %(Using `:end_task` and `:end_id` in Path() is deprecated, use `:terminus` instead. Please refer to https://trailblazer.to/2.1/docs/activity.html#activity-wiring-api-path-end_task-end_id-deprecation)
55
+
56
+ options.merge(
57
+ end_task: Activity.End(end_task.to_h[:semantic]),
58
+ end_id: options[:end_id]
59
+ )
60
+ elsif connect_to
61
+ {}
62
+ elsif terminus
63
+ options.merge(
64
+ end_task: Activity.End(terminus),
65
+ end_id: "End.#{terminus}"
66
+ )
67
+ else # Path() with End() inside block.
68
+ {}
69
+ end
70
+
50
71
  # DISCUSS: if anyone overrides `#step` in the "outer" activity, this won't be applied inside the branch.
51
72
 
52
73
  # DISCUSS: use Path::Sequencer::Builder here instead?
@@ -54,7 +75,7 @@ module Trailblazer
54
75
 
55
76
  seq = path.to_h[:sequence]
56
77
  # Strip default ends `Start.default` and `End.success` (if present).
57
- seq = seq[1..-1].reject{ |row| row[3][:stop_event] && row.id == 'End.success' }
78
+ seq = seq[1..-1].reject { |row| row[3][:stop_event] && row.id == "End.success" }
58
79
 
59
80
  if connect_to
60
81
  seq = connect_for_sequence(seq, connect_to: connect_to)
@@ -69,7 +90,7 @@ module Trailblazer
69
90
  insert_method = options[:stop_event] ? Activity::Adds::Insert.method(:Append) : Activity::Adds::Insert.method(:Prepend)
70
91
 
71
92
  insert_target = "End.success" # insert before/after
72
- insert_target = before if before && connect_to.instance_of?(Trailblazer::Activity::DSL::Linear::Track) # FIXME: this is a bit hacky, of course!
93
+ insert_target = before if before && connect_to.instance_of?(Linear::Normalizer::OutputTuples::Track) # FIXME: this is a bit hacky, of course!
73
94
 
74
95
  {
75
96
  row: row,
@@ -78,7 +99,7 @@ module Trailblazer
78
99
  end
79
100
 
80
101
  # Connect the Output() => Track(path_track)
81
- return Linear::Track.new(track_color, adds, {})
102
+ Linear::Normalizer::OutputTuples::Track.new(track_color, adds, {})
82
103
  end
83
104
 
84
105
  # Connect last row of the {sequence} to the given step via its {Id}
@@ -87,16 +108,14 @@ module Trailblazer
87
108
  output, _ = sequence[-1][2][0].(sequence, sequence[-1]) # FIXME: the Forward() proc contains the row's Output, and the only current way to retrieve it is calling the search strategy. It should be Forward#to_h
88
109
 
89
110
  # searches = [Search.ById(output, connect_to.value)]
90
- searches = [Sequence::Search.ById(output, connect_to.value)] if connect_to.instance_of?(Trailblazer::Activity::DSL::Linear::Id)
91
- searches = [Sequence::Search.Forward(output, connect_to.color)] if connect_to.instance_of?(Trailblazer::Activity::DSL::Linear::Track) # FIXME: use existing mapping logic!
111
+ searches = [Sequence::Search.ById(output, connect_to.value)] if connect_to.instance_of?(Linear::Normalizer::OutputTuples::Id)
112
+ searches = [Sequence::Search.Forward(output, connect_to.color)] if connect_to.instance_of?(Linear::Normalizer::OutputTuples::Track) # FIXME: use existing mapping logic!
92
113
 
93
114
  row = sequence[-1]
94
115
  row = row[0..1] + [searches] + [row[3]] # FIXME: not mutating an array is so hard: we only want to replace the "searches" element, index 2
95
116
  row = Sequence::Row[*row]
96
117
 
97
- sequence = sequence[0..-2] + [row]
98
-
99
- sequence
118
+ sequence[0..-2] + [row]
100
119
  end
101
120
  end # Path
102
121
  end