trailblazer-activity 0.4.2 → 0.4.3

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bed08027bb74c9466a7dee0325bf2eb5fddc637eb2e46f3f86a3292e522fe083
4
- data.tar.gz: 3a89ef72fbbb55f084779cb376f68ef542486d4a5b0fe8af1200e594fea6f6b4
3
+ metadata.gz: b12275a2f1dfc9e9c90d7b3df76d2eab01db0964c453d61a23a307296cda2378
4
+ data.tar.gz: 93b881493ecec9eb50516cb1185ff1129c6fbc5efe478bc429604adae077c552
5
5
  SHA512:
6
- metadata.gz: 1c221eba23024d176d6c6c3376fd3aa6c5a668806d3b2cccd09e7a85496a07c833dddb74fa30e6c346eb0e8093b8186f1f8cc1557a21a37f1feddb7a9fabd7a9
7
- data.tar.gz: 27e679eab5c94988e821e05a7bdb25c301e656091f8bc100bb84a142cec3ec0f7fced3c61bb7ef0d5b2e89cd0847d22e7db2ca17c783906316628216dad93e12
6
+ metadata.gz: 7245451409ba95340e9a3ef5e9404df93b3e2f7aa9325fe2132bc45f4f7fbcd49370200dfe9532fb5fa8f4307fdd3f4c6eae480920927e232228361712ac8cef
7
+ data.tar.gz: a127529dea689958ff467558c6a373b37cfe0e2e2475b99b24f854488b672ff012cb8cccdfc3b02339e1b20e62eecbd92e5148fbe7e80ad5da7b8242e7f2c793
data/.travis.yml CHANGED
@@ -9,6 +9,6 @@ rvm:
9
9
  - 2.5.0
10
10
  matrix:
11
11
  include:
12
- - rvm: jruby-9.1.15.0
12
+ - rvm: jruby-head
13
13
  env: JRUBY_OPTS="--profile.api"
14
14
  before_install: gem install bundler
data/CHANGES.md CHANGED
@@ -1,3 +1,10 @@
1
+ # 0.4.3
2
+
3
+ * Make `:outputs` the canonical way to define outputs, and not `:plus_poles`. The latter is computed by the DSL if not passed.
4
+ * Allow injecting `inspect` implementations into `Introspect` methods.
5
+ * Add `Nested`.
6
+ * Add `TaskBuilder::Task#to_s`.
7
+
1
8
  # 0.4.2
2
9
 
3
10
  * `End` is not a `Struct` so we can maintain more state, and are immutable.
data/README.md CHANGED
@@ -4,7 +4,7 @@ The `activity` gem brings a light-weight DSL to define business processes, and t
4
4
 
5
5
  A process is a set of arbitrary pieces of logic you define, chained together and put into a meaningful context by an activity. Activity lets you focus on the implementation of steps while Trailblazer takes care of the control flow.
6
6
 
7
- Please find the [full documentation on the Trailblazer website](http://trailblazer.to/2.1/activity). [Note that the docs are WIP.]
7
+ Please find the [full documentation on the Trailblazer website](http://trailblazer.to/api-docs). [Note that the docs are WIP.]
8
8
 
9
9
  ## Example
10
10
 
@@ -0,0 +1,19 @@
1
+
2
+ module Inspect
3
+ def inspect
4
+ "nice view!"
5
+ end
6
+ end
7
+
8
+ module A
9
+ extend Inspect
10
+
11
+ def self.a
12
+ end
13
+ end
14
+
15
+ # jruby 9.1.7
16
+ puts A.method(:a).inspect #=> #<Method: A.a>
17
+ # 2.5
18
+ puts A.method(:a).inspect #=> #<Method: nice view!.a>
19
+
@@ -42,7 +42,7 @@ module Trailblazer
42
42
  module DSLHelper
43
43
  extend Forwardable
44
44
  def_delegators :@builder, :Path
45
- def_delegators DSL::Helper, :Output, :End
45
+ def_delegators DSL::Helper, :Output, :End, :Nested
46
46
 
47
47
  def Path(*args, &block)
48
48
  self[:builder].Path(*args, &block)
@@ -95,6 +95,7 @@ require "trailblazer/activity/config"
95
95
  require "trailblazer/activity/implementation/build_state"
96
96
  require "trailblazer/activity/implementation/interface"
97
97
  require "trailblazer/activity/implementation/path"
98
+ require "trailblazer/activity/implementation/plan"
98
99
  require "trailblazer/activity/implementation/railway"
99
100
  require "trailblazer/activity/implementation/fast_track"
100
101
 
@@ -44,6 +44,14 @@ module Trailblazer
44
44
  [ track_color, path ]
45
45
  }
46
46
  end
47
+
48
+ # Computes the :outputs options for {activity}
49
+ def Nested(activity)
50
+ {
51
+ task: activity,
52
+ outputs: activity.outputs
53
+ }
54
+ end
47
55
  end
48
56
  end
49
57
  end
@@ -22,6 +22,7 @@ class Trailblazer::Activity < Module
22
22
  return normalizer, options
23
23
  end
24
24
 
25
+ # @api private
25
26
  def self.build_state(normalizer, builder_class:, builder_options: {}, **options)
26
27
  builder, adds, circuit, outputs = State.build(builder_class, normalizer, options.merge(builder_options))
27
28
 
@@ -11,45 +11,13 @@ module Trailblazer
11
11
  {
12
12
  builder_class: Magnetic::Builder::Path, # we use the Activity-based Normalizer
13
13
  normalizer_class: Magnetic::Normalizer,
14
- plus_poles: Magnetic::Builder::Path.default_plus_poles,
14
+ default_outputs: Magnetic::Builder::Path.default_outputs,
15
15
  extension: [ Introspect.method(:add_introspection) ],
16
16
 
17
17
  extend: [ DSL.def_dsl(:task) ],
18
18
  }
19
19
  end
20
-
21
- def self.Plan()
22
- Plan
23
- end
24
-
25
- module Plan
26
- def self.extended(extended)
27
- extended.singleton_class.send :attr_accessor, :record
28
- extended.record = []
29
- extended.extend(Methods)
30
- end
31
-
32
- module Methods
33
- def task(*args, &block)
34
- record << [:task, args, block]
35
- end
36
- end
37
-
38
- def self.merge!(activity, plan)
39
- plan.record.each { |(dsl_method, args, block)| activity.send(dsl_method, *args, &block) }
40
- activity
41
- end
42
-
43
- # Creates a copy of the {activity} module and merges the {Plan} into it.
44
- #
45
- # @params activity [Activity] The activity to extend
46
- # @params plan [Plan] The plan providing additional steps
47
- # @return [Activity] A new, merged activity
48
- def self.merge(activity, plan)
49
- merge!(activity.clone, plan)
50
- end
51
- end
52
- end
20
+ end # Path
53
21
  end
54
22
  end
55
23
 
@@ -0,0 +1,36 @@
1
+ module Trailblazer
2
+ class Activity::Path < Activity
3
+ def self.Plan()
4
+ Plan
5
+ end
6
+
7
+ module Plan
8
+ def self.extended(extended)
9
+ extended.singleton_class.send :attr_accessor, :record
10
+ extended.record = []
11
+ extended.extend(Methods)
12
+ end
13
+
14
+ module Methods
15
+ def task(*args, &block)
16
+ record << [:task, args, block]
17
+ end
18
+ end
19
+
20
+ def self.merge!(activity, plan)
21
+ plan.record.each { |(dsl_method, args, block)| activity.send(dsl_method, *args, &block) }
22
+ activity
23
+ end
24
+
25
+ # Creates a copy of the {activity} module and merges the {Plan} into it.
26
+ #
27
+ # @params activity [Activity] The activity to extend
28
+ # @params plan [Plan] The plan providing additional steps
29
+ # @return [Activity] A new, merged activity
30
+ def self.merge(activity, plan)
31
+ merge!(activity.clone, plan)
32
+ end
33
+ end
34
+ end
35
+ end
36
+
@@ -8,9 +8,9 @@ module Trailblazer
8
8
  class Railway < Activity
9
9
  def self.config
10
10
  Path.config.merge(
11
- builder_class: Magnetic::Builder::Railway,
12
- plus_poles: Magnetic::Builder::Railway.default_plus_poles,
13
- extend: [ DSL.def_dsl(:step), DSL.def_dsl(:fail), DSL.def_dsl(:pass) ],
11
+ builder_class: Magnetic::Builder::Railway,
12
+ default_outputs: Magnetic::Builder::Railway.default_outputs,
13
+ extend: [ DSL.def_dsl(:step), DSL.def_dsl(:fail), DSL.def_dsl(:pass) ],
14
14
  )
15
15
  end
16
16
  end
@@ -35,6 +35,11 @@ module Trailblazer
35
35
  end
36
36
 
37
37
 
38
+ def self.inspect_task_builder(task)
39
+ proc = task.instance_variable_get(:@user_proc)
40
+ %{#<TaskBuilder{#{proc}}>}
41
+ end
42
+
38
43
  # FIXME: clean up that shit below.
39
44
 
40
45
  # render
@@ -42,14 +47,14 @@ module Trailblazer
42
47
  circuit_hash( circuit.to_h[:map], **options )
43
48
  end
44
49
 
45
- def self.circuit_hash(circuit_hash, show_ids:false)
50
+ def self.circuit_hash(circuit_hash, show_ids:false, **options)
46
51
  content =
47
52
  circuit_hash.collect do |task, connections|
48
53
  conns = connections.collect do |signal, target|
49
- " {#{signal}} => #{Task(target)}"
54
+ " {#{signal}} => #{inspect_with_matcher(target, **options)}"
50
55
  end
51
56
 
52
- [ Task(task), conns.join("\n") ]
57
+ [ inspect_with_matcher(task, **options), conns.join("\n") ]
53
58
  end
54
59
 
55
60
  content = content.join("\n")
@@ -60,7 +65,7 @@ module Trailblazer
60
65
 
61
66
  def self.Ends(activity)
62
67
  end_events = activity.to_h[:end_events]
63
- ends = end_events.collect { |evt| Task(evt) }.join(",")
68
+ ends = end_events.collect { |evt| inspect_end(evt) }.join(",")
64
69
  "[#{ends}]".gsub(/\d\d+/, "")
65
70
  end
66
71
 
@@ -70,9 +75,17 @@ module Trailblazer
70
75
  join("\n").gsub(/0x\w+/, "").gsub(/\d\d+/, "")
71
76
  end
72
77
 
73
- def self.Task(task)
74
- return task.inspect unless task.kind_of?(Trailblazer::Activity::End)
78
+ # If Ruby had pattern matching, this function wasn't necessary.
79
+ def self.inspect_with_matcher(task, inspect_task: method(:inspect_task), inspect_end: method(:inspect_end))
80
+ return inspect_task.(task) unless task.kind_of?(Trailblazer::Activity::End)
81
+ inspect_end.(task)
82
+ end
83
+
84
+ def self.inspect_task(task)
85
+ task.inspect
86
+ end
75
87
 
88
+ def self.inspect_end(task)
76
89
  class_name = strip(task.class)
77
90
  options = task.to_h
78
91
 
@@ -108,7 +121,7 @@ module Trailblazer
108
121
  sequence.collect do |(magnetic_to, task, plus_poles)|
109
122
  pluses = plus_poles.collect { |plus_pole| PlusPole(plus_pole) }
110
123
 
111
- %{#{magnetic_to.inspect} ==> #{Activity::Introspect.Task(task)}
124
+ %{#{magnetic_to.inspect} ==> #{Activity::Introspect.inspect_with_matcher(task)}
112
125
  #{pluses.empty? ? " []" : pluses.join("\n")}}
113
126
  end.join("\n")
114
127
 
@@ -16,8 +16,8 @@ module Trailblazer
16
16
  end
17
17
 
18
18
  require "trailblazer/activity/magnetic/dsl"
19
- require "trailblazer/activity/magnetic/dsl/plus_poles"
20
- require "trailblazer/activity/magnetic/dsl/alterations"
19
+ require "trailblazer/activity/magnetic/structure/plus_poles"
20
+ require "trailblazer/activity/magnetic/structure/alterations"
21
21
 
22
22
  require "trailblazer/activity/schema/dependencies"
23
23
 
@@ -15,6 +15,7 @@ module Trailblazer
15
15
  end
16
16
  end
17
17
 
18
+ # Called from Path/Railway/FastTrack, creates the specific {Builder} instance.
18
19
  def self.Builder(implementation, normalizer, builder_options={})
19
20
  builder = implementation.new(normalizer, builder_options.freeze).freeze # e.g. Path.new(...)
20
21
 
@@ -32,11 +33,14 @@ module Trailblazer
32
33
  activity_adds + merged_adds
33
34
  end
34
35
 
35
- # Stateful helper.
36
+ # DSL method to create a Path within an activity which is embedded.
37
+ #
38
+ # Output(:success) => Path() {}
36
39
  def Path(*args)
37
40
  Activity::DSL::Helper.Path(@normalizer, *args)
38
41
  end
39
42
 
43
+ # Public top-level entry point.
40
44
  def insert(name, task, options, &block)
41
45
  normalizer = options[:normalizer] || @normalizer # DISCUSS: do this at a deeper point?
42
46
 
@@ -50,13 +54,12 @@ module Trailblazer
50
54
  private
51
55
 
52
56
  # Internal top-level entry point to add task(s) and connections.
57
+ # High level interface for DSL calls like ::task or ::step.
53
58
  def insert_element(impl, polarizations, task, local_options, connection_options, sequence_options, &block)
54
59
  adds, *returned_options = Builder.adds_for(polarizations, task, local_options, connection_options, sequence_options, &block)
55
60
  end
56
61
 
57
62
  # @return Adds
58
- # High level interface for DSL calls like ::task or ::step.
59
- # TODO: RETURN ALL OPTIONS
60
63
  def self.adds_for(polarizations, task, local_options, connection_options, sequence_options, &block)
61
64
  # go through all wiring options such as Output()=>:color.
62
65
  polarizations_from_user_options, additional_adds = process_dsl_options(connection_options, local_options, &block)
@@ -75,7 +78,7 @@ module Trailblazer
75
78
  # Low-level interface for DSL calls (e.g. Start, where "you know what you're doing")
76
79
  # @private
77
80
  def self.adds(task, polarizations, options, sequence_options, magnetic_to:nil, id:nil, plus_poles:, **) # DISCUSS: no :id ?
78
- magnetic_to, plus_poles = apply_polarizations(
81
+ magnetic_to, plus_poles = PlusPoles.apply_polarizations(
79
82
  polarizations,
80
83
  magnetic_to,
81
84
  plus_poles,
@@ -88,19 +91,9 @@ module Trailblazer
88
91
  )
89
92
  end
90
93
 
91
- # Called once per DSL method call, e.g. ::step.
92
- #
93
- # The idea is to chain a bunch of PlusPoles transformations (and magnetic_to "transformations")
94
- # for each DSL call, and thus realize things like path+railway+fast_track
95
- def self.apply_polarizations(polarizations, magnetic_to, plus_poles, options)
96
- polarizations.inject([magnetic_to, plus_poles]) do |args, pol|
97
- magnetic, plus_poles = pol.(*args, options)
98
- end
99
- end
100
-
101
94
  def self.Add(id, task, magnetic_to, plus_poles, options, sequence_options)
102
95
  [
103
- [ :add, [id, [ magnetic_to, task, plus_poles.to_a ], sequence_options] ],
96
+ [ :add, [id, [ magnetic_to, task, plus_poles ], sequence_options] ],
104
97
  ]
105
98
  end
106
99
  end # Builder
@@ -1,40 +1,33 @@
1
1
  module Trailblazer
2
2
  module Activity::Magnetic
3
- # The {Normalizer} is called for every DSL call (step/pass/fail etc.) and normalizes/defaults
3
+ # One {Normalizer} instance is called for every DSL call (step/pass/fail etc.) and normalizes/defaults
4
4
  # the user options, such as setting `:id`, connecting the task's outputs or wrapping the user's
5
5
  # task via {TaskBuilder::Binary} in order to translate true/false to `Right` or `Left`.
6
6
  #
7
7
  # The Normalizer sits in the `@builder`, which receives all DSL calls from the Operation subclass.
8
8
  class Normalizer
9
- def self.build(task_builder: Activity::TaskBuilder::Binary, default_plus_poles: Normalizer.InitialPlusPoles(), pipeline: Pipeline, extension:[], **options)
9
+ def self.build(task_builder: Activity::TaskBuilder::Binary, default_outputs: Builder::Path.default_outputs, pipeline: Pipeline, extension:[], **options)
10
10
  return new(
11
- default_plus_poles: default_plus_poles,
12
- extension: extension,
13
- task_builder: task_builder,
14
- pipeline: pipeline,
11
+ default_outputs: default_outputs,
12
+ extension: extension,
13
+ task_builder: task_builder,
14
+ pipeline: pipeline,
15
15
  ), options
16
16
  end
17
17
 
18
- # @private Might be removed.
19
- def self.InitialPlusPoles
20
- Activity::Magnetic::DSL::PlusPoles.new.merge(
21
- Activity.Output(Activity::Right, :success) => nil,
22
- Activity.Output(Activity::Left, :failure) => nil,
23
- )
24
- end
25
-
26
- def initialize(task_builder:, default_plus_poles:, pipeline:, **options)
27
- @task_builder = task_builder
28
- @default_plus_poles = default_plus_poles
29
- @pipeline = pipeline # TODO: test me.
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.
30
22
  freeze
31
23
  end
32
24
 
33
25
  def call(task, options)
34
26
  ctx = {
35
- task: task, options: options,
36
- task_builder: @task_builder,
37
- default_plus_poles: @default_plus_poles,
27
+ task: task,
28
+ options: options,
29
+ task_builder: @task_builder,
30
+ default_outputs: @default_outputs,
38
31
  }
39
32
 
40
33
  signal, (ctx, ) = @pipeline.( [ctx] )
@@ -46,7 +39,7 @@ module Trailblazer
46
39
 
47
40
  # :default_plus_poles is an injectable option.
48
41
  module Pipeline
49
- extend Trailblazer::Activity::Path( normalizer_class: DefaultNormalizer, plus_poles: Builder::Path.default_plus_poles )
42
+ extend Trailblazer::Activity::Path( normalizer_class: DefaultNormalizer, plus_poles: PlusPoles.new.merge( Builder::Path.default_outputs.values ) ) # FIXME: the DefaultNormalizer actually doesn't need Left.
50
43
 
51
44
  def self.split_options( ctx, task:, options:, ** )
52
45
  keywords = extract_dsl_keywords(options)
@@ -84,11 +77,18 @@ module Trailblazer
84
77
  end
85
78
  end
86
79
 
87
- # Merge user options over defaults.
88
- def self.defaultize( ctx, local_options:, default_plus_poles:, ** ) # TODO: test :default_plus_poles
80
+ # :outputs passed: I know what I want to have connected.
81
+ # no :outputs: use default_outputs
82
+ # ALWAYS connect all outputs to their semantic-color.
83
+
84
+ # Create the `plus_poles: <PlusPoles>` tuple where the PlusPoles instance will act as the interface
85
+ # to rewire or add connections for the DSL.
86
+ def self.initialize_plus_poles( ctx, local_options:, default_outputs:, ** )
87
+ outputs = local_options[:outputs] || default_outputs
88
+
89
89
  ctx[:local_options] =
90
90
  {
91
- plus_poles: default_plus_poles,
91
+ plus_poles: PlusPoles.initial(outputs),
92
92
  }
93
93
  .merge(local_options)
94
94
  end
@@ -96,7 +96,7 @@ module Trailblazer
96
96
  task Activity::TaskBuilder::Binary.( method(:normalize_for_macro) ), id: "normalize_for_macro"
97
97
  task Activity::TaskBuilder::Binary.( method(:split_options) ), id: "split_options"
98
98
  task Activity::TaskBuilder::Binary.( method(:normalize_extension_option) ), id: "normalize_extension_option"
99
- task Activity::TaskBuilder::Binary.( method(:defaultize) ), id: "defaultize"
99
+ task Activity::TaskBuilder::Binary.( method(:initialize_plus_poles) ), id: "initialize_plus_poles"
100
100
  # task ->((ctx, _), **) { pp ctx; [Activity::Right, [ctx, _]] }
101
101
  end
102
102
  end # Normalizer
@@ -20,15 +20,16 @@ module Trailblazer
20
20
  return Path, polarizations, task, options, block
21
21
  end
22
22
 
23
-
24
- def self.default_plus_poles
25
- DSL::PlusPoles.new.merge(
26
- Activity.Output( Activity::Right, :success ) => nil
27
- ).freeze
23
+ # @private Might be removed.
24
+ def self.default_outputs
25
+ {
26
+ success: Activity.Output(Activity::Right, :success),
27
+ # failure: Activity.Output(Activity::Left, :failure),
28
+ }
28
29
  end
29
30
 
30
31
  # @return [Adds] list of Adds instances that can be chained or added to an existing sequence.
31
- def self.InitialAdds(track_color:raise, end_semantic:raise, default_plus_poles: self.default_plus_poles, track_end: Activity.End(end_semantic), **)
32
+ def self.InitialAdds(track_color:raise, end_semantic:raise, start_outputs: {success: self.default_outputs[:success]}, track_end: Activity.End(end_semantic), **)
32
33
 
33
34
  builder_options={ track_color: track_color, end_semantic: end_semantic }
34
35
 
@@ -41,7 +42,7 @@ module Trailblazer
41
42
 
42
43
  id: "Start.default",
43
44
  magnetic_to: [],
44
- plus_poles: default_plus_poles
45
+ plus_poles: PlusPoles.initial(start_outputs), # FIXME: this is actually redundant with Normalizer
45
46
  )
46
47
 
47
48
  end_adds = adds(
@@ -59,14 +60,14 @@ module Trailblazer
59
60
  start_adds + end_adds
60
61
  end
61
62
 
62
- def self.TaskPolarizations(track_color:raise, type: :task, **)
63
+ def self.TaskPolarizations(track_color:, type: :task, **)
63
64
  return [EndPolarization.new( track_color: track_color )] if type == :End # DISCUSS: should this dispatch be here?
64
65
 
65
66
  [TaskPolarization.new( track_color: track_color )]
66
67
  end
67
68
 
68
69
  class TaskPolarization
69
- def initialize( track_color:raise )
70
+ def initialize(track_color:)
70
71
  @track_color = track_color
71
72
  end
72
73
 
@@ -22,11 +22,10 @@ module Trailblazer
22
22
  return Railway, Railway.PassPolarizations(@builder_options), task, options, block
23
23
  end
24
24
 
25
- def self.default_plus_poles
26
- DSL::PlusPoles.new.merge(
27
- Activity.Output(Activity::Right, :success) => nil,
28
- Activity.Output(Activity::Left, :failure) => nil,
29
- ).freeze
25
+ def self.default_outputs
26
+ Path.default_outputs.merge(
27
+ :failure => Activity.Output(Activity::Left, :failure),
28
+ )
30
29
  end
31
30
 
32
31
  # Adds the End.failure end to the Path sequence.
@@ -28,30 +28,30 @@ module Trailblazer
28
28
  # options:
29
29
  # { DSL::Output[::Semantic] => target }
30
30
  #
31
- def call(id, options, initial_plus_poles, &block)
31
+ def call(id, options, plus_poles, &block)
32
32
  polarization, adds =
33
33
  options.
34
34
  collect { |key, task|
35
35
  # this method call is the only thing that really matters here. # TODO: make this transformation a bit more obvious.
36
- process_tuple(id, key, task, initial_plus_poles, &block)
36
+ process_tuple(id, key, task, plus_poles, &block)
37
37
  }.
38
38
  inject([[],[]]) { |memo, (polarization, adds)| memo[0]<<polarization; memo[1]<<adds; memo }
39
39
 
40
40
  return polarization, adds.flatten(1)
41
41
  end
42
42
 
43
- def process_tuple(id, output, task, initial_plus_poles, &block)
44
- output = output_for(output, initial_plus_poles) if output.kind_of?(DSL::Output::Semantic)
43
+ def process_tuple(id, output, task, plus_poles, &block)
44
+ output = output_for(output, plus_poles) if output.kind_of?(DSL::Output::Semantic)
45
45
 
46
46
  if task.kind_of?(Activity::End)
47
47
  new_edge = "#{id}-#{output.signal}"
48
48
 
49
49
  [
50
50
  Polarization.new( output: output, color: new_edge ),
51
- [ [:add, [task.instance_variable_get(:@name), [ [new_edge], task, [] ], group: :end]] ]
51
+ [ [:add, [task.to_h[:semantic], [ [new_edge], task, [] ], group: :end]] ]
52
52
  ]
53
53
  elsif task.is_a?(String) # let's say this means an existing step
54
- new_edge = "#{output.signal}-#{task}"
54
+ new_edge = "#{id}-#{output.signal}-#{task}"
55
55
 
56
56
  [
57
57
  Polarization.new( output: output, color: new_edge ),
@@ -0,0 +1,92 @@
1
+ module Trailblazer
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
+ # Builds PlusPoles from { semantic => Output }, which, surprisingly, is exactly what Activity::outputs looks like.
77
+ # The plus pole's color is set to the output's semantic.
78
+ def self.from_outputs(outputs)
79
+ ary = outputs.collect { |semantic, output| [ output, semantic ] }
80
+
81
+ new.merge(::Hash[ary])
82
+ end
83
+
84
+ # FIXME: should this be a hash or whatever?
85
+ #
86
+ # @return Hash All {Output}s mapped to their semantic: `{ Output(Right, :success) => :success }`
87
+ def self.initial(outputs)
88
+ new.merge(Hash[ outputs.collect { |semantic, output| [output, semantic] } ])
89
+ end
90
+ end
91
+ end
92
+ end
@@ -1,6 +1,6 @@
1
1
  module Trailblazer
2
2
  class Activity < Module # End event is just another callable task.
3
- # Builds an Activity::End instance.
3
+ # Builds an {Activity::End} instance.
4
4
  def self.End(semantic)
5
5
  End.new(semantic: semantic)
6
6
  end
@@ -48,6 +48,7 @@
48
48
  # semantic: the original "semantic" or role of the signal, such as :success. This usually comes from the activity hosting this output.
49
49
  Output = Struct.new(:signal, :semantic)
50
50
 
51
+ # Builds an {Activity::Output} instance.
51
52
  def self.Output(signal, color)
52
53
  Output.new(signal, color).freeze
53
54
  end
@@ -33,6 +33,11 @@ module Trailblazer
33
33
 
34
34
  [ direction, [ options, *args ], **circuit_args ]
35
35
  end
36
+
37
+ def inspect
38
+ %{#<Trailblazer::Activity::TaskBuilder::Task user_proc=#{@user_proc}>}
39
+ end
40
+ alias_method :to_s, :inspect
36
41
  end
37
42
  end
38
43
  end
@@ -1,4 +1,5 @@
1
- class Trailblazer::Activity < Module
1
+ module Trailblazer
2
+ class Activity < Module
2
3
  #
3
4
  # Example with tracing:
4
5
  #
@@ -8,39 +9,44 @@ class Trailblazer::Activity < Module
8
9
  # |-- Call (call actual task) id: "task_wrap.call_task"
9
10
  # |-- Trace.capture_return [optional]
10
11
  # |-- Wrap::End
11
- module TaskWrap
12
- # The actual activity that implements the taskWrap.
13
- def self.initial_activity
14
- Module.new do
15
- extend Trailblazer::Activity::Path( name: "taskWrap", normalizer_class: Magnetic::DefaultNormalizer )
12
+ module TaskWrap
13
+ # The actual activity that implements the taskWrap.
14
+ def self.initial_activity
15
+ Module.new do
16
+ extend Trailblazer::Activity::Path(
17
+ name: "taskWrap",
18
+ normalizer_class: Magnetic::DefaultNormalizer,
19
+ plus_poles: Magnetic::PlusPoles.initial( :success => Magnetic::Builder::Path.default_outputs[:success] ) # DefaultNormalizer doesn't give us default PlusPoles.
20
+ )
16
21
 
17
- task TaskWrap.method(:call_task), id: "task_wrap.call_task" # ::call_task is defined in task_wrap/call_task.
22
+ task TaskWrap.method(:call_task), id: "task_wrap.call_task" # ::call_task is defined in task_wrap/call_task.
23
+ end
18
24
  end
19
- end
20
-
21
- # Compute runtime arguments necessary to execute a taskWrap per task of the activity.
22
- def self.arguments_for_call(activity, (options, flow_options), **circuit_options)
23
- circuit_options = circuit_options.merge(
24
- runner: TaskWrap::Runner,
25
- wrap_runtime: circuit_options[:wrap_runtime] || {},
26
- wrap_static: activity[:wrap_static] || {},
27
- )
28
25
 
29
- return activity, [ options, flow_options ], circuit_options
30
- end
31
-
32
- module NonStatic
26
+ # Compute runtime arguments necessary to execute a taskWrap per task of the activity.
33
27
  def self.arguments_for_call(activity, (options, flow_options), **circuit_options)
34
28
  circuit_options = circuit_options.merge(
35
29
  runner: TaskWrap::Runner,
36
- wrap_runtime: circuit_options[:wrap_runtime] || {}, # FIXME:this sucks. (was:) this overwrites wrap_runtime from outside.
37
- wrap_static: ::Hash.new(TaskWrap.initial_activity), # add a default static wrap.
30
+ wrap_runtime: circuit_options[:wrap_runtime] || {},
31
+ wrap_static: activity[:wrap_static] || {},
38
32
  )
39
33
 
40
34
  return activity, [ options, flow_options ], circuit_options
41
35
  end
42
- end
43
36
 
44
- # better: MyClass < Activity(TaskWrap, ...)
37
+ module NonStatic
38
+ def self.arguments_for_call(activity, (options, flow_options), **circuit_options)
39
+ circuit_options = circuit_options.merge(
40
+ runner: TaskWrap::Runner,
41
+ wrap_runtime: circuit_options[:wrap_runtime] || {}, # FIXME:this sucks. (was:) this overwrites wrap_runtime from outside.
42
+ wrap_static: ::Hash.new(TaskWrap.initial_activity), # add a default static wrap.
43
+ )
44
+
45
+ return activity, [ options, flow_options ], circuit_options
46
+ end
47
+ end
48
+
49
+ # better: MyClass < Activity(TaskWrap, ...)
50
+ end
45
51
  end
46
52
  end
@@ -1,5 +1,5 @@
1
1
  module Trailblazer
2
2
  class Activity < Module
3
- VERSION = "0.4.2"
3
+ VERSION = "0.4.3"
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trailblazer-activity
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.2
4
+ version: 0.4.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-01-24 00:00:00.000000000 Z
11
+ date: 2018-02-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: hirb
@@ -112,6 +112,7 @@ files:
112
112
  - NOTES_
113
113
  - README.md
114
114
  - Rakefile
115
+ - inspeccccccccct.rb
115
116
  - lib/trailblazer-activity.rb
116
117
  - lib/trailblazer/activity.rb
117
118
  - lib/trailblazer/activity/config.rb
@@ -121,6 +122,7 @@ files:
121
122
  - lib/trailblazer/activity/implementation/fast_track.rb
122
123
  - lib/trailblazer/activity/implementation/interface.rb
123
124
  - lib/trailblazer/activity/implementation/path.rb
125
+ - lib/trailblazer/activity/implementation/plan.rb
124
126
  - lib/trailblazer/activity/implementation/railway.rb
125
127
  - lib/trailblazer/activity/introspect.rb
126
128
  - lib/trailblazer/activity/magnetic.rb
@@ -131,11 +133,11 @@ files:
131
133
  - lib/trailblazer/activity/magnetic/builder/path.rb
132
134
  - lib/trailblazer/activity/magnetic/builder/railway.rb
133
135
  - lib/trailblazer/activity/magnetic/dsl.rb
134
- - lib/trailblazer/activity/magnetic/dsl/alterations.rb
135
- - lib/trailblazer/activity/magnetic/dsl/plus_poles.rb
136
136
  - lib/trailblazer/activity/magnetic/finalizer.rb
137
137
  - lib/trailblazer/activity/magnetic/generate.rb
138
138
  - lib/trailblazer/activity/magnetic/merge.rb
139
+ - lib/trailblazer/activity/magnetic/structure/alterations.rb
140
+ - lib/trailblazer/activity/magnetic/structure/plus_poles.rb
139
141
  - lib/trailblazer/activity/present.rb
140
142
  - lib/trailblazer/activity/schema/dependencies.rb
141
143
  - lib/trailblazer/activity/schema/sequence.rb
@@ -1,59 +0,0 @@
1
- module Trailblazer
2
- module Activity::Magnetic
3
- module DSL
4
- # Output(:signal, :semantic) => :color
5
- # add / merge
6
- # change existing, => color
7
- #
8
- # Mutable DSL datastructure for managing all PlusPoles for a particular task.
9
- #
10
- # Produces [ PlusPole, PlusPole, ] via `to_a`.
11
- #
12
- # @privat
13
- # @note This is private until we know what we want.
14
- class PlusPoles
15
- def initialize(plus_poles={})
16
- @plus_poles = plus_poles.freeze
17
- end
18
-
19
- # merge( Activity::Magnetic.Output(Right, :success) => :success
20
- def merge(output_to_color)
21
- overrides = ::Hash[ output_to_color.collect { |output, color| [ output.semantic, [output, color] ] } ]
22
- PlusPoles.new(@plus_poles.merge(overrides))
23
- end
24
-
25
- def reverse_merge(output_to_color)
26
- existing_colors = @plus_poles.values.collect { |pole_cfg| pole_cfg.last }
27
-
28
- overrides = output_to_color.find_all { |output, color| !existing_colors.include?(color) } # filter all outputs with a color that already exists.
29
- merge(overrides)
30
- end
31
-
32
- def reconnect(semantic_to_color)
33
- ary = semantic_to_color.collect do |semantic, color|
34
- existing_output, _ = @plus_poles[semantic]
35
-
36
- next unless existing_output
37
-
38
- [ Activity.Output(existing_output.signal, existing_output.semantic), color ]
39
- end
40
-
41
- merge( ::Hash[ary.compact] )
42
- end
43
-
44
- # The DSL is a series of transformations that yield in tasks with several PlusPole instances each.
45
- def to_a
46
- @plus_poles.values.collect { |output, color| PlusPole.new(output, color) }
47
- end
48
-
49
- # Builds PlusPoles from { semantic => Output }, which, surprisingly, is exactly what Activity::outputs looks like.
50
- # The plus pole's color is set to the output's semantic.
51
- def self.from_outputs(outputs)
52
- ary = outputs.collect { |semantic, output| [ output, semantic ] }
53
-
54
- new.merge(::Hash[ary])
55
- end
56
- end
57
- end
58
- end
59
- end