trailblazer-activity-dsl-linear 1.0.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 (29) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/ci.yml +2 -3
  3. data/CHANGES.md +100 -0
  4. data/Gemfile +7 -4
  5. data/Rakefile +1 -1
  6. data/lib/trailblazer/activity/dsl/linear/feature/merge.rb +2 -2
  7. data/lib/trailblazer/activity/dsl/linear/feature/patch.rb +9 -5
  8. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/dsl.rb +241 -156
  9. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/runtime.rb +276 -0
  10. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping.rb +70 -226
  11. data/lib/trailblazer/activity/dsl/linear/helper/path.rb +37 -18
  12. data/lib/trailblazer/activity/dsl/linear/helper.rb +38 -17
  13. data/lib/trailblazer/activity/dsl/linear/normalizer/extensions.rb +63 -0
  14. data/lib/trailblazer/activity/dsl/linear/normalizer/inherit.rb +90 -0
  15. data/lib/trailblazer/activity/dsl/linear/normalizer/output_tuples.rb +160 -0
  16. data/lib/trailblazer/activity/dsl/linear/normalizer/terminus.rb +26 -29
  17. data/lib/trailblazer/activity/dsl/linear/normalizer.rb +99 -160
  18. data/lib/trailblazer/activity/dsl/linear/sequence/builder.rb +3 -2
  19. data/lib/trailblazer/activity/dsl/linear/sequence/compiler.rb +21 -17
  20. data/lib/trailblazer/activity/dsl/linear/sequence/search.rb +2 -8
  21. data/lib/trailblazer/activity/dsl/linear/strategy.rb +56 -17
  22. data/lib/trailblazer/activity/dsl/linear/version.rb +1 -1
  23. data/lib/trailblazer/activity/dsl/linear.rb +13 -1
  24. data/lib/trailblazer/activity/fast_track.rb +96 -67
  25. data/lib/trailblazer/activity/path.rb +35 -53
  26. data/lib/trailblazer/activity/railway.rb +63 -65
  27. data/trailblazer-activity-dsl-linear.gemspec +8 -8
  28. metadata +27 -18
  29. data/lib/trailblazer/activity/dsl/linear/feature/variable_mapping/inherit.rb +0 -38
@@ -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"
@@ -34,8 +46,8 @@ require "trailblazer/activity/railway"
34
46
  require "trailblazer/activity/fast_track"
35
47
  require "trailblazer/activity/dsl/linear/feature/variable_mapping"
36
48
  require "trailblazer/activity/dsl/linear/feature/variable_mapping/dsl"
49
+ require "trailblazer/activity/dsl/linear/feature/variable_mapping/runtime"
37
50
  require "trailblazer/activity/dsl/linear/feature/patch"
38
- require "trailblazer/activity/dsl/linear/feature/variable_mapping/inherit"
39
51
 
40
52
  # feature/variable_mapping
41
53
  Trailblazer::Activity::DSL::Linear::VariableMapping.extend!(Trailblazer::Activity::Path, :step)
@@ -2,63 +2,120 @@ module Trailblazer
2
2
  class Activity
3
3
  # Implementation of the "FastTrack" layout that is also used for `Operation`.
4
4
  class FastTrack < Activity::DSL::Linear::Strategy
5
-
6
5
  # Signals
7
6
  FailFast = Class.new(Signal)
8
7
  PassFast = Class.new(Signal)
9
8
 
10
9
  module DSL
11
10
  Linear = Activity::DSL::Linear
11
+ # The connector logic needs to be run before Railway's connector logic:
12
+ PREPEND_TO = "activity.path_helper.path_to_track"
12
13
 
13
14
  module_function
14
15
 
15
- def Normalizer(base_normalizer=Trailblazer::Activity::Railway::DSL.Normalizer())
16
- Linear::Normalizer.prepend_to(
17
- base_normalizer,
18
- "activity.wirings",
16
+ def Normalizer(prepend_to_default_outputs: [], base_normalizer_builder: Railway::DSL.method(:Normalizer))
17
+ fast_track_output_steps = {
18
+ "fast_track.pass_fast_output" => Linear::Normalizer.Task(method(:add_pass_fast_output)),
19
+ "fast_track.fail_fast_output" => Linear::Normalizer.Task(method(:add_fail_fast_output)),
20
+ "fast_track.fast_track_outputs" => Linear::Normalizer.Task(method(:add_fast_track_outputs)),
21
+ }
22
+
23
+ # Retrieve the base normalizer from {linear/normalizer.rb} and add processing steps.
24
+ step_normalizer = base_normalizer_builder.call( # E.g Railway::DSL.NormalizerForPass.
25
+ prepend_to_default_outputs: [fast_track_output_steps, *prepend_to_default_outputs]
26
+ )
19
27
 
28
+ _normalizer = Linear::Normalizer.prepend_to(
29
+ step_normalizer,
30
+ PREPEND_TO,
20
31
  {
21
- "fast_track.pass_fast_option" => Linear::Normalizer.Task(method(:pass_fast_option)),
22
- "fast_track.fail_fast_option" => Linear::Normalizer.Task(method(:fail_fast_option)),
23
- "fast_track.fast_track_option" => Linear::Normalizer.Task(method(:fast_track_option)),
32
+ "fast_track.record_options" => Linear::Normalizer.Task(method(:record_options)),
33
+ "fast_track.pass_fast_option" => Linear::Normalizer.Task(method(:pass_fast_option)),
34
+ "fast_track.fail_fast_option" => Linear::Normalizer.Task(method(:fail_fast_option)),
35
+ "fast_track.fast_track_option" => Linear::Normalizer.Task(method(:add_fast_track_connectors)),
24
36
  }
25
37
  )
26
38
  end
27
39
 
28
- def NormalizerForFail
29
- pipeline = Normalizer(Railway::DSL.NormalizerForFail())
40
+ module Fail
41
+ module_function
30
42
 
31
- Linear::Normalizer.prepend_to(
32
- pipeline,
33
- "activity.wirings",
43
+ def Normalizer
44
+ pipeline = DSL.Normalizer(base_normalizer_builder: Railway::DSL::Fail.method(:Normalizer))
34
45
 
35
- {
36
- "fast_track.fail_fast_option_for_fail" => Linear::Normalizer.Task(method(:fail_fast_option_for_fail)),
37
- }
38
- )
46
+ Linear::Normalizer.prepend_to(
47
+ pipeline,
48
+ PREPEND_TO,
49
+ {
50
+ "fast_track.fail_fast_option_for_fail" => Linear::Normalizer.Task(DSL.method(:fail_fast_option_for_fail)),
51
+ }
52
+ )
53
+ end
39
54
  end
40
55
 
41
- def NormalizerForPass
42
- pipeline = Normalizer(Railway::DSL.NormalizerForPass())
56
+ module Pass
57
+ module_function
43
58
 
44
- Linear::Normalizer.prepend_to(
45
- pipeline,
46
- "activity.wirings",
59
+ def Normalizer
60
+ pipeline = DSL.Normalizer(base_normalizer_builder: Railway::DSL::Pass.method(:Normalizer))
47
61
 
48
- {
49
- "fast_track.pass_fast_option_for_pass" => Linear::Normalizer.Task(method(:pass_fast_option_for_pass)),
50
- }
62
+ Linear::Normalizer.prepend_to(
63
+ pipeline,
64
+ PREPEND_TO,
65
+ {
66
+ "fast_track.pass_fast_option_for_pass" => Linear::Normalizer.Task(DSL.method(:pass_fast_option_for_pass)),
67
+ }
68
+ )
69
+ end
70
+ end
71
+
72
+ # inherit: true
73
+ RECORD_OPTIONS = [:pass_fast, :fail_fast, :fast_track]
74
+
75
+ # *If* {fast_track: true} (or :pass_fast or :fail_fast), record it using Normalizer::Inherit mechanics.
76
+ def record_options(ctx, non_symbol_options:, **)
77
+ recorded_options =
78
+ RECORD_OPTIONS.collect { |option| ctx.key?(option) ? [option, ctx[option]] : nil }
79
+ .compact
80
+ .to_h
81
+
82
+ ctx.merge!(
83
+ non_symbol_options: non_symbol_options.merge(
84
+ Linear::Normalizer::Inherit.Record(recorded_options, type: :fast_track, non_symbol_options: false)
85
+ )
51
86
  )
52
87
  end
53
88
 
89
+ def add_pass_fast_output(ctx, outputs:, pass_fast: nil, **)
90
+ return unless pass_fast
91
+
92
+ ctx[:outputs] = PASS_FAST_OUTPUT.merge(outputs)
93
+ end
94
+
95
+ def add_fail_fast_output(ctx, outputs:, fail_fast: nil, **)
96
+ return unless fail_fast
97
+
98
+ ctx[:outputs] = FAIL_FAST_OUTPUT.merge(outputs)
99
+ end
100
+
101
+ def add_fast_track_outputs(ctx, outputs:, fast_track: nil, **)
102
+ return unless fast_track
103
+
104
+ ctx[:outputs] = FAIL_FAST_OUTPUT.merge(PASS_FAST_OUTPUT).merge(outputs)
105
+ end
106
+
107
+ PASS_FAST_OUTPUT = {pass_fast: Activity.Output(Activity::FastTrack::PassFast, :pass_fast)}
108
+ FAIL_FAST_OUTPUT = {fail_fast: Activity.Output(Activity::FastTrack::FailFast, :fail_fast)}
109
+
110
+ def add_fast_track_connectors(ctx, fast_track: nil, **)
111
+ ctx = merge_connections_for!(ctx, :fast_track, :pass_fast, :pass_fast, **ctx)
112
+ ctx = merge_connections_for!(ctx, :fast_track, :fail_fast, :fail_fast, **ctx)
113
+ end
114
+
54
115
  def pass_fast_option(ctx, **)
55
116
  ctx = merge_connections_for!(ctx, :pass_fast, :success, **ctx)
56
117
 
57
118
  ctx = merge_connections_for!(ctx, :pass_fast, :pass_fast, :pass_fast, **ctx)
58
- ctx = merge_outputs_for!(ctx,
59
- {pass_fast: Activity.Output(Activity::FastTrack::PassFast, :pass_fast)},
60
- **ctx
61
- )
62
119
  end
63
120
 
64
121
  def pass_fast_option_for_pass(ctx, **)
@@ -70,10 +127,6 @@ module Trailblazer
70
127
  ctx = merge_connections_for!(ctx, :fail_fast, :failure, **ctx)
71
128
 
72
129
  ctx = merge_connections_for!(ctx, :fail_fast, :fail_fast, :fail_fast, **ctx)
73
- ctx = merge_outputs_for!(ctx,
74
- {fail_fast: Activity.Output(Activity::FastTrack::FailFast, :fail_fast)},
75
- **ctx
76
- )
77
130
  end
78
131
 
79
132
  def fail_fast_option_for_fail(ctx, **)
@@ -81,54 +134,30 @@ module Trailblazer
81
134
  ctx = merge_connections_for!(ctx, :fail_fast, :success, **ctx)
82
135
  end
83
136
 
84
- def fast_track_option(ctx, fast_track: false, **)
85
- return unless fast_track
86
-
87
- ctx = merge_connections_for!(ctx, :fast_track, :fail_fast, :fail_fast, **ctx)
88
- ctx = merge_connections_for!(ctx, :fast_track, :pass_fast, :pass_fast, **ctx)
89
-
90
- ctx = merge_outputs_for!(ctx,
91
- {pass_fast: Activity.Output(Activity::FastTrack::PassFast, :pass_fast),
92
- fail_fast: Activity.Output(Activity::FastTrack::FailFast, :fail_fast)},
93
- **ctx
94
- )
95
- end
96
-
97
- def merge_connections_for!(ctx, option_name, semantic, magnetic_to=option_name, connections:, **)
137
+ def merge_connections_for!(ctx, option_name, semantic, magnetic_to=option_name, non_symbol_options:, **)
98
138
  return ctx unless ctx[option_name]
99
139
 
100
- ctx[:connections] = connections.merge(semantic => [Linear::Sequence::Search.method(:Forward), magnetic_to])
101
- ctx
102
- end
140
+ connector = {Linear::Normalizer::OutputTuples.Output(semantic) => Linear::Strategy.Track(magnetic_to)}
103
141
 
104
- def merge_outputs_for!(ctx, new_outputs, outputs:, **)
105
- ctx[:outputs] = new_outputs.merge(outputs)
142
+ ctx[:non_symbol_options] = connector.merge(non_symbol_options)
106
143
  ctx
107
144
  end
108
145
 
109
- def initial_sequence(sequence:, fail_fast_end: Activity::End.new(semantic: :fail_fast), pass_fast_end: Activity::End.new(semantic: :pass_fast), **)
110
- sequence = Path::DSL.append_terminus(sequence, fail_fast_end, magnetic_to: :fail_fast, id: "End.fail_fast", normalizers: Normalizers)
111
- sequence = Path::DSL.append_terminus(sequence, pass_fast_end, magnetic_to: :pass_fast, id: "End.pass_fast", normalizers: Normalizers)
112
- end
113
-
114
146
  # Normalizer pipelines taking care of processing your DSL options.
115
147
  Normalizers = Linear::Normalizer::Normalizers.new(
116
148
  step: FastTrack::DSL.Normalizer(),
117
- fail: FastTrack::DSL.NormalizerForFail(),
118
- pass: FastTrack::DSL.NormalizerForPass(),
149
+ fail: FastTrack::DSL::Fail.Normalizer(),
150
+ pass: FastTrack::DSL::Pass.Normalizer(),
119
151
  terminus: Linear::Normalizer::Terminus.Normalizer(),
120
152
  )
121
153
 
122
- def self.OptionsForSequenceBuilder(**options)
154
+ def options_for_sequence_build(fail_fast_end: Activity::End.new(semantic: :fail_fast), pass_fast_end: Activity::End.new(semantic: :pass_fast), **options)
155
+ fail_fast_terminus_options = [fail_fast_end, magnetic_to: :fail_fast, id: "End.fail_fast", normalizers: Normalizers]
156
+ past_fast_terminus_options = [pass_fast_end, magnetic_to: :pass_fast, id: "End.pass_fast", normalizers: Normalizers]
123
157
 
124
- options = Railway::DSL.OptionsForSequenceBuilder(**options)
158
+ railway_options, railway_termini = Railway::DSL.options_for_sequence_build(**options)
125
159
 
126
- initial_sequence = DSL.initial_sequence(**options)
127
-
128
- {
129
- **options,
130
- sequence: initial_sequence,
131
- }
160
+ return railway_options, railway_termini + [fail_fast_terminus_options, past_fast_terminus_options]
132
161
  end
133
162
  end # DSL
134
163
 
@@ -5,39 +5,43 @@ module Trailblazer
5
5
  # Functions that help creating a path-specific sequence.
6
6
  module DSL
7
7
  Linear = Activity::DSL::Linear
8
+ # Always prepend all "add connectors" steps of all normalizers to normalize_output_tuples.
9
+ # This assures that the order is
10
+ # [<default tuples>, <inherited tuples>, <user tuples>]
11
+ PREPEND_TO = "output_tuples.normalize_output_tuples"
8
12
 
9
13
  module_function
10
14
 
11
- def Normalizer
15
+ def Normalizer(prepend_to_default_outputs: [])
16
+ path_output_steps = {
17
+ "path.outputs" => Linear::Normalizer.Task(method(:add_success_output))
18
+ }
19
+
12
20
  # Retrieve the base normalizer from {linear/normalizer.rb} and add processing steps.
13
- dsl_normalizer = Linear::Normalizer.Normalizer()
21
+ dsl_normalizer = Linear::Normalizer.Normalizer(
22
+ prepend_to_default_outputs: [*prepend_to_default_outputs, path_output_steps]
23
+ )
14
24
 
15
25
  Linear::Normalizer.prepend_to(
16
26
  dsl_normalizer,
17
- # "activity.wirings",
18
- "activity.normalize_outputs_from_dsl",
27
+ PREPEND_TO,
19
28
  {
20
- "path.outputs" => Linear::Normalizer.Task(method(:merge_path_outputs)),
21
- "path.connections" => Linear::Normalizer.Task(method(:merge_path_connections)),
22
- "path.magnetic_to" => Linear::Normalizer.Task(method(:normalize_magnetic_to)),
29
+ "path.step.add_success_connector" => Linear::Normalizer.Task(method(:add_success_connector)),
30
+ "path.magnetic_to" => Linear::Normalizer.Task(method(:normalize_magnetic_to)),
23
31
  }
24
32
  )
25
33
  end
26
34
 
27
- def unary_outputs
28
- {success: Activity::Output(Activity::Right, :success)}
29
- end
35
+ SUCCESS_OUTPUT = {success: Activity::Output(Activity::Right, :success)}
30
36
 
31
- def unary_connections(track_name: :success)
32
- {success: [Linear::Sequence::Search.method(:Forward), track_name]}
37
+ def add_success_output(ctx, **)
38
+ ctx[:outputs] = SUCCESS_OUTPUT
33
39
  end
34
40
 
35
- def merge_path_outputs(ctx, outputs: nil, **)
36
- ctx[:outputs] = outputs || unary_outputs
37
- end
41
+ def add_success_connector(ctx, track_name:, non_symbol_options:, **)
42
+ connectors = {Linear::Normalizer::OutputTuples.Output(:success) => Linear::Strategy.Track(track_name)}
38
43
 
39
- def merge_path_connections(ctx, track_name:, connections: nil, **)
40
- ctx[:connections] = connections || unary_connections(track_name: track_name)
44
+ ctx[:non_symbol_options] = connectors.merge(non_symbol_options)
41
45
  end
42
46
 
43
47
  def normalize_magnetic_to(ctx, track_name:, **) # TODO: merge with Railway.merge_magnetic_to
@@ -45,7 +49,6 @@ module Trailblazer
45
49
  end
46
50
 
47
51
  # This is slow and should be done only once at compile-time,
48
- # DISCUSS: maybe make this a function?
49
52
  # These are the normalizers for an {Activity}, to be injected into a State.
50
53
  Normalizers = Linear::Normalizer::Normalizers.new(
51
54
  step: Normalizer(), # here, we extend the generic FastTrack::step_normalizer with the Activity-specific DSL
@@ -56,39 +59,29 @@ module Trailblazer
56
59
 
57
60
  # DISCUSS: following methods are not part of Normalizer
58
61
 
59
- def append_terminus(sequence, task, normalizers:, **options)
60
- _sequence = Linear::Sequence::Builder.update_sequence_for(:terminus, task, options, normalizers: normalizers, sequence: sequence, normalizer_options: {})
61
- end
62
-
63
62
  # @private
64
63
  def start_sequence(track_name:)
65
- Linear::Strategy::DSL.start_sequence(wirings: [Linear::Sequence::Search::Forward(unary_outputs[:success], track_name)])
64
+ Linear::Strategy::DSL.start_sequence(wirings: [Linear::Sequence::Search::Forward(SUCCESS_OUTPUT[:success], track_name)])
66
65
  end
67
66
 
68
- # Returns an initial two-step sequence with {Start.default > End.success}.
69
- def initial_sequence(track_name:, end_task:, end_id:)
70
- sequence = start_sequence(track_name: track_name)
71
- sequence = append_terminus(sequence, end_task, id: end_id, magnetic_to: track_name, normalizers: Normalizers, append_to: "Start.default")
72
- end
67
+ def options_for_sequence_build(track_name: :success, end_task: Activity::End.new(semantic: :success), end_id: "End.success", **)
68
+ initial_sequence = start_sequence(track_name: track_name)
73
69
 
74
- def OptionsForSequenceBuilder(normalizers:, track_name: :success, end_task: Activity::End.new(semantic: :success), end_id: "End.success", **options)
75
- # DISCUSS: instead of calling a separate {initial_sequence} method we could make DSL strategies
76
- # use the actual DSL to build up the initial_sequence, somewhere outside? Maybe using {:adds}?
77
- initial_sequence = initial_sequence(track_name: track_name, end_task: end_task, end_id: end_id)
78
-
79
- {
80
- sequence: initial_sequence,
81
- normalizers: normalizers,
82
- track_name: track_name,
83
- end_id: end_id,
84
- step_interface_builder: Activity::TaskBuilder.method(:Binary), # DISCUSS: this is currently the only option we want to pass on in Path() ?
85
- adds: [], # DISCUSS: needed?
86
- **options
70
+ termini = [
71
+ [end_task, id: end_id, magnetic_to: track_name, append_to: "Start.default"]
72
+ ]
73
+
74
+ options = {
75
+ sequence: initial_sequence,
76
+ track_name: track_name,
77
+ end_id: end_id, # needed in Normalizer.normalize_sequence_insert.
87
78
  }
79
+
80
+ return options, termini
88
81
  end
89
82
  end # DSL
90
83
 
91
- compile_strategy!(DSL, normalizers: DSL::Normalizers) # sets :normalizer, normalizer_options, sequence and activity
84
+ compile_strategy!(Path::DSL, normalizers: DSL::Normalizers) # sets :normalizer, normalizer_options, sequence and activity
92
85
  end # Path
93
86
 
94
87
  def self.Path(**options, &block)
@@ -96,14 +89,3 @@ module Trailblazer
96
89
  end
97
90
  end
98
91
  end
99
-
100
- =begin
101
- class Operation
102
- def self.subclassed(track_name:) # FIXME: it should be run in SubOperation context.
103
- # initialize code here
104
- end
105
-
106
- end
107
-
108
- SubOperation = Class.new(Operation, track_name: :green)
109
- =end
@@ -1,114 +1,112 @@
1
1
  module Trailblazer
2
2
  class Activity
3
3
  class Railway < DSL::Linear::Strategy
4
-
5
4
  module DSL
6
5
  Linear = Activity::DSL::Linear
7
6
 
8
7
  module_function
9
8
 
10
- def Normalizer
11
- path_normalizer = Path::DSL.Normalizer()
12
-
13
- Linear::Normalizer.prepend_to(
14
- path_normalizer,
15
- "activity.wirings",
16
- {
17
- "railway.outputs" => Linear::Normalizer.Task(method(:normalize_path_outputs)),
18
- "railway.connections" => Linear::Normalizer.Task(method(:normalize_path_connections)),
19
- },
20
- )
21
- end
22
-
23
- # Change some parts of the step-{Normalizer} pipeline.
24
- # We're bound to using a very primitive Pipeline API, remember, we don't have
25
- # a DSL at this point!
26
- def NormalizerForFail
27
- pipeline = Linear::Normalizer.prepend_to(
28
- Normalizer(),
29
- "activity.wirings",
30
- {
31
- "railway.magnetic_to.fail" => Linear::Normalizer.Task(Fail.method(:merge_magnetic_to)),
32
- }
33
- )
9
+ def Normalizer(prepend_to_default_outputs: [])
10
+ railway_output_steps = {
11
+ "railway.outputs" => Linear::Normalizer.Task(method(:add_failure_output)),
12
+ }
34
13
 
35
- pipeline = Linear::Normalizer.replace(
36
- pipeline,
37
- "path.connections",
38
- ["railway.connections.fail.success_to_failure", Linear::Normalizer.Task(Fail.method(:connect_success_to_failure))],
14
+ # Retrieve the base normalizer from {linear/normalizer.rb} and add processing steps.
15
+ step_normalizer = Path::DSL.Normalizer(
16
+ prepend_to_default_outputs: [railway_output_steps, *prepend_to_default_outputs]
39
17
  )
40
- end
41
18
 
42
- def NormalizerForPass
43
19
  Linear::Normalizer.prepend_to(
44
- Normalizer(),
45
- "activity.normalize_outputs_from_dsl",
46
- # "path.connections",
47
- {"railway.connections.pass.failure_to_success" => Linear::Normalizer.Task(Pass.method(:connect_failure_to_success))}.to_a
20
+ step_normalizer,
21
+ Path::DSL::PREPEND_TO,
22
+ {
23
+ "railway.step.add_failure_connector" => Linear::Normalizer.Task(method(:add_failure_connector)),
24
+ },
48
25
  )
49
26
  end
50
27
 
51
28
  module Fail
52
29
  module_function
53
30
 
31
+ # Change some parts of the step-{Normalizer} pipeline.
32
+ # We're bound to using a very primitive Pipeline API, remember, we don't have
33
+ # a DSL at this point!
34
+ def Normalizer(**options)
35
+ pipeline = Linear::Normalizer.prepend_to( # TODO: replace path.magnetic_to???
36
+ DSL.Normalizer(**options), # grab Railway::DSL::Normalizer.
37
+ Path::DSL::PREPEND_TO,
38
+ {
39
+ "railway.magnetic_to.fail" => Linear::Normalizer.Task(Fail.method(:merge_magnetic_to)),
40
+ }
41
+ )
42
+
43
+ pipeline = Linear::Normalizer.replace(
44
+ pipeline,
45
+ "path.step.add_success_connector",
46
+ ["railway.fail.success_to_failure", Linear::Normalizer.Task(Fail.method(:connect_success_to_failure))],
47
+ )
48
+ end
49
+
54
50
  def merge_magnetic_to(ctx, **)
55
51
  ctx[:magnetic_to] = :failure
56
52
  end
57
53
 
58
- def connect_success_to_failure(ctx, connections: nil, **)
59
- ctx[:connections] = connections || {success: [Linear::Sequence::Search.method(:Forward), :failure]}
54
+ SUCCESS_TO_FAILURE_CONNECTOR = {Linear::Normalizer::OutputTuples.Output(:success) => Linear::Strategy.Track(:failure)}
55
+
56
+ def connect_success_to_failure(ctx, non_symbol_options:, **)
57
+ ctx[:non_symbol_options] = SUCCESS_TO_FAILURE_CONNECTOR.merge(non_symbol_options)
60
58
  end
61
59
  end
62
60
 
63
61
  module Pass
64
62
  module_function
65
63
 
66
- def connect_failure_to_success(ctx, connections:, **)
67
- ctx[:connections] = connections.merge({failure: [Linear::Sequence::Search.method(:Forward), :success]})
64
+ def Normalizer(**options)
65
+ Linear::Normalizer.replace(
66
+ DSL.Normalizer(**options), # grab Railway::DSL::Normalizer.
67
+ "railway.step.add_failure_connector",
68
+ ["railway.pass.failure_to_success", Linear::Normalizer.Task(Pass.method(:connect_failure_to_success))]
69
+ )
68
70
  end
69
- end
70
71
 
71
- # Add {:failure} output to {:outputs}.
72
- # TODO: assert that failure_outputs doesn't override existing {:outputs}
73
- def normalize_path_outputs(ctx, outputs:, **)
74
- outputs = failure_outputs.merge(outputs)
72
+ FAILURE_TO_SUCCESS_CONNECTOR = {Linear::Normalizer::OutputTuples.Output(:failure) => Linear::Strategy.Track(:success)}
75
73
 
76
- ctx[:outputs] = outputs
74
+ def connect_failure_to_success(ctx, **options)
75
+ Railway::DSL.add_failure_connector(ctx, **options, failure_connector: FAILURE_TO_SUCCESS_CONNECTOR)
76
+ end
77
77
  end
78
78
 
79
- def normalize_path_connections(ctx, connections:, **)
80
- ctx[:connections] = failure_connections.merge(connections)
81
- end
79
+ FAILURE_OUTPUT = {failure: Activity::Output(Activity::Left, :failure)}
80
+ FAILURE_CONNECTOR = {Linear::Normalizer::OutputTuples.Output(:failure) => Linear::Strategy.Track(:failure)}
81
+ PASS_CONNECTOR = {Linear::Normalizer::OutputTuples.Output(:failure) => Linear::Strategy.Track(:success)}
82
+ FAIL_CONNECTOR = {Linear::Normalizer::OutputTuples.Output(:success) => Linear::Strategy.Track(:failure)}
82
83
 
83
- def failure_outputs
84
- {failure: Activity::Output(Activity::Left, :failure)}
84
+ # Add {:failure} output to {:outputs}.
85
+ # This is only called for non-Subprocess steps.
86
+ def add_failure_output(ctx, outputs:, **)
87
+ ctx[:outputs] = FAILURE_OUTPUT.merge(outputs)
85
88
  end
86
89
 
87
- def failure_connections
88
- {failure: [Linear::Sequence::Search.method(:Forward), :failure]}
89
- end
90
+ def add_failure_connector(ctx, outputs:, non_symbol_options:, failure_connector: FAILURE_CONNECTOR, **)
91
+ return unless outputs[:failure] # do not add the default failure connection when we don't have
92
+ # a corresponding output.
90
93
 
91
- def initial_sequence(failure_end:, sequence:, **path_options)
92
- _seq = Path::DSL.append_terminus(sequence, failure_end, magnetic_to: :failure, id: "End.failure", normalizers: Normalizers)
94
+ ctx[:non_symbol_options] = failure_connector.merge(non_symbol_options)
93
95
  end
94
96
 
95
97
  Normalizers = Linear::Normalizer::Normalizers.new(
96
98
  step: Railway::DSL.Normalizer(),
97
- fail: Railway::DSL.NormalizerForFail(),
98
- pass: Railway::DSL.NormalizerForPass(),
99
+ fail: Railway::DSL::Fail.Normalizer(),
100
+ pass: Railway::DSL::Pass.Normalizer(),
99
101
  terminus: Linear::Normalizer::Terminus.Normalizer(),
100
102
  )
101
103
 
102
- def self.OptionsForSequenceBuilder(failure_end: Activity::End.new(semantic: :failure), **options)
103
- options = Path::DSL.OptionsForSequenceBuilder(**options).
104
- merge(failure_end: failure_end)
104
+ def options_for_sequence_build(failure_end: Activity::End.new(semantic: :failure), **options)
105
+ failure_terminus_options = [failure_end, magnetic_to: :failure, id: "End.failure", normalizers: Normalizers]
105
106
 
106
- initial_sequence = Railway::DSL.initial_sequence(failure_end: failure_end, **options)
107
+ path_options, path_termini = Path::DSL.options_for_sequence_build(**options)
107
108
 
108
- {
109
- **options,
110
- sequence: initial_sequence,
111
- }
109
+ return path_options, path_termini + [failure_terminus_options]
112
110
  end
113
111
  end # DSL
114
112
 
@@ -1,4 +1,4 @@
1
- lib = File.expand_path('../lib', __FILE__)
1
+ lib = File.expand_path("../lib", __FILE__)
2
2
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
3
3
  require "trailblazer/activity/dsl/linear/version"
4
4
 
@@ -8,9 +8,9 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ["Nick Sutterer"]
9
9
  spec.email = ["apotonick@gmail.com"]
10
10
 
11
- spec.summary = %q(Simple DSL to define Trailblazer activities.)
12
- spec.description = %q(Simple DSL to define Trailblazer activities with arbitrary wirings.)
13
- spec.homepage = "http://trailblazer.to"
11
+ spec.summary = %(Simple DSL to define Trailblazer activities.)
12
+ spec.description = %(Simple DSL to define Trailblazer activities with arbitrary wirings.)
13
+ spec.homepage = "https://trailblazer.to/2.1/docs/activity"
14
14
  spec.licenses = ["LGPL-3.0"]
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0").reject do |f|
@@ -18,13 +18,13 @@ Gem::Specification.new do |spec|
18
18
  end
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "trailblazer-activity", ">= 0.14.0", "< 0.15.0"
21
+ spec.add_dependency "trailblazer-activity", ">= 0.16.0", "< 0.17.0"
22
22
  spec.add_dependency "trailblazer-declarative", ">= 0.0.1", "< 0.1.0"
23
23
 
24
24
  spec.add_development_dependency "bundler"
25
- spec.add_development_dependency "minitest", "~> 5.0"
25
+ spec.add_development_dependency "minitest", ">= 5.15.0", "< 5.16.0"
26
26
  spec.add_development_dependency "rake"
27
- spec.add_development_dependency "trailblazer-developer", ">= 0.0.26"
27
+ spec.add_development_dependency "trailblazer-core-utils", "0.0.2"
28
28
 
29
- spec.required_ruby_version = '>= 2.1.0'
29
+ spec.required_ruby_version = ">= 2.5.0"
30
30
  end