trailblazer-activity-dsl-linear 1.1.0 → 1.2.0

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.
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