trailblazer-activity 0.7.1 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop-https---raw-githubusercontent-com-trailblazer-meta-master-rubocop-yml +101 -0
  3. data/.rubocop.yml +4 -13
  4. data/.rubocop_todo.yml +474 -476
  5. data/.travis.yml +3 -2
  6. data/CHANGES.md +10 -0
  7. data/Gemfile +5 -4
  8. data/README.md +2 -0
  9. data/Rakefile +1 -1
  10. data/lib/trailblazer/activity.rb +29 -92
  11. data/lib/trailblazer/activity/circuit.rb +74 -0
  12. data/lib/trailblazer/activity/config.rb +4 -6
  13. data/lib/trailblazer/activity/introspect.rb +33 -129
  14. data/lib/trailblazer/activity/present.rb +14 -39
  15. data/lib/trailblazer/activity/schema.rb +13 -0
  16. data/lib/trailblazer/activity/schema/implementation.rb +10 -0
  17. data/lib/trailblazer/activity/schema/intermediate.rb +94 -0
  18. data/lib/trailblazer/activity/structures.rb +43 -43
  19. data/lib/trailblazer/activity/task_wrap.rb +29 -16
  20. data/lib/trailblazer/activity/task_wrap/call_task.rb +4 -4
  21. data/lib/trailblazer/activity/task_wrap/inject.rb +37 -0
  22. data/lib/trailblazer/activity/task_wrap/pipeline.rb +55 -0
  23. data/lib/trailblazer/activity/task_wrap/runner.rb +10 -19
  24. data/lib/trailblazer/activity/task_wrap/variable_mapping.rb +25 -97
  25. data/lib/trailblazer/activity/testing.rb +64 -22
  26. data/lib/trailblazer/activity/trace.rb +88 -41
  27. data/lib/trailblazer/activity/version.rb +4 -2
  28. data/trailblazer-activity.gemspec +5 -9
  29. metadata +18 -55
  30. data/lib/trailblazer/activity/dsl/add_task.rb +0 -22
  31. data/lib/trailblazer/activity/dsl/helper.rb +0 -68
  32. data/lib/trailblazer/activity/dsl/magnetic.rb +0 -36
  33. data/lib/trailblazer/activity/dsl/magnetic/builder.rb +0 -101
  34. data/lib/trailblazer/activity/dsl/magnetic/builder/default_normalizer.rb +0 -26
  35. data/lib/trailblazer/activity/dsl/magnetic/builder/fast_track.rb +0 -118
  36. data/lib/trailblazer/activity/dsl/magnetic/builder/normalizer.rb +0 -113
  37. data/lib/trailblazer/activity/dsl/magnetic/builder/path.rb +0 -105
  38. data/lib/trailblazer/activity/dsl/magnetic/builder/railway.rb +0 -97
  39. data/lib/trailblazer/activity/dsl/magnetic/builder/state.rb +0 -58
  40. data/lib/trailblazer/activity/dsl/magnetic/finalizer.rb +0 -51
  41. data/lib/trailblazer/activity/dsl/magnetic/generate.rb +0 -62
  42. data/lib/trailblazer/activity/dsl/magnetic/merge.rb +0 -16
  43. data/lib/trailblazer/activity/dsl/magnetic/process_options.rb +0 -76
  44. data/lib/trailblazer/activity/dsl/magnetic/structure/alterations.rb +0 -44
  45. data/lib/trailblazer/activity/dsl/magnetic/structure/plus_poles.rb +0 -85
  46. data/lib/trailblazer/activity/dsl/magnetic/structure/polarization.rb +0 -23
  47. data/lib/trailblazer/activity/dsl/record.rb +0 -11
  48. data/lib/trailblazer/activity/dsl/schema/dependencies.rb +0 -46
  49. data/lib/trailblazer/activity/dsl/schema/sequence.rb +0 -46
  50. data/lib/trailblazer/activity/dsl/strategy/build_state.rb +0 -32
  51. data/lib/trailblazer/activity/dsl/strategy/fast_track.rb +0 -24
  52. data/lib/trailblazer/activity/dsl/strategy/path.rb +0 -26
  53. data/lib/trailblazer/activity/dsl/strategy/plan.rb +0 -36
  54. data/lib/trailblazer/activity/dsl/strategy/railway.rb +0 -23
  55. data/lib/trailblazer/activity/interface.rb +0 -16
  56. data/lib/trailblazer/activity/task_wrap/merge.rb +0 -23
  57. data/lib/trailblazer/activity/task_wrap/trace.rb +0 -44
  58. data/lib/trailblazer/circuit.rb +0 -71
@@ -1,113 +0,0 @@
1
- module Trailblazer
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::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
@@ -1,105 +0,0 @@
1
- module Trailblazer
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
@@ -1,97 +0,0 @@
1
- module Trailblazer
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
@@ -1,58 +0,0 @@
1
- module Trailblazer
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
@@ -1,51 +0,0 @@
1
- module Trailblazer
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
@@ -1,62 +0,0 @@
1
- module Trailblazer
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