trailblazer-future 2.1.0.rc1

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 (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,97 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ class Builder
4
+ class Railway < Builder
5
+ def self.for(normalizer, builder_options={}) # Build the Builder.
6
+ Activity::Magnetic::Builder(
7
+ Railway,
8
+ normalizer,
9
+ { track_color: :success, end_semantic: :success, failure_color: :failure }.merge( builder_options )
10
+ )
11
+ end
12
+
13
+ # Adds the End.failure end to the Path sequence.
14
+ # @return [Adds] list of Adds instances that can be chained or added to an existing sequence.
15
+ def self.InitialAdds(failure_color:raise, failure_end: Activity.End(failure_color), **builder_options)
16
+ path_adds = Path.InitialAdds(**builder_options)
17
+
18
+ end_adds = adds(
19
+ failure_end,
20
+
21
+ Path::EndEventPolarizations(builder_options),
22
+
23
+ {},
24
+ { group: :end },
25
+
26
+ magnetic_to: [failure_color],
27
+ id: "End.#{failure_color}",
28
+ plus_poles: {},
29
+ )
30
+
31
+ path_adds + end_adds
32
+ end
33
+
34
+ # ONLY JOB: magnetic_to and Outputs ("Polarization") via PlusPoles.merge
35
+ def self.StepPolarizations(**options)
36
+ [
37
+ *Path.TaskPolarizations(options),
38
+ StepPolarization.new(options)
39
+ ]
40
+ end
41
+
42
+ def self.PassPolarizations(options)
43
+ [
44
+ Railway::PassPolarization.new( options )
45
+ ]
46
+ end
47
+
48
+ def self.FailPolarizations(options)
49
+ [
50
+ Railway::FailPolarization.new( options )
51
+ ]
52
+ end
53
+
54
+ class StepPolarization
55
+ def initialize(track_color: :success, failure_color: :failure, **o)
56
+ @track_color, @failure_color = track_color, failure_color
57
+ end
58
+
59
+ # Returns the polarization for a DSL call. Takes care of user options such as :magnetic_to.
60
+ def call(magnetic_to, plus_poles, options)
61
+ [
62
+ magnetic_to || default_magnetic_to,
63
+ plus_poles_for(plus_poles, options),
64
+ ]
65
+ end
66
+
67
+ private
68
+
69
+ def plus_poles_for(plus_poles, options)
70
+ plus_poles.reconnect( :failure => @failure_color )
71
+ end
72
+
73
+ def default_magnetic_to
74
+ [@track_color]
75
+ end
76
+ end
77
+
78
+ class PassPolarization < StepPolarization
79
+ def plus_poles_for(plus_poles, options)
80
+ plus_poles.reconnect( :failure => @track_color, :success => @track_color )
81
+ end
82
+ end
83
+
84
+ class FailPolarization < StepPolarization
85
+ def default_magnetic_to
86
+ [@failure_color]
87
+ end
88
+
89
+ def plus_poles_for(plus_poles, options)
90
+ plus_poles.reconnect( :failure => @failure_color, :success => @failure_color )
91
+ end
92
+ end
93
+
94
+ end # Railway
95
+ end # Builder
96
+ end
97
+ end
@@ -0,0 +1,58 @@
1
+ module Trailblazer::V2_1
2
+ class Activity::Magnetic::Builder
3
+ # Maintain Builder instance plus Adds/Process/Outputs as immutable objects.
4
+ module State
5
+ def self.build(builder_class, normalizer, builder_options)
6
+ builder, adds = builder_class.for(normalizer, builder_options) # e.g. Path.for(...) which creates a Builder::Path instance.
7
+
8
+ recompile(builder.freeze, adds.freeze)
9
+ end
10
+
11
+ def self.add(builder, adds, strategy, polarizer, *args, &block)
12
+ new_adds, *returned_options = builder.insert(strategy, polarizer, *args, &block) # TODO: move that out of here.
13
+
14
+ adds = adds + new_adds
15
+
16
+ recompile(builder, adds.freeze, returned_options)
17
+ end
18
+
19
+ private
20
+
21
+ # @return {builder, Adds, Process, outputs}, returned_options
22
+ def self.recompile(builder, adds, *args)
23
+ circuit, outputs = recompile_circuit(adds)
24
+
25
+ return builder, adds, circuit.freeze, outputs.freeze, *args
26
+ end
27
+
28
+ def self.recompile_circuit(adds)
29
+ circuit, outputs = Recompile.( adds )
30
+ end
31
+
32
+ module Recompile
33
+ # Recompile the circuit and outputs from the {ADDS} instance that collects circuit tasks and connections.
34
+ #
35
+ # @return [Process, Hash] The {Process} instance and its outputs hash.
36
+ def self.call(adds)
37
+ circuit, end_events = Finalizer.(adds)
38
+ outputs = recompile_outputs(end_events)
39
+
40
+ return circuit, outputs
41
+ end
42
+
43
+ private
44
+
45
+ def self.recompile_outputs(end_events)
46
+ ary = end_events.collect do |evt|
47
+ [
48
+ semantic = evt.to_h[:semantic],
49
+ Activity::Output(evt, semantic)
50
+ ]
51
+ end
52
+
53
+ ::Hash[ ary ]
54
+ end
55
+ end # Recompile
56
+ end # State
57
+ end
58
+ end
@@ -0,0 +1,51 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ class Builder
4
+ module Finalizer
5
+
6
+ def self.call(adds)
7
+ tripletts = adds_to_tripletts(adds)
8
+
9
+ circuit_hash = tripletts_to_circuit_hash( tripletts )
10
+
11
+ circuit_hash_to_process( circuit_hash )
12
+ end
13
+
14
+ def self.adds_to_tripletts(adds)
15
+ alterations = adds_to_alterations(adds)
16
+
17
+ alterations.to_a
18
+ end
19
+
20
+ def self.adds_to_alterations(adds)
21
+ alterations = DSL::Alterations.new
22
+
23
+ adds = adds.compact # TODO: test me explicitly, and where does this come from anyway?
24
+
25
+ adds.each { |method, cfg| alterations.send( method, *cfg ) }
26
+
27
+ alterations
28
+ end
29
+
30
+ def self.tripletts_to_circuit_hash(tripletts)
31
+ Activity::Magnetic::Generate.( tripletts )
32
+ end
33
+
34
+ def self.circuit_hash_to_process(circuit_hash)
35
+ end_events = end_events_for(circuit_hash)
36
+
37
+ return Circuit.new(circuit_hash, end_events, start_task: circuit_hash.keys.first), end_events
38
+ end
39
+
40
+ # Find all end events that don't have outgoing connections.
41
+ def self.end_events_for(circuit_hash)
42
+ ary = circuit_hash.collect do |task, connections|
43
+ task.kind_of?(Activity::End) && connections.empty? ? task : nil
44
+ end
45
+
46
+ ary.compact
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,62 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ # Transforms an array of {Triplett}s into a circuit hash.
4
+ module Generate
5
+ Line = Struct.new(:source, :output)
6
+ MinusPole = Struct.new(:color)
7
+
8
+ class OpenLines
9
+ def initialize
10
+ @arr = []
11
+ end
12
+
13
+ def pop(signal, &block)
14
+ lines = @arr.find_all { |line| line.output.color == signal }
15
+ @arr -= lines
16
+
17
+ lines.each(&block)
18
+ lines.any?
19
+ end
20
+
21
+ def <<((node, output))
22
+ @arr << Line.new(node, output)
23
+ end
24
+ end
25
+
26
+ def self.call(tasks)
27
+ open_plus_poles = OpenLines.new
28
+ open_minus_poles = OpenLines.new
29
+ circuit_hash = {}
30
+
31
+ tasks.each do |(magnetic_to, node, outputs)|
32
+ circuit_hash[ node ] ||= {} # DISCUSS: or needed?
33
+
34
+ magnetic_to.each do |edge_color| # minus poles
35
+ open_plus_poles.pop(edge_color) do |line|
36
+ connect( circuit_hash, line.source, line.output.signal, node )
37
+ end and next
38
+
39
+ # only run when there were no open_minus_poles
40
+ open_minus_poles << [node, MinusPole.new(edge_color)] # open inputs on a node, waiting to be connected.
41
+ end
42
+
43
+ outputs.each do |output|
44
+ open_minus_poles.pop(output.color) do |line|
45
+ connect( circuit_hash, node, output.signal, line.source )
46
+ end and next
47
+
48
+ # only run when there were no open_plus_poles
49
+ open_plus_poles << [node, output]
50
+ end
51
+ end
52
+
53
+ circuit_hash
54
+ end
55
+
56
+ # plus minus
57
+ def self.connect(circuit_hash, source, signal, target)
58
+ circuit_hash[ source ][ signal ] = target
59
+ end
60
+ end # Magnetic
61
+ end
62
+ end
@@ -0,0 +1,16 @@
1
+ class Trailblazer::V2_1::Activity < Module
2
+ module Magnetic
3
+ module Merge
4
+ def merge!(merged)
5
+ merged[:record].each do |key, args|
6
+ dsl_method, *args = args
7
+
8
+ return send( dsl_method, args[0], args[1], &args[2] ) if args[2]
9
+ send( dsl_method, args[0], args[1] )
10
+ end
11
+
12
+ self
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,76 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ module DSL
4
+ # This module only processes additional "wiring" options from the DSL calls
5
+ # Output(:success) => End("my.new")
6
+ #
7
+ # Returns PlusPoles and additional sequence alterations.
8
+ module ProcessOptions
9
+ module_function
10
+
11
+ # Output => target (End/"id"/:color)
12
+ # @return [PlusPole]
13
+ # @return additional alterations
14
+ #
15
+ # options:
16
+ # { DSL::Output[::Semantic] => target }
17
+ #
18
+ def call(id, options, plus_poles, &block)
19
+ polarization, adds =
20
+ options.
21
+ collect { |key, task|
22
+ # this method call is the only thing that really matters here. # TODO: make this transformation a bit more obvious.
23
+ process_tuple(id, key, task, plus_poles, &block)
24
+ }.
25
+ inject([[],[]]) { |memo, (polarization, adds)| memo[0]<<polarization; memo[1]<<adds; memo }
26
+
27
+ return polarization, adds.flatten(1)
28
+ end
29
+
30
+ def process_tuple(id, output, task, plus_poles, &block)
31
+ output = output_for(output, plus_poles) if output.kind_of?(Activity::DSL::OutputSemantic)
32
+
33
+ if task.kind_of?(Activity::End)
34
+ # raise %{An end event with semantic `#{task.to_h[:semantic]}` has already been added. Please use an ID reference: `=> "End.#{task.to_h[:semantic]}"`} if
35
+ new_edge = "#{id}-#{output.signal}"
36
+
37
+ [
38
+ Polarization.new( output: output, color: new_edge ),
39
+ [ [:add, [task.to_h[:semantic], [ [new_edge], task, [] ], group: :end]] ]
40
+ ]
41
+ # procs come from DSL calls such as `Path() do ... end`.
42
+ elsif task.is_a?(Proc)
43
+ start_color, activity = task.(block)
44
+
45
+ adds = activity.to_h[:adds]
46
+
47
+ [
48
+ Polarization.new( output: output, color: start_color ),
49
+ # TODO: this is a pseudo-"merge" and should be public API at some point.
50
+ # TODO: we also need to merge all the other states such as debug.
51
+ adds[1..-1] # drop start
52
+ ]
53
+ elsif task.is_a?(Activity::DSL::Track) # An additional plus polarization. Example: Output => :success
54
+ [
55
+ Polarization.new( output: output, color: task.color )
56
+ ]
57
+ else # ID: existing step
58
+ new_edge = "#{id}-#{output.signal}-#{task}" # edge from <id> to <target>
59
+
60
+ [
61
+ Polarization.new( output: output, color: new_edge ),
62
+ [[ :magnetic_to, [ task, [new_edge] ] ]], # mark target (`task`) as magnetic to the new edge.
63
+ ]
64
+ end
65
+ end
66
+
67
+ # @param semantic DSL::Output::Semantic
68
+ def output_for(semantic, plus_poles)
69
+ # DISCUSS: review PlusPoles#[]
70
+ output, _ = plus_poles.instance_variable_get(:@plus_poles)[semantic.value]
71
+ output or raise("Couldn't find existing output for `#{semantic.value.inspect}`.")
72
+ end
73
+ end # OptionsProcessing
74
+ end # DSL
75
+ end
76
+ end
@@ -0,0 +1,44 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ module DSL
4
+ # works on a generic Dependencies structure that has no knowledge of magnetism.
5
+ class Alterations
6
+ def initialize
7
+ @groups = Activity::Schema::Dependencies.new
8
+ @future_magnetic_to = {} # DISCUSS: future - should it be here?
9
+ end
10
+
11
+ def add(id, options, **sequence_options)
12
+ @groups.add(id, options, **sequence_options)
13
+
14
+ # DISCUSS: future - should it be here?
15
+ if magnetic_to = @future_magnetic_to.delete(id)
16
+ magnetic_to( id, magnetic_to )
17
+ end
18
+
19
+ self
20
+ end
21
+
22
+ # make `id` magnetic_to
23
+ def magnetic_to(id, magnetic_to)
24
+ group, index = @groups.find(id) # this can be a future task!
25
+
26
+ unless group # DISCUSS: future - should it be here?
27
+ @future_magnetic_to[id] = magnetic_to
28
+ return
29
+ end
30
+
31
+ arr = group[index].configuration.dup
32
+
33
+ arr[0] = arr[0] + magnetic_to
34
+ group.add(id, arr, replace: id)
35
+ end
36
+
37
+ # Returns array of tripletts.
38
+ def to_a
39
+ @groups.to_a
40
+ end
41
+ end
42
+ end # DSL
43
+ end
44
+ end
@@ -0,0 +1,85 @@
1
+ module Trailblazer::V2_1
2
+ module Activity::Magnetic
3
+ # A plus pole is associating an Output{:signal, :semantic} to a magnetic :color.
4
+ #
5
+ # When it comes to connecting tasks to each other, PlusPoles is the most important object
6
+ # here. When a task is added via the DSL, a PlusPoles is set up, and the DSL adds polarizations
7
+ # from the implementation and from the options (e.g. `Outputs(..) => ..`).
8
+ #
9
+ # These are then finalized and return the effective plus poles
10
+
11
+ # Polarization is one or multiple calls to PlusPoles
12
+
13
+
14
+
15
+
16
+
17
+ # Output(:signal, :semantic) => :color
18
+ # add / merge
19
+ # change existing, => color
20
+ #
21
+ #
22
+ # Produces [ PlusPole, PlusPole, ] via `to_a`.
23
+ #
24
+ # @privat
25
+ # @note This is private until we know what we want.
26
+ class PlusPoles
27
+ def initialize(plus_poles={})
28
+ @plus_poles = plus_poles.freeze
29
+ end
30
+
31
+ # merge( Activity::Magnetic.Output(Right, :success) => :success
32
+ def merge(output_to_color)
33
+ overrides = ::Hash[ output_to_color.collect { |output, color| [ output.semantic, [output, color] ] } ]
34
+ PlusPoles.new(@plus_poles.merge(overrides))
35
+ end
36
+
37
+ def reverse_merge(output_to_color)
38
+ existing_colors = @plus_poles.values.collect { |pole_cfg| pole_cfg.last }
39
+
40
+ # filter all outputs with a color that already exists.
41
+ overrides = output_to_color.find_all { |output, color| !existing_colors.include?(color) }
42
+ merge(overrides)
43
+ end
44
+
45
+ def reconnect(semantic_to_color)
46
+ ary = semantic_to_color.collect do |semantic, color|
47
+ existing_output, _ = @plus_poles[semantic]
48
+
49
+ next unless existing_output
50
+
51
+ [ Activity.Output(existing_output.signal, existing_output.semantic), color ]
52
+ end
53
+
54
+ merge( ::Hash[ary.compact] )
55
+ end
56
+
57
+ # Compile one {PlusPoles} instance from all a sequence of {Polarization}s.
58
+ # This is usually called once per `step` DSL call.
59
+ #
60
+ # @api private
61
+ def self.apply_polarizations(polarizations, magnetic_to, plus_poles, options)
62
+ magnetic_to, plus_poles = polarizations.inject([magnetic_to, plus_poles]) do |args, pol|
63
+ magnetic_to, plus_poles = pol.(*args, options)
64
+ end
65
+
66
+ return magnetic_to, plus_poles.to_a
67
+ end
68
+
69
+ # The DSL is a series of transformations that yield in tasks with several PlusPole instances each.
70
+ #
71
+ # @api private
72
+ def to_a
73
+ @plus_poles.values.collect { |output, color| PlusPole.new(output, color) }
74
+ end
75
+
76
+ # FIXME: should this be a hash or whatever?
77
+ #
78
+ # @return Hash All {Output}s mapped to their (guessed) semantic: `{ Output(Right, :success) => :success }`
79
+ def self.initial(outputs)
80
+ new.merge(Hash[ outputs.collect { |semantic, output| [output, semantic] } ])
81
+ end
82
+ end
83
+ end
84
+ end
85
+