trailblazer-activity 0.2.1 → 0.3.0
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 +4 -4
- data/CHANGES.md +4 -0
- data/NOTES_ +36 -0
- data/README.md +7 -7
- data/Rakefile +1 -1
- data/lib/trailblazer/activity.rb +137 -96
- data/lib/trailblazer/activity/heritage.rb +30 -0
- data/lib/trailblazer/activity/introspection.rb +105 -0
- data/lib/trailblazer/activity/magnetic.rb +47 -0
- data/lib/trailblazer/activity/magnetic/builder.rb +161 -0
- data/lib/trailblazer/activity/magnetic/builder/block.rb +37 -0
- data/lib/trailblazer/activity/magnetic/builder/fast_track.rb +141 -0
- data/lib/trailblazer/activity/magnetic/builder/path.rb +98 -0
- data/lib/trailblazer/activity/magnetic/builder/railway.rb +123 -0
- data/lib/trailblazer/activity/magnetic/dsl.rb +90 -0
- data/lib/trailblazer/activity/magnetic/dsl/alterations.rb +44 -0
- data/lib/trailblazer/activity/magnetic/dsl/plus_poles.rb +59 -0
- data/lib/trailblazer/activity/magnetic/finalizer.rb +55 -0
- data/lib/trailblazer/activity/magnetic/generate.rb +62 -0
- data/lib/trailblazer/activity/present.rb +12 -19
- data/lib/trailblazer/activity/process.rb +16 -0
- data/lib/trailblazer/activity/schema/dependencies.rb +41 -0
- data/lib/trailblazer/activity/schema/sequence.rb +46 -0
- data/lib/trailblazer/activity/structures.rb +41 -0
- data/lib/trailblazer/activity/subprocess.rb +9 -1
- data/lib/trailblazer/activity/trace.rb +25 -16
- data/lib/trailblazer/activity/version.rb +1 -1
- data/lib/trailblazer/activity/wrap.rb +4 -13
- data/lib/trailblazer/circuit.rb +4 -35
- data/lib/trailblazer/wrap/call_task.rb +2 -2
- data/lib/trailblazer/wrap/runner.rb +7 -1
- data/lib/trailblazer/wrap/trace.rb +6 -5
- metadata +21 -10
- data/lib/trailblazer/activity/graph.rb +0 -157
- data/lib/trailblazer/circuit/testing.rb +0 -58
- data/lib/trailblazer/container_chain.rb +0 -45
- data/lib/trailblazer/context.rb +0 -68
- data/lib/trailblazer/option.rb +0 -78
- data/lib/trailblazer/wrap/inject.rb +0 -32
- data/lib/trailblazer/wrap/variable_mapping.rb +0 -92
@@ -0,0 +1,123 @@
|
|
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
|
+
def self.plan(options={}, normalizer=DefaultNormalizer.new(plus_poles: default_plus_poles), &block)
|
14
|
+
plan_for( *Railway.for(normalizer, options), &block )
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.keywords
|
18
|
+
[:type]
|
19
|
+
end
|
20
|
+
|
21
|
+
def step(task, options={}, &block)
|
22
|
+
insert_element( Railway, Railway.StepPolarizations(@builder_options), task, options, &block )
|
23
|
+
end
|
24
|
+
|
25
|
+
def fail(task, options={}, &block)
|
26
|
+
insert_element( Railway, Railway.FailPolarizations(@builder_options), task, options, &block )
|
27
|
+
end
|
28
|
+
|
29
|
+
def pass(task, options={}, &block)
|
30
|
+
insert_element( Railway, Railway.PassPolarizations(@builder_options), task, options, &block )
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.default_plus_poles
|
34
|
+
DSL::PlusPoles.new.merge(
|
35
|
+
Activity.Output(Activity::Right, :success) => nil,
|
36
|
+
Activity.Output(Activity::Left, :failure) => nil,
|
37
|
+
).freeze
|
38
|
+
end
|
39
|
+
|
40
|
+
# Adds the End.failure end to the Path sequence.
|
41
|
+
# @return [Adds] list of Adds instances that can be chained or added to an existing sequence.
|
42
|
+
def self.InitialAdds(failure_color:raise, failure_end: Activity.End(failure_color, :failure), **builder_options)
|
43
|
+
path_adds = Path.InitialAdds(**builder_options)
|
44
|
+
|
45
|
+
end_adds = adds(
|
46
|
+
"End.#{failure_color}", failure_end,
|
47
|
+
|
48
|
+
{}, # plus_poles
|
49
|
+
Path::TaskPolarizations(builder_options.merge( type: :End )),
|
50
|
+
[],
|
51
|
+
|
52
|
+
{},
|
53
|
+
{ group: :end },
|
54
|
+
[failure_color]
|
55
|
+
)
|
56
|
+
|
57
|
+
path_adds + end_adds
|
58
|
+
end
|
59
|
+
|
60
|
+
# ONLY JOB: magnetic_to and Outputs ("Polarization") via PlusPoles.merge
|
61
|
+
def self.StepPolarizations(**options)
|
62
|
+
[
|
63
|
+
*Path.TaskPolarizations(options),
|
64
|
+
StepPolarization.new(options)
|
65
|
+
]
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.PassPolarizations(options)
|
69
|
+
[
|
70
|
+
Railway::PassPolarization.new( options )
|
71
|
+
]
|
72
|
+
end
|
73
|
+
|
74
|
+
def self.FailPolarizations(options)
|
75
|
+
[
|
76
|
+
Railway::FailPolarization.new( options )
|
77
|
+
]
|
78
|
+
end
|
79
|
+
|
80
|
+
class StepPolarization
|
81
|
+
def initialize(track_color: :success, failure_color: :failure, **o)
|
82
|
+
@track_color, @failure_color = track_color, failure_color
|
83
|
+
end
|
84
|
+
|
85
|
+
# Returns the polarization for a DSL call. Takes care of user options such as :magnetic_to.
|
86
|
+
def call(magnetic_to, plus_poles, options)
|
87
|
+
[
|
88
|
+
magnetic_to || default_magnetic_to,
|
89
|
+
plus_poles_for(plus_poles, options),
|
90
|
+
]
|
91
|
+
end
|
92
|
+
|
93
|
+
private
|
94
|
+
|
95
|
+
def plus_poles_for(plus_poles, options)
|
96
|
+
plus_poles.reconnect( :failure => @failure_color )
|
97
|
+
end
|
98
|
+
|
99
|
+
def default_magnetic_to
|
100
|
+
[@track_color]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class PassPolarization < StepPolarization
|
105
|
+
def plus_poles_for(plus_poles, options)
|
106
|
+
plus_poles.reconnect( :failure => @track_color, :success => @track_color )
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
class FailPolarization < StepPolarization
|
111
|
+
def default_magnetic_to
|
112
|
+
[@failure_color]
|
113
|
+
end
|
114
|
+
|
115
|
+
def plus_poles_for(plus_poles, options)
|
116
|
+
plus_poles.reconnect( :failure => @failure_color, :success => @failure_color )
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
end # Railway
|
121
|
+
end # Builder
|
122
|
+
end
|
123
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Activity::Magnetic
|
3
|
+
module DSL
|
4
|
+
class Polarization
|
5
|
+
def initialize( output:raise, color:raise )
|
6
|
+
@output, @color = output, color
|
7
|
+
end
|
8
|
+
|
9
|
+
def call(magnetic_to, plus_poles, options)
|
10
|
+
[
|
11
|
+
magnetic_to,
|
12
|
+
plus_poles.merge( @output => @color ) # this usually adds a new Output to the task.
|
13
|
+
]
|
14
|
+
end
|
15
|
+
end # Polarization
|
16
|
+
|
17
|
+
# This module only processes additional "wiring" options from the DSL calls
|
18
|
+
# Output(:success) => End("my.new")
|
19
|
+
#
|
20
|
+
# Returns PlusPoles and additional sequence alterations.
|
21
|
+
module ProcessOptions
|
22
|
+
module_function
|
23
|
+
|
24
|
+
# Output => target (End/"id"/:color)
|
25
|
+
# @return [PlusPole]
|
26
|
+
# @return additional alterations
|
27
|
+
#
|
28
|
+
# options:
|
29
|
+
# { DSL::Output[::Semantic] => target }
|
30
|
+
#
|
31
|
+
def call(id, options, initial_plus_poles, &block)
|
32
|
+
polarization, adds =
|
33
|
+
options.
|
34
|
+
collect { |key, task|
|
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)
|
37
|
+
}.
|
38
|
+
inject([[],[]]) { |memo, (polarization, adds)| memo[0]<<polarization; memo[1]<<adds; memo }
|
39
|
+
|
40
|
+
return polarization, adds.flatten(1)
|
41
|
+
end
|
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)
|
45
|
+
|
46
|
+
if task.kind_of?(Activity::End)
|
47
|
+
new_edge = "#{id}-#{output.signal}"
|
48
|
+
|
49
|
+
[
|
50
|
+
Polarization.new( output: output, color: new_edge ),
|
51
|
+
[ [:add, [task.instance_variable_get(:@name), [ [new_edge], task, [] ], group: :end]] ]
|
52
|
+
]
|
53
|
+
elsif task.is_a?(String) # let's say this means an existing step
|
54
|
+
new_edge = "#{output.signal}-#{task}"
|
55
|
+
|
56
|
+
[
|
57
|
+
Polarization.new( output: output, color: new_edge ),
|
58
|
+
[[ :magnetic_to, [ task, [new_edge] ] ]],
|
59
|
+
]
|
60
|
+
# procs come from DSL calls such as `Path() do ... end`.
|
61
|
+
elsif task.is_a?(Proc)
|
62
|
+
start_color, adds = task.(block)
|
63
|
+
|
64
|
+
[
|
65
|
+
Polarization.new( output: output, color: start_color ),
|
66
|
+
# TODO: this is a pseudo-"merge" and should be public API at some point.
|
67
|
+
adds[1..-1] # drop start
|
68
|
+
]
|
69
|
+
else # An additional plus polarization. Example: Output => :success
|
70
|
+
[
|
71
|
+
Polarization.new( output: output, color: task )
|
72
|
+
]
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# @param semantic DSL::Output::Semantic
|
77
|
+
def output_for(semantic, plus_poles)
|
78
|
+
# DISCUSS: review PlusPoles#[]
|
79
|
+
output, _ = plus_poles.instance_variable_get(:@plus_poles)[semantic.value]
|
80
|
+
output or raise("Couldn't find existing output for `#{semantic.value.inspect}`.")
|
81
|
+
end
|
82
|
+
end # OptionsProcessing
|
83
|
+
|
84
|
+
# DSL datastructures
|
85
|
+
module Output
|
86
|
+
Semantic = Struct.new(:value)
|
87
|
+
end
|
88
|
+
end # DSL
|
89
|
+
end
|
90
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
module Trailblazer
|
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,59 @@
|
|
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
|
@@ -0,0 +1,55 @@
|
|
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 Activity::Process.new( circuit_hash, end_events ), end_events
|
38
|
+
end
|
39
|
+
|
40
|
+
# Filters out unconnected ends, e.g. the standard end in nested tracks that weren't used.
|
41
|
+
def self.end_events_for(circuit_hash)
|
42
|
+
tasks_with_incoming_edge = circuit_hash.values.collect { |connections| connections.values }.flatten(1)
|
43
|
+
|
44
|
+
ary = circuit_hash.collect do |task, connections|
|
45
|
+
task.kind_of?(Activity::End) &&
|
46
|
+
connections.empty? &&
|
47
|
+
tasks_with_incoming_edge.include?(task) ? task : nil
|
48
|
+
end
|
49
|
+
|
50
|
+
ary.compact
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,62 @@
|
|
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
|
@@ -3,8 +3,7 @@ require "hirb"
|
|
3
3
|
module Trailblazer
|
4
4
|
class Activity
|
5
5
|
module Trace
|
6
|
-
# TODO:
|
7
|
-
# * Struct for debug_item
|
6
|
+
# TODO: make this simpler.
|
8
7
|
module Present
|
9
8
|
module_function
|
10
9
|
|
@@ -14,24 +13,18 @@ module Trailblazer
|
|
14
13
|
Hirb::Console.format_output(tree, class: :tree, type: :directory)
|
15
14
|
end
|
16
15
|
|
17
|
-
# API HERE is: we only know the current element (e.g. task), input, output, and have an "introspection" object that tells us more about the element.
|
18
|
-
# TODO: the debug_item's "api" sucks, this should be a struct.
|
19
16
|
def tree_for(stack, level, tree)
|
20
|
-
stack.each do |
|
21
|
-
task =
|
17
|
+
stack.each do |captured, *returned|
|
18
|
+
task = captured.task
|
22
19
|
|
23
|
-
|
24
|
-
introspect = debug_item[0].last
|
20
|
+
name = (node = captured.introspection[task]) ? node[:id] : task
|
25
21
|
|
26
|
-
|
27
|
-
|
28
|
-
tree << [ level, name ]
|
22
|
+
if returned.size == 1 # flat
|
23
|
+
tree << [ level, name ]
|
29
24
|
else # nesting
|
30
|
-
tree << [ level,
|
31
|
-
|
32
|
-
tree_for(debug_item[1..-2], level + 1, tree)
|
25
|
+
tree << [ level, name ]
|
33
26
|
|
34
|
-
|
27
|
+
tree_for(returned[0..-2], level + 1, tree)
|
35
28
|
end
|
36
29
|
|
37
30
|
tree
|
@@ -59,10 +52,10 @@ module Trailblazer
|
|
59
52
|
|
60
53
|
def color_map
|
61
54
|
{
|
62
|
-
Trailblazer::
|
63
|
-
Trailblazer::
|
64
|
-
Trailblazer::
|
65
|
-
Trailblazer::
|
55
|
+
Trailblazer::Activity::Start => :blue,
|
56
|
+
Trailblazer::Activity::End => :pink,
|
57
|
+
Trailblazer::Activity::Right => :green,
|
58
|
+
Trailblazer::Activity::Left => :red
|
66
59
|
}
|
67
60
|
end
|
68
61
|
|