trailblazer-future 2.1.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (161) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +12 -0
  3. data/.travis.yml +6 -0
  4. data/CHANGES.md +4 -0
  5. data/LICENSE.txt +9 -0
  6. data/README.md +48 -0
  7. data/Rakefile +10 -0
  8. data/bin/console +14 -0
  9. data/bin/setup +8 -0
  10. data/gems.rb +3 -0
  11. data/lib/trailblazer/future.rb +9 -0
  12. data/lib/trailblazer/future/version.rb +5 -0
  13. data/lib/trailblazer/v2_1/activity.rb +123 -0
  14. data/lib/trailblazer/v2_1/activity/config.rb +37 -0
  15. data/lib/trailblazer/v2_1/activity/dsl/add_task.rb +22 -0
  16. data/lib/trailblazer/v2_1/activity/dsl/helper.rb +68 -0
  17. data/lib/trailblazer/v2_1/activity/dsl/magnetic.rb +36 -0
  18. data/lib/trailblazer/v2_1/activity/dsl/magnetic/builder.rb +101 -0
  19. data/lib/trailblazer/v2_1/activity/dsl/magnetic/builder/default_normalizer.rb +26 -0
  20. data/lib/trailblazer/v2_1/activity/dsl/magnetic/builder/fast_track.rb +118 -0
  21. data/lib/trailblazer/v2_1/activity/dsl/magnetic/builder/normalizer.rb +113 -0
  22. data/lib/trailblazer/v2_1/activity/dsl/magnetic/builder/path.rb +105 -0
  23. data/lib/trailblazer/v2_1/activity/dsl/magnetic/builder/railway.rb +97 -0
  24. data/lib/trailblazer/v2_1/activity/dsl/magnetic/builder/state.rb +58 -0
  25. data/lib/trailblazer/v2_1/activity/dsl/magnetic/finalizer.rb +51 -0
  26. data/lib/trailblazer/v2_1/activity/dsl/magnetic/generate.rb +62 -0
  27. data/lib/trailblazer/v2_1/activity/dsl/magnetic/merge.rb +16 -0
  28. data/lib/trailblazer/v2_1/activity/dsl/magnetic/process_options.rb +76 -0
  29. data/lib/trailblazer/v2_1/activity/dsl/magnetic/structure/alterations.rb +44 -0
  30. data/lib/trailblazer/v2_1/activity/dsl/magnetic/structure/plus_poles.rb +85 -0
  31. data/lib/trailblazer/v2_1/activity/dsl/magnetic/structure/polarization.rb +23 -0
  32. data/lib/trailblazer/v2_1/activity/dsl/record.rb +11 -0
  33. data/lib/trailblazer/v2_1/activity/dsl/schema/dependencies.rb +46 -0
  34. data/lib/trailblazer/v2_1/activity/dsl/schema/sequence.rb +46 -0
  35. data/lib/trailblazer/v2_1/activity/dsl/strategy/build_state.rb +32 -0
  36. data/lib/trailblazer/v2_1/activity/dsl/strategy/fast_track.rb +24 -0
  37. data/lib/trailblazer/v2_1/activity/dsl/strategy/path.rb +26 -0
  38. data/lib/trailblazer/v2_1/activity/dsl/strategy/plan.rb +36 -0
  39. data/lib/trailblazer/v2_1/activity/dsl/strategy/railway.rb +23 -0
  40. data/lib/trailblazer/v2_1/activity/interface.rb +16 -0
  41. data/lib/trailblazer/v2_1/activity/introspect.rb +167 -0
  42. data/lib/trailblazer/v2_1/activity/present.rb +95 -0
  43. data/lib/trailblazer/v2_1/activity/structures.rb +57 -0
  44. data/lib/trailblazer/v2_1/activity/task_builder.rb +41 -0
  45. data/lib/trailblazer/v2_1/activity/task_wrap.rb +40 -0
  46. data/lib/trailblazer/v2_1/activity/task_wrap/call_task.rb +19 -0
  47. data/lib/trailblazer/v2_1/activity/task_wrap/merge.rb +23 -0
  48. data/lib/trailblazer/v2_1/activity/task_wrap/runner.rb +62 -0
  49. data/lib/trailblazer/v2_1/activity/task_wrap/trace.rb +44 -0
  50. data/lib/trailblazer/v2_1/activity/task_wrap/variable_mapping.rb +162 -0
  51. data/lib/trailblazer/v2_1/activity/testing.rb +32 -0
  52. data/lib/trailblazer/v2_1/activity/trace.rb +97 -0
  53. data/lib/trailblazer/v2_1/circuit.rb +71 -0
  54. data/lib/trailblazer/v2_1/container_chain.rb +45 -0
  55. data/lib/trailblazer/v2_1/context.rb +79 -0
  56. data/lib/trailblazer/v2_1/deprecation/call.rb +46 -0
  57. data/lib/trailblazer/v2_1/deprecation/context.rb +43 -0
  58. data/lib/trailblazer/v2_1/dsl.rb +47 -0
  59. data/lib/trailblazer/v2_1/macro.rb +11 -0
  60. data/lib/trailblazer/v2_1/macro/contract.rb +5 -0
  61. data/lib/trailblazer/v2_1/operation.rb +91 -0
  62. data/lib/trailblazer/v2_1/operation/auto_inject.rb +47 -0
  63. data/lib/trailblazer/v2_1/operation/callable.rb +42 -0
  64. data/lib/trailblazer/v2_1/operation/class_dependencies.rb +25 -0
  65. data/lib/trailblazer/v2_1/operation/contract.rb +61 -0
  66. data/lib/trailblazer/v2_1/operation/deprecated_macro.rb +19 -0
  67. data/lib/trailblazer/v2_1/operation/deprecations.rb +21 -0
  68. data/lib/trailblazer/v2_1/operation/guard.rb +18 -0
  69. data/lib/trailblazer/v2_1/operation/heritage.rb +30 -0
  70. data/lib/trailblazer/v2_1/operation/inject.rb +36 -0
  71. data/lib/trailblazer/v2_1/operation/inspect.rb +79 -0
  72. data/lib/trailblazer/v2_1/operation/model.rb +50 -0
  73. data/lib/trailblazer/v2_1/operation/module.rb +29 -0
  74. data/lib/trailblazer/v2_1/operation/nested.rb +98 -0
  75. data/lib/trailblazer/v2_1/operation/persist.rb +14 -0
  76. data/lib/trailblazer/v2_1/operation/policy.rb +44 -0
  77. data/lib/trailblazer/v2_1/operation/public_call.rb +55 -0
  78. data/lib/trailblazer/v2_1/operation/pundit.rb +38 -0
  79. data/lib/trailblazer/v2_1/operation/railway.rb +32 -0
  80. data/lib/trailblazer/v2_1/operation/railway/fast_track.rb +13 -0
  81. data/lib/trailblazer/v2_1/operation/railway/macaroni.rb +23 -0
  82. data/lib/trailblazer/v2_1/operation/railway/normalizer.rb +58 -0
  83. data/lib/trailblazer/v2_1/operation/railway/task_builder.rb +37 -0
  84. data/lib/trailblazer/v2_1/operation/rescue.rb +42 -0
  85. data/lib/trailblazer/v2_1/operation/responder.rb +18 -0
  86. data/lib/trailblazer/v2_1/operation/result.rb +30 -0
  87. data/lib/trailblazer/v2_1/operation/test.rb +17 -0
  88. data/lib/trailblazer/v2_1/operation/trace.rb +46 -0
  89. data/lib/trailblazer/v2_1/operation/validate.rb +76 -0
  90. data/lib/trailblazer/v2_1/operation/wrap.rb +83 -0
  91. data/lib/trailblazer/v2_1/option.rb +78 -0
  92. data/lib/trailblazer/v2_1/rails.rb +12 -0
  93. data/lib/trailblazer/v2_1/rails/cell.rb +22 -0
  94. data/lib/trailblazer/v2_1/rails/controller.rb +66 -0
  95. data/lib/trailblazer/v2_1/rails/form.rb +21 -0
  96. data/lib/trailblazer/v2_1/rails/railtie.rb +31 -0
  97. data/lib/trailblazer/v2_1/rails/railtie/extend_application_controller.rb +28 -0
  98. data/lib/trailblazer/v2_1/rails/railtie/loader.rb +58 -0
  99. data/lib/trailblazer/v2_1/rails/test/integration.rb +6 -0
  100. data/lib/trailblazer/v2_1/versions.txt +7 -0
  101. data/test/rails5.0/.gitignore +17 -0
  102. data/test/rails5.0/Gemfile +21 -0
  103. data/test/rails5.0/Rakefile +3 -0
  104. data/test/rails5.0/app/concepts/artist/cell/dashboard.rb +7 -0
  105. data/test/rails5.0/app/concepts/artist/cell/show.rb +4 -0
  106. data/test/rails5.0/app/concepts/artist/view/dashboard.erb +4 -0
  107. data/test/rails5.0/app/concepts/artist/view/show.erb +1 -0
  108. data/test/rails5.0/app/concepts/params/operation/with_args.rb +5 -0
  109. data/test/rails5.0/app/concepts/song/contract/form.rb +6 -0
  110. data/test/rails5.0/app/concepts/song/operation/create.rb +15 -0
  111. data/test/rails5.0/app/concepts/song/operation/show.rb +3 -0
  112. data/test/rails5.0/app/concepts/song/operation/update.rb +15 -0
  113. data/test/rails5.0/app/controllers/application_controller.rb +46 -0
  114. data/test/rails5.0/app/controllers/args_controller.rb +5 -0
  115. data/test/rails5.0/app/controllers/artists_controller.rb +24 -0
  116. data/test/rails5.0/app/controllers/params_controller.rb +11 -0
  117. data/test/rails5.0/app/controllers/songs_controller.rb +35 -0
  118. data/test/rails5.0/app/models/artist.rb +2 -0
  119. data/test/rails5.0/app/models/song.rb +2 -0
  120. data/test/rails5.0/app/views/args/with_args.html.erb +1 -0
  121. data/test/rails5.0/app/views/layouts/application.html.erb +2 -0
  122. data/test/rails5.0/app/views/songs/edit.html.erb +4 -0
  123. data/test/rails5.0/app/views/songs/new.html.erb +5 -0
  124. data/test/rails5.0/app/views/songs/new_with_result.html.erb +3 -0
  125. data/test/rails5.0/app/views/songs/show.html.erb +3 -0
  126. data/test/rails5.0/bin/bundle +3 -0
  127. data/test/rails5.0/bin/rails +4 -0
  128. data/test/rails5.0/bin/rake +4 -0
  129. data/test/rails5.0/bin/setup +29 -0
  130. data/test/rails5.0/config.ru +4 -0
  131. data/test/rails5.0/config/application.rb +25 -0
  132. data/test/rails5.0/config/boot.rb +3 -0
  133. data/test/rails5.0/config/database.yml +21 -0
  134. data/test/rails5.0/config/environment.rb +5 -0
  135. data/test/rails5.0/config/environments/development.rb +41 -0
  136. data/test/rails5.0/config/environments/test.rb +42 -0
  137. data/test/rails5.0/config/initializers/assets.rb +11 -0
  138. data/test/rails5.0/config/initializers/backtrace_silencers.rb +7 -0
  139. data/test/rails5.0/config/initializers/cookies_serializer.rb +3 -0
  140. data/test/rails5.0/config/initializers/filter_parameter_logging.rb +4 -0
  141. data/test/rails5.0/config/initializers/inflections.rb +16 -0
  142. data/test/rails5.0/config/initializers/mime_types.rb +4 -0
  143. data/test/rails5.0/config/initializers/session_store.rb +3 -0
  144. data/test/rails5.0/config/initializers/wrap_parameters.rb +14 -0
  145. data/test/rails5.0/config/locales/en.yml +23 -0
  146. data/test/rails5.0/config/routes.rb +15 -0
  147. data/test/rails5.0/config/secrets.yml +17 -0
  148. data/test/rails5.0/db/migrate/20161122145124_create_songs.rb +8 -0
  149. data/test/rails5.0/db/schema.rb +19 -0
  150. data/test/rails5.0/log/.keep +0 -0
  151. data/test/rails5.0/test/concepts/song/operation/create_test.rb +11 -0
  152. data/test/rails5.0/test/concepts/song/operation/update_test.rb +34 -0
  153. data/test/rails5.0/test/integration/.keep +0 -0
  154. data/test/rails5.0/test/integration/args_controller_test.rb +8 -0
  155. data/test/rails5.0/test/integration/artists_controller_test.rb +28 -0
  156. data/test/rails5.0/test/integration/params_controller_test.rb +8 -0
  157. data/test/rails5.0/test/integration/songs_controller_test.rb +40 -0
  158. data/test/rails5.0/test/test_helper.rb +7 -0
  159. data/test/test_helper.rb +5 -0
  160. data/trailblazer-future.gemspec +25 -0
  161. metadata +246 -0
@@ -0,0 +1,101 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+
4
+ # TODO: move?
5
+ module Options
6
+ # Produce two hashes, one "local" options with DSL-specific options such as `:fast_track`,
7
+ # one with generic DSL options, for example tuples like `Right=>Output(:failure)`.
8
+ def self.normalize(options, local_keys)
9
+ local, foreign = {}, {}
10
+ options.each { |k,v| local_keys.include?(k) ? local[k] = v : foreign[k] = v }
11
+
12
+ return foreign, local
13
+ end
14
+ end
15
+
16
+ # Called from Path/Railway/FastTrack, creates the specific {Builder} instance.
17
+ def self.Builder(implementation, normalizer, builder_options={})
18
+ builder = implementation.new(normalizer, builder_options.freeze).freeze # e.g. Path.new(...)
19
+
20
+ return builder, implementation.InitialAdds(builder_options)
21
+ end
22
+
23
+ class Builder
24
+ def initialize(normalizer, builder_options)
25
+ @normalizer, @builder_options = normalizer, builder_options
26
+ end
27
+
28
+ def self.merge(activity_adds, merged_adds)
29
+ merged_adds = merged_adds[2..-1] || []
30
+
31
+ activity_adds + merged_adds
32
+ end
33
+
34
+ # DSL method to create a Path within an activity which is embedded.
35
+ #
36
+ # Output(:success) => Path() {}
37
+ def Path(*args)
38
+ Activity::DSL.Path(@normalizer, *args)
39
+ end
40
+
41
+ # Public top-level entry point.
42
+ def insert(strategy, polarizer, task, options, &block)
43
+ normalizer = options[:normalizer] || @normalizer # DISCUSS: do this at a deeper point?
44
+
45
+ task, local_options, connection_options, sequence_options, extension_options = normalizer.(task, options)
46
+
47
+ polarizations = strategy.send(polarizer, @builder_options) # Railway.StepPolarizations( @builder_options )
48
+
49
+ insert_element( polarizations, task, local_options, connection_options, sequence_options, extension_options, &block )
50
+ end
51
+
52
+ private
53
+
54
+ # Internal top-level entry point to add task(s) and connections.
55
+ # High level interface for DSL calls like ::task or ::step.
56
+ def insert_element(polarizations, task, local_options, connection_options, sequence_options, extension_options, &block)
57
+ adds, *returned_options = Builder.adds_for(polarizations, task, local_options, connection_options, sequence_options, extension_options, &block)
58
+ end
59
+
60
+ # @return Adds
61
+ def self.adds_for(polarizations, task, local_options, connection_options, sequence_options, extension_options, &block)
62
+ # go through all wiring options such as Output()=>:color.
63
+ polarizations_from_user_options, additional_adds = process_dsl_options(connection_options, local_options, &block)
64
+
65
+ polarizations = polarizations + polarizations_from_user_options
66
+
67
+ result = adds(task, polarizations, local_options, sequence_options, local_options)
68
+
69
+ return result + (local_options[:adds] || []) + additional_adds, task, local_options, connection_options, sequence_options, extension_options
70
+ end
71
+
72
+ def self.process_dsl_options(options, id:nil, plus_poles:, **, &block)
73
+ DSL::ProcessOptions.(id, options, plus_poles, &block)
74
+ end
75
+
76
+ # Low-level interface for DSL calls (e.g. Start, where "you know what you're doing")
77
+ # @private
78
+ def self.adds(task, polarizations, options, sequence_options, magnetic_to:nil, id:nil, plus_poles:, **) # DISCUSS: no :id ?
79
+ magnetic_to, plus_poles = PlusPoles.apply_polarizations(
80
+ polarizations,
81
+ magnetic_to,
82
+ plus_poles,
83
+ options
84
+ )
85
+
86
+ Add( id, task, magnetic_to, plus_poles,
87
+ options, #{ fast_track: true },
88
+ sequence_options #{ group: :main }
89
+ )
90
+ end
91
+
92
+ def self.Add(id, task, magnetic_to, plus_poles, options, sequence_options)
93
+ [
94
+ [ :add, [id, [ magnetic_to, task, plus_poles ], sequence_options] ],
95
+ ]
96
+ end
97
+ end # Builder
98
+ end
99
+ end
100
+
101
+
@@ -0,0 +1,26 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ # This normalizer only processes basic input and is meant for bootstrapping.
4
+ #
5
+ # task Callable, id: "success", before: "another"
6
+ class DefaultNormalizer
7
+ # Declarative::Variables
8
+ def self.build(plus_poles:, **options)
9
+ return new(plus_poles: plus_poles), options
10
+ end
11
+
12
+ def initialize(**default_options)
13
+ @default_options = default_options
14
+ end
15
+
16
+ # Processes the user arguments from the DSL
17
+ def call(task, options)
18
+ local_options = @default_options.merge(options) # here, we merge default :plus_poles.
19
+
20
+ local_options, sequence_options = Options.normalize( local_options, Activity::Schema::Dependencies.sequence_keywords )
21
+
22
+ return task, local_options, {}, sequence_options, {}
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,118 @@
1
+ # TODO: move me to Operation.
2
+ module Trailblazer::V2_1
3
+ module Activity::Magnetic
4
+ class Builder
5
+
6
+ class FastTrack < Builder
7
+ def self.for(normalizer, builder_options={}) # Build the Builder.
8
+ Activity::Magnetic::Builder(
9
+ FastTrack,
10
+ normalizer,
11
+ { track_color: :success, end_semantic: :success, failure_color: :failure }.merge( builder_options )
12
+ )
13
+ end
14
+
15
+ def self.StepPolarizations(**options)
16
+ [
17
+ *Railway.StepPolarizations(options),
18
+ StepPolarization.new(options)
19
+ ]
20
+ end
21
+
22
+ def self.FailPolarizations(**options)
23
+ [
24
+ *Railway.FailPolarizations(options),
25
+ FailPolarization.new(options)
26
+ ]
27
+ end
28
+
29
+ def self.PassPolarizations(**options)
30
+ [
31
+ *Railway.PassPolarizations(options),
32
+ PassPolarization.new(options)
33
+ ]
34
+ end
35
+
36
+ # pass_fast: true simply means: color my :success Output with :pass_fast color
37
+ class StepPolarization < Railway::StepPolarization
38
+ def call(magnetic_to, plus_poles, options)
39
+ plus_poles = plus_poles.reconnect( :success => :pass_fast ) if options[:pass_fast]
40
+ plus_poles = plus_poles.reconnect( :failure => :fail_fast ) if options[:fail_fast]
41
+
42
+ # add fast track outputs if :fast_track
43
+ plus_poles = plus_poles.reverse_merge(
44
+ Activity.Output(Activity::FastTrack::FailFast, :fail_fast) => :fail_fast,
45
+ Activity.Output(Activity::FastTrack::PassFast, :pass_fast) => :pass_fast
46
+ ) if options[:fast_track]
47
+
48
+ [
49
+ magnetic_to,
50
+ plus_poles
51
+ ]
52
+ end
53
+ end
54
+
55
+ class FailPolarization < Railway::StepPolarization
56
+ def call(magnetic_to, plus_poles, options)
57
+ plus_poles = plus_poles.reconnect( :failure => :fail_fast, :success => :fail_fast ) if options[:fail_fast]
58
+ plus_poles = plus_poles.reverse_merge( Activity.Output(Activity::FastTrack::FailFast, :fail_fast) => :fail_fast, Activity.Output(Activity::FastTrack::PassFast, :pass_fast) => :pass_fast ) if options[:fast_track]
59
+
60
+ [
61
+ magnetic_to,
62
+ plus_poles
63
+ ]
64
+ end
65
+ end
66
+
67
+ class PassPolarization < Railway::StepPolarization
68
+ def call(magnetic_to, plus_poles, options)
69
+ plus_poles = plus_poles.reconnect( :success => :pass_fast, :failure => :pass_fast ) if options[:pass_fast]
70
+ plus_poles = plus_poles.reverse_merge( Activity.Output(Activity::FastTrack::FailFast, :fail_fast) => :fail_fast, Activity.Output(Activity::FastTrack::PassFast, :pass_fast) => :pass_fast ) if options[:fast_track]
71
+
72
+ [
73
+ magnetic_to,
74
+ plus_poles
75
+ ]
76
+ end
77
+ end
78
+
79
+ def self.default_plus_poles(*args)
80
+ Railway.default_plus_poles(*args)
81
+ end
82
+
83
+ # Adds the End.fail_fast and End.pass_fast end to the Railway sequence.
84
+ def self.InitialAdds(pass_fast_end: Activity.End(:pass_fast), fail_fast_end: Activity.End(:fail_fast), **builder_options)
85
+ path_adds = Railway.InitialAdds(**builder_options)
86
+
87
+ ends =
88
+ adds(
89
+ pass_fast_end,
90
+
91
+ Path::EndEventPolarizations(builder_options),
92
+
93
+ {},
94
+ { group: :end },
95
+
96
+ id: "End.pass_fast",
97
+ magnetic_to: [:pass_fast],
98
+ plus_poles: {},
99
+ )+
100
+ adds(
101
+ fail_fast_end,
102
+
103
+ Path::EndEventPolarizations(builder_options),
104
+
105
+ {},
106
+ { group: :end },
107
+
108
+ magnetic_to: [:fail_fast],
109
+ id: "End.fail_fast",
110
+ plus_poles: {},
111
+ )
112
+
113
+ path_adds + ends
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,113 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ # One {Normalizer} instance is called for every DSL call (step/pass/fail etc.) and normalizes/defaults
4
+ # the user options, such as setting `:id`, connecting the task's outputs or wrapping the user's
5
+ # task via {TaskBuilder::Binary} in order to translate true/false to `Right` or `Left`.
6
+ #
7
+ # The Normalizer sits in the `@builder`, which receives all DSL calls from the Operation subclass.
8
+ class Normalizer
9
+ def self.build(task_builder: Activity::TaskBuilder.method(:Binary), default_outputs: Builder::Path.default_outputs, pipeline: Pipeline, extension:[], **options)
10
+ return new(
11
+ default_outputs: default_outputs,
12
+ extension: extension,
13
+ task_builder: task_builder,
14
+ pipeline: pipeline,
15
+ ), options
16
+ end
17
+
18
+ def initialize(task_builder:, default_outputs:, pipeline:, **options)
19
+ @task_builder = task_builder
20
+ @default_outputs = default_outputs
21
+ @pipeline = pipeline # TODO: test me.
22
+ freeze
23
+ end
24
+
25
+ def call(task, options)
26
+ ctx = {
27
+ task: task,
28
+ options: options,
29
+ task_builder: @task_builder,
30
+ default_outputs: @default_outputs,
31
+ }
32
+
33
+ signal, (ctx, ) = @pipeline.( [ctx], {} )
34
+
35
+ return ctx[:options][:task], ctx[:local_options], ctx[:connection_options], ctx[:sequence_options], ctx[:extension_options]
36
+ end
37
+
38
+ # needs the basic Normalizer
39
+
40
+ # :default_plus_poles is an injectable option.
41
+ module Pipeline
42
+ extend Trailblazer::V2_1::Activity::Path( normalizer_class: DefaultNormalizer, plus_poles: PlusPoles.new.merge( Builder::Path.default_outputs.values ) ) # FIXME: the DefaultNormalizer actually doesn't need Left.
43
+
44
+ def self.split_options( ctx, task:, options:, ** )
45
+ keywords = extract_dsl_keywords(options)
46
+ extensions = extract_extensions(options)
47
+
48
+ # sort through the "original" user DSL options.
49
+ options, extension_options = Options.normalize( options, extensions ) # DISCUSS:
50
+ options, local_options = Options.normalize( options, keywords ) # DISCUSS:
51
+ local_options, sequence_options = Options.normalize( local_options, Activity::Schema::Dependencies.sequence_keywords )
52
+
53
+ ctx[:local_options],
54
+ ctx[:connection_options],
55
+ ctx[:sequence_options],
56
+ ctx[:extension_options] = local_options, options, sequence_options, extension_options
57
+ end
58
+
59
+ # Filter out connections, e.g. `Output(:fail_fast) => :success` and return only the keywords like `:id` or `:replace`.
60
+ def self.extract_dsl_keywords(options, connection_classes = [Activity::Output, Activity::DSL::OutputSemantic])
61
+ options.keys - options.keys.find_all { |k| connection_classes.include?( k.class ) }
62
+ end
63
+
64
+ def self.extract_extensions(options, extensions_classes = [Activity::DSL::Extension])
65
+ options.keys.find_all { |k| extensions_classes.include?( k.class ) }
66
+ end
67
+
68
+ # FIXME; why don't we use the extensions passed into the initializer?
69
+ def self.initialize_extension_option( ctx, options:, ** )
70
+ ctx[:options] = options.merge( Activity::DSL::Extension.new( Activity::DSL.method(:record) ) => true )
71
+ end
72
+
73
+ # Normalizes ctx[:options] (the user-options via the DSL) into the internal Hash format.
74
+ def self.normalize_for_macro( ctx, task:, options:, task_builder:, ** )
75
+ ctx[:options] =
76
+ if task.is_a?(::Hash) # macro.
77
+ task.merge(options) # Note that the user options are merged over the macro options.
78
+ else # user step
79
+ { id: task }
80
+ .merge(options) # default :id
81
+ .merge( task: task_builder.(task) )
82
+ end
83
+ end
84
+
85
+ # :outputs passed: I know what I want to have connected.
86
+ # no :outputs: use default_outputs
87
+ # ALWAYS connect all outputs to their semantic-color.
88
+
89
+ # Create the `plus_poles: <PlusPoles>` tuple where the PlusPoles instance will act as the interface
90
+ # to rewire or add connections for the DSL.
91
+ def self.initialize_plus_poles( ctx, local_options:, default_outputs:, ** )
92
+ outputs = local_options[:outputs] || default_outputs
93
+
94
+ ctx[:local_options] =
95
+ {
96
+ plus_poles: PlusPoles.initial(outputs),
97
+ }
98
+ .merge(local_options)
99
+ end
100
+
101
+ task Activity::TaskBuilder::Binary( method(:initialize_extension_option) ), id: "initialize_extension_option"
102
+ task Activity::TaskBuilder::Binary( method(:normalize_for_macro) ), id: "normalize_for_macro"
103
+
104
+ task Activity::TaskBuilder::Binary( Activity::TaskWrap::VariableMapping.method(:normalizer_step_for_input_output) )
105
+
106
+ task Activity::TaskBuilder::Binary( method(:split_options) ), id: "split_options"
107
+ task Activity::TaskBuilder::Binary( method(:initialize_plus_poles) ), id: "initialize_plus_poles"
108
+ # task ->((ctx, _), **) { pp ctx; [Activity::Right, [ctx, _]] }
109
+ end
110
+ end # Normalizer
111
+
112
+ end
113
+ end
@@ -0,0 +1,105 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ class Builder
4
+
5
+ class Path < Builder
6
+ # strategy_options:
7
+ # :track_color
8
+ # :end_semantic
9
+ def self.for(normalizer, builder_options={}) # Build the Builder.
10
+ Activity::Magnetic::Builder(
11
+ Path,
12
+ normalizer,
13
+ { track_color: :success, end_semantic: :success }.merge( builder_options )
14
+ )
15
+ end
16
+
17
+ # In most cases, a task has a binary signal, which is why we decided to make that
18
+ # the default output set.
19
+ def self.default_outputs
20
+ {
21
+ :success => Activity.Output(Activity::Right, :success),
22
+ :failure => Activity.Output(Activity::Left, :failure)
23
+ }
24
+ end
25
+
26
+ # @return [Adds] list of Adds instances that can be chained or added to an existing sequence.
27
+ def self.InitialAdds(**options)
28
+ StartAdds(**options) + EndAdds(**options)
29
+ end
30
+
31
+ # TODO: make this nicer.
32
+ def self.StartAdds(track_color:, end_semantic:, start_outputs: {success: self.default_outputs[:success]}, **)
33
+ builder_options={ track_color: track_color, end_semantic: end_semantic }
34
+
35
+ adds(
36
+ Activity::Start.new(semantic: :default),
37
+
38
+ TaskPolarizations(builder_options),
39
+
40
+ {}, { group: :start },
41
+
42
+ id: "Start.default",
43
+ magnetic_to: [],
44
+ plus_poles: PlusPoles.initial(start_outputs), # FIXME: this is actually redundant with Normalizer
45
+ )
46
+ end
47
+
48
+ # TODO: make this nicer.
49
+ def self.EndAdds(track_color:, end_semantic:, track_end: Activity.End(end_semantic), end_id: nil, **)
50
+ # an end can either be a reference to another task,
51
+ # or a "real" end event.
52
+ if end_id
53
+ [[:magnetic_to,
54
+ [ end_id, [track_color] ] ]
55
+ ]
56
+ else
57
+ builder_options={ track_color: track_color, end_semantic: end_semantic }
58
+
59
+ adds(
60
+ track_end,
61
+
62
+ EndEventPolarizations(builder_options), # only sets :magnetic_to.
63
+
64
+ {}, { group: :end },
65
+
66
+ id: "End.#{track_color}",
67
+ plus_poles: {},
68
+ magnetic_to: nil,
69
+ )
70
+ end
71
+ end
72
+
73
+ def self.TaskPolarizations(track_color:, **)
74
+ [TaskPolarization.new( track_color: track_color )]
75
+ end
76
+
77
+ def self.EndEventPolarizations(track_color:, **)
78
+ [EndEventPolarization.new( track_color: track_color )]
79
+ end
80
+
81
+ class TaskPolarization
82
+ def initialize(track_color:)
83
+ @track_color = track_color
84
+ end
85
+
86
+ def call(magnetic_to, plus_poles, options)
87
+ [
88
+ magnetic_to || [@track_color],
89
+ plus_poles.reconnect( :success => @track_color )
90
+ ]
91
+ end
92
+ end # TaskPolarization
93
+
94
+ class EndEventPolarization < TaskPolarization
95
+ def call(magnetic_to, plus_poles, options)
96
+ [
97
+ magnetic_to || [@track_color],
98
+ {}
99
+ ]
100
+ end
101
+ end # EndEventPolarization
102
+ end # Path
103
+ end # Builder
104
+ end
105
+ end