trailblazer-activity 0.3.2 → 0.4.o

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. checksums.yaml +5 -5
  2. data/.travis.yml +4 -3
  3. data/CHANGES.md +4 -0
  4. data/lib/trailblazer/activity.rb +82 -140
  5. data/lib/trailblazer/activity/config.rb +37 -0
  6. data/lib/trailblazer/activity/dsl/add_task.rb +22 -0
  7. data/lib/trailblazer/activity/dsl/helper.rb +49 -0
  8. data/lib/trailblazer/activity/implementation/build_state.rb +31 -0
  9. data/lib/trailblazer/activity/implementation/fast_track.rb +14 -0
  10. data/lib/trailblazer/activity/implementation/interface.rb +16 -0
  11. data/lib/trailblazer/activity/implementation/path.rb +55 -0
  12. data/lib/trailblazer/activity/implementation/railway.rb +18 -0
  13. data/lib/trailblazer/activity/{introspection.rb → introspect.rb} +33 -11
  14. data/lib/trailblazer/activity/magnetic.rb +7 -18
  15. data/lib/trailblazer/activity/magnetic/builder.rb +37 -92
  16. data/lib/trailblazer/activity/magnetic/builder/default_normalizer.rb +26 -0
  17. data/lib/trailblazer/activity/magnetic/builder/fast_track.rb +13 -15
  18. data/lib/trailblazer/activity/magnetic/builder/normalizer.rb +105 -0
  19. data/lib/trailblazer/activity/magnetic/builder/path.rb +14 -15
  20. data/lib/trailblazer/activity/magnetic/builder/railway.rb +8 -11
  21. data/lib/trailblazer/activity/magnetic/dsl.rb +4 -1
  22. data/lib/trailblazer/activity/magnetic/finalizer.rb +1 -1
  23. data/lib/trailblazer/activity/magnetic/merge.rb +18 -0
  24. data/lib/trailblazer/activity/present.rb +1 -1
  25. data/lib/trailblazer/activity/schema/dependencies.rb +6 -1
  26. data/lib/trailblazer/activity/state.rb +58 -0
  27. data/lib/trailblazer/activity/structures.rb +1 -2
  28. data/lib/trailblazer/activity/subprocess.rb +6 -3
  29. data/lib/trailblazer/activity/task_builder.rb +38 -0
  30. data/lib/trailblazer/activity/task_wrap.rb +46 -0
  31. data/lib/trailblazer/{wrap → activity/task_wrap}/call_task.rb +3 -3
  32. data/lib/trailblazer/activity/task_wrap/merge.rb +23 -0
  33. data/lib/trailblazer/{wrap → activity/task_wrap}/runner.rb +14 -16
  34. data/lib/trailblazer/{wrap → activity/task_wrap}/trace.rb +3 -3
  35. data/lib/trailblazer/activity/trace.rb +22 -28
  36. data/lib/trailblazer/activity/version.rb +2 -2
  37. data/lib/trailblazer/circuit.rb +7 -5
  38. data/trailblazer-activity.gemspec +2 -1
  39. metadata +39 -14
  40. data/lib/trailblazer/activity/heritage.rb +0 -30
  41. data/lib/trailblazer/activity/magnetic/builder/block.rb +0 -37
  42. data/lib/trailblazer/activity/process.rb +0 -16
  43. data/lib/trailblazer/activity/wrap.rb +0 -22
@@ -0,0 +1,16 @@
1
+ class Trailblazer::Activity < Module
2
+ module Interface
3
+ # @return [Process, Hash, Adds] Adds is private and should not be used in your application as it might get removed.
4
+ def decompose # TODO: test me
5
+ @state.to_h
6
+ end
7
+
8
+ def debug # TODO: TEST ME
9
+ decompose[:debug]
10
+ end
11
+
12
+ def outputs
13
+ decompose[:outputs]
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,55 @@
1
+ module Trailblazer
2
+ class Activity < Module
3
+ def self.Path(options={})
4
+ Activity::Path.new(Path, options)
5
+ end
6
+
7
+ # Implementation module that can be passed to `Activity[]`.
8
+ class Path < Activity
9
+ # Default variables, called in {Activity::initialize}.
10
+ def self.config
11
+ {
12
+ builder_class: Magnetic::Builder::Path, # we use the Activity-based Normalizer
13
+ normalizer_class: Magnetic::Normalizer,
14
+ plus_poles: Magnetic::Builder::Path.default_plus_poles,
15
+ extension: [ Introspect.method(:add_introspection) ],
16
+
17
+ extend: [ DSL.def_dsl(:task) ],
18
+ }
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
53
+ end
54
+ end
55
+
@@ -0,0 +1,18 @@
1
+ module Trailblazer
2
+ # Implementation module that can be passed to `Activity[]`.
3
+ class Activity < Module
4
+ def self.Railway(options={})
5
+ Railway.new(Railway, options)
6
+ end
7
+
8
+ class Railway < Activity
9
+ def self.config
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) ],
14
+ )
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,10 +1,30 @@
1
1
  module Trailblazer
2
- class Activity
3
- # Introspection is not used at run-time except for rendering diagrams, tracing, and the like.
2
+ class Activity < Module # Introspection is not used at run-time except for rendering diagrams, tracing, and the like.
4
3
  module Introspect
4
+ # {:argumenter} API
5
+ def self.arguments_for_call(activity, (options, flow_options), **circuit_options)
6
+ circuit_options = circuit_options.merge( introspect: activity.debug )
7
+
8
+ return activity, [ options, flow_options ], circuit_options
9
+ end
10
+
11
+ # {Extension} API
12
+ def self.add_introspection(activity, task, local_options, *returned_options)
13
+ activity[:debug, task] = { id: local_options[:id] || task }
14
+ end
15
+
16
+
17
+ # @api private
18
+ def self.find(activity, &block)
19
+ circuit = activity.decompose[:circuit]
20
+
21
+ circuit.instance_variable_get(:@map).find(&block)
22
+ end
23
+
5
24
 
6
25
  def self.collect(activity, options={}, &block)
7
- circuit_hash, _ = activity.decompose
26
+ circuit = activity.decompose[:circuit]
27
+ circuit_hash, _ = circuit.decompose
8
28
 
9
29
  locals = circuit_hash.collect do |task, connections|
10
30
  [
@@ -15,9 +35,11 @@ module Trailblazer
15
35
  end
16
36
 
17
37
 
38
+ # FIXME: clean up that shit below.
39
+
18
40
  # render
19
- def self.Cct(process, **options)
20
- circuit_hash( process.instance_variable_get(:@circuit).to_fields[0], **options )
41
+ def self.Cct(circuit, **options)
42
+ circuit_hash( circuit.decompose[0], **options )
21
43
  end
22
44
 
23
45
  def self.circuit_hash(circuit_hash, show_ids:false)
@@ -33,11 +55,11 @@ module Trailblazer
33
55
  content = content.join("\n")
34
56
 
35
57
  return "\n#{content}" if show_ids
36
- return "\n#{content}".gsub(/\d\d+/, "")
58
+ return "\n#{content}".gsub(/0x\w+/, "0x").gsub(/0.\d+/, "0.")
37
59
  end
38
60
 
39
- def self.Ends(process)
40
- end_events = process.instance_variable_get(:@circuit).to_fields[1]
61
+ def self.Ends(activity)
62
+ end_events = activity.decompose[1]
41
63
  ends = end_events.collect { |evt| Task(evt) }.join(",")
42
64
  "[#{ends}]".gsub(/\d\d+/, "")
43
65
  end
@@ -74,9 +96,9 @@ module Trailblazer
74
96
 
75
97
  def self.cct(builder)
76
98
  adds = builder.instance_variable_get(:@adds)
77
- process, _ = Builder::Finalizer.(adds)
99
+ circuit, _ = Builder::Finalizer.(adds)
78
100
 
79
- Cct(process)
101
+ Cct(circuit)
80
102
  end
81
103
 
82
104
  private
@@ -90,7 +112,7 @@ module Trailblazer
90
112
  #{pluses.empty? ? " []" : pluses.join("\n")}}
91
113
  end.join("\n")
92
114
 
93
- "\n#{content}\n".gsub(/\d\d+/, "")
115
+ "\n#{content}\n".gsub(/\d\d+/, "").gsub(/0x\w+/, "0x")
94
116
  end
95
117
 
96
118
  def self.PlusPole(plus_pole)
@@ -1,6 +1,5 @@
1
1
  module Trailblazer
2
- class Activity
3
- # all code related to the magnetic building of a circuit hash lives in this namespace.
2
+ class Activity < Module # all code related to the magnetic building of a circuit hash lives in this namespace.
4
3
  module Magnetic
5
4
  # PlusPole "radiates" a color that MinusPoles are attracted to.
6
5
  #
@@ -13,21 +12,6 @@ module Trailblazer
13
12
  end
14
13
  end # PlusPole
15
14
  end
16
-
17
- class Process
18
- def self.plan(options={}, &block)
19
- Magnetic::Builder::Path.plan(options, &block)
20
- end
21
-
22
- def self.build(options={}, &block)
23
- Magnetic::Builder::Path.build(options, &block)
24
- end
25
-
26
- def self.draft(options={}, &block) # TODO: remove me!
27
- Magnetic::Builder::Path.draft(options, &block)
28
- end
29
- end
30
-
31
15
  end
32
16
  end
33
17
 
@@ -39,7 +23,12 @@ require "trailblazer/activity/schema/dependencies"
39
23
 
40
24
  require "trailblazer/activity/magnetic"
41
25
  require "trailblazer/activity/magnetic/builder"
42
- require "trailblazer/activity/magnetic/builder/block"
26
+ # require "trailblazer/activity/magnetic/builder/dsl_helper"
27
+ # require "trailblazer/activity/magnetic/dsl_helper"
28
+
29
+ require "trailblazer/option"
30
+ require "trailblazer/activity/task_builder"
31
+ require "trailblazer/activity/magnetic/builder/default_normalizer"
43
32
  require "trailblazer/activity/magnetic/builder/path"
44
33
  require "trailblazer/activity/magnetic/builder/railway"
45
34
  require "trailblazer/activity/magnetic/builder/fast_track" # TODO: move to Operation gem.
@@ -2,6 +2,19 @@ require "trailblazer/activity/magnetic/finalizer"
2
2
 
3
3
  module Trailblazer
4
4
  module Activity::Magnetic
5
+
6
+ # TODO: move?
7
+ module Options
8
+ # Produce two hashes, one "local" options with DSL-specific options such as `:fast_track`,
9
+ # one with generic DSL options, for example tuples like `Right=>Output(:failure)`.
10
+ def self.normalize(options, local_keys)
11
+ local, foreign = {}, {}
12
+ options.each { |k,v| local_keys.include?(k) ? local[k] = v : foreign[k] = v }
13
+
14
+ return foreign, local
15
+ end
16
+ end
17
+
5
18
  def self.Builder(implementation, normalizer, builder_options={})
6
19
  builder = implementation.new(normalizer, builder_options.freeze).freeze # e.g. Path.new(...)
7
20
 
@@ -9,115 +22,63 @@ module Trailblazer
9
22
  end
10
23
 
11
24
  class Builder
12
-
13
- def self.plan_for(builder, adds, &block)
14
- adds += Block.new(builder).(&block) # returns ADDS
15
- end
16
-
17
- def self.build(options={}, &block)
18
- adds = plan( options, &block )
19
-
20
- Finalizer.(adds)
21
- end
22
-
23
25
  def initialize(normalizer, builder_options)
24
26
  @normalizer, @builder_options = normalizer, builder_options
25
27
  end
26
28
 
27
- def self.merge(activity, merged)
28
- merged = merged[2..-1] || []
29
+ def self.merge(activity_adds, merged_adds)
30
+ merged_adds = merged_adds[2..-1] || []
29
31
 
30
- activity + merged
32
+ activity_adds + merged_adds
31
33
  end
32
34
 
33
- module DSLMethods
34
- # Output( Left, :failure )
35
- # Output( :failure ) #=> Output::Semantic
36
- def Output(signal, semantic=nil)
37
- return DSL::Output::Semantic.new(signal) if semantic.nil?
35
+ # Stateful helper.
36
+ def Path(*args)
37
+ Activity::DSL::Helper.Path(@normalizer, *args)
38
+ end
38
39
 
39
- Activity.Output(signal, semantic)
40
- end
40
+ def insert(name, task, options, &block)
41
+ normalizer = options[:normalizer] || @normalizer # DISCUSS: do this at a deeper point?
41
42
 
42
- def End(name, semantic)
43
- Activity.End(name, semantic)
44
- end
43
+ task, local_options, connection_options, sequence_options = normalizer.(task, options)
45
44
 
46
- def Path(track_color: "track_#{rand}", end_semantic: :success, **options)
47
- options = options.merge(track_color: track_color, end_semantic: end_semantic)
45
+ implementation, polarizations, task, local_options, block = send(name, task, local_options, &block) # builder.task
48
46
 
49
- # this block is called in DSL::ProcessTuples.
50
- ->(block) { [ track_color, Builder::Path.plan( options, @normalizer, &block ) ] }
51
- end
47
+ insert_element( implementation, polarizations, task, local_options, connection_options, sequence_options, &block )
52
48
  end
53
49
 
54
- include DSLMethods
55
-
56
50
  private
57
51
 
58
52
  # Internal top-level entry point to add task(s) and connections.
59
- def insert_element(impl, polarizations, task, options, &block)
60
- normalizer = options[:normalizer] || @normalizer # DISCUSS: do this at a deeper point?
61
-
62
- adds, *returned_options = Builder.adds_for(polarizations, normalizer, task, options, &block)
63
- end
64
-
65
- def self.sequence_keywords
66
- [ :group, :before, :after, :replace, :delete ] # hard-wires Builder to Sequence/Alterations.
67
- end
68
-
69
- # Produce two hashes, one "local" options with DSL-specific options such as `:fast_track`,
70
- # one with generic DSL options, for example tuples like `Right=>Output(:failure)`.
71
- def self.normalize(options, local_keys)
72
- local, foreign = {}, {}
73
- options.each { |k,v| local_keys.include?(k) ? local[k] = v : foreign[k] = v }
74
-
75
- return foreign, local
53
+ def insert_element(impl, polarizations, task, local_options, connection_options, sequence_options, &block)
54
+ adds, *returned_options = Builder.adds_for(polarizations, task, local_options, connection_options, sequence_options, &block)
76
55
  end
77
56
 
78
57
  # @return Adds
79
58
  # High level interface for DSL calls like ::task or ::step.
80
59
  # TODO: RETURN ALL OPTIONS
81
- def self.adds_for(polarizations, normalizer, task, options, &block)
82
- task, local_options, options, sequence_options = normalize_options(normalizer, task, options)
83
-
84
- initial_plus_poles = local_options[:plus_poles]
85
- magnetic_to = local_options[:magnetic_to]
86
- adds = local_options[:adds] || []
87
-
60
+ def self.adds_for(polarizations, task, local_options, connection_options, sequence_options, &block)
88
61
  # go through all wiring options such as Output()=>:color.
89
- polarizations_from_user_options, additional_adds = DSL::ProcessOptions.(local_options[:id], options, initial_plus_poles, &block)
62
+ polarizations_from_user_options, additional_adds = process_dsl_options(connection_options, local_options, &block)
90
63
 
91
- result = adds(local_options[:id], task, initial_plus_poles, polarizations, polarizations_from_user_options, local_options, sequence_options, magnetic_to)
64
+ polarizations = polarizations + polarizations_from_user_options
92
65
 
93
- return result + adds + additional_adds, task, local_options, options, sequence_options
94
- end
66
+ result = adds(task, polarizations, local_options, sequence_options, local_options)
95
67
 
96
- # @private
97
- def self.normalize_options(normalizer, task, options)
98
- keywords = extract_dsl_keywords(options)
99
-
100
- # sort through the "original" user DSL options.
101
- options, local_options = normalize( options, keywords ) # DISCUSS:
102
- local_options, sequence_options = normalize( local_options, sequence_keywords )
103
-
104
- task, local_options, options, sequence_options = normalizer.(task, local_options, options, sequence_options)
105
-
106
- return task, local_options, options, sequence_options
68
+ return result + (local_options[:adds] || []) + additional_adds, task, local_options, connection_options, sequence_options
107
69
  end
108
70
 
109
- # Filter out connections, e.g. `Output(:fail_fast) => :success` and return only the keywords like `:id` or `:replace`.
110
- def self.extract_dsl_keywords(options, connection_classes = [Activity::Output, DSL::Output::Semantic])
111
- options.keys - options.keys.find_all { |k| connection_classes.include?( k.class ) }
71
+ def self.process_dsl_options(options, id:nil, plus_poles:, **, &block)
72
+ DSL::ProcessOptions.(id, options, plus_poles, &block)
112
73
  end
113
74
 
114
75
  # Low-level interface for DSL calls (e.g. Start, where "you know what you're doing")
115
76
  # @private
116
- def self.adds(id, task, initial_plus_poles, polarization, polarizations_from_user_options, options, sequence_options, magnetic_to = nil)
77
+ def self.adds(task, polarizations, options, sequence_options, magnetic_to:nil, id:nil, plus_poles:, **) # DISCUSS: no :id ?
117
78
  magnetic_to, plus_poles = apply_polarizations(
118
- polarization + polarizations_from_user_options,
79
+ polarizations,
119
80
  magnetic_to,
120
- initial_plus_poles,
81
+ plus_poles,
121
82
  options
122
83
  )
123
84
 
@@ -142,22 +103,6 @@ module Trailblazer
142
103
  [ :add, [id, [ magnetic_to, task, plus_poles.to_a ], sequence_options] ],
143
104
  ]
144
105
  end
145
-
146
- class DefaultNormalizer
147
- def initialize( **default_options )
148
- raise "you didn't specify default :plus_poles" unless default_options[:plus_poles]
149
-
150
- @default_options = default_options
151
- end
152
-
153
- # called for every ::task, ::step call etc to defaultize the `local_options`.
154
- def call(task, local_options, options, sequence_options)
155
- local_options = @default_options.merge(local_options) # here, we merge default :plus_poles.
156
-
157
- return task, local_options, options, sequence_options
158
- end
159
- end
160
-
161
106
  end # Builder
162
107
  end
163
108
  end
@@ -0,0 +1,26 @@
1
+ module Trailblazer
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:, extension:[], **options)
9
+ return new(plus_poles: plus_poles, extension: extension), 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
@@ -12,10 +12,6 @@ module Trailblazer
12
12
  )
13
13
  end
14
14
 
15
- def self.plan(options={}, normalizer=DefaultNormalizer.new(plus_poles: default_plus_poles), &block)
16
- plan_for( *FastTrack.for(normalizer, options), &block )
17
- end
18
-
19
15
  def self.StepPolarizations(**options)
20
16
  [
21
17
  *Railway.StepPolarizations(options),
@@ -90,26 +86,28 @@ module Trailblazer
90
86
 
91
87
  ends =
92
88
  adds(
93
- "End.pass_fast", pass_fast_end,
89
+ pass_fast_end,
94
90
 
95
- {}, # plus_poles
96
91
  Path::TaskPolarizations(builder_options.merge( type: :End )),
97
- [],
98
92
 
99
93
  {},
100
94
  { group: :end },
101
- [:pass_fast]
95
+
96
+ id: "End.pass_fast",
97
+ magnetic_to: [:pass_fast],
98
+ plus_poles: {},
102
99
  )+
103
100
  adds(
104
- "End.fail_fast", fail_fast_end,
101
+ fail_fast_end,
105
102
 
106
- {}, # plus_poles
107
103
  Path::TaskPolarizations(builder_options.merge( type: :End )),
108
- [],
109
104
 
110
105
  {},
111
106
  { group: :end },
112
- [:fail_fast]
107
+
108
+ magnetic_to: [:fail_fast],
109
+ id: "End.fail_fast",
110
+ plus_poles: {},
113
111
  )
114
112
 
115
113
  path_adds + ends
@@ -120,15 +118,15 @@ module Trailblazer
120
118
  PassFast = Class.new(Activity::Signal)
121
119
 
122
120
  def step(task, options={}, &block)
123
- insert_element( FastTrack, FastTrack.StepPolarizations(@builder_options), task, options, &block )
121
+ return FastTrack, FastTrack.StepPolarizations(@builder_options), task, options, block
124
122
  end
125
123
 
126
124
  def fail(task, options={}, &block)
127
- insert_element( FastTrack, FastTrack.FailPolarizations(@builder_options), task, options, &block )
125
+ return FastTrack, FastTrack.FailPolarizations(@builder_options), task, options, block
128
126
  end
129
127
 
130
128
  def pass(task, options={}, &block)
131
- insert_element( FastTrack, FastTrack.PassPolarizations(@builder_options), task, options, &block )
129
+ return FastTrack, FastTrack.PassPolarizations(@builder_options), task, options, block
132
130
  end
133
131
  end
134
132
  end