trailblazer-activity 0.5.2 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +4 -10
- data/CHANGES.md +22 -0
- data/lib/trailblazer/activity/dsl/add_task.rb +2 -2
- data/lib/trailblazer/activity/dsl/helper.rb +5 -0
- data/lib/trailblazer/activity/dsl/magnetic/builder/default_normalizer.rb +3 -3
- data/lib/trailblazer/activity/dsl/magnetic/builder/normalizer.rb +15 -10
- data/lib/trailblazer/activity/dsl/magnetic/builder/path.rb +26 -11
- data/lib/trailblazer/activity/dsl/magnetic/builder.rb +6 -6
- data/lib/trailblazer/activity/dsl/magnetic/finalizer.rb +1 -1
- data/lib/trailblazer/activity/dsl/magnetic/process_options.rb +2 -2
- data/lib/trailblazer/activity/dsl/strategy/path.rb +0 -1
- data/lib/trailblazer/activity/introspect.rb +39 -14
- data/lib/trailblazer/activity/present.rb +4 -1
- data/lib/trailblazer/activity/structures.rb +4 -4
- data/lib/trailblazer/activity/task_wrap/call_task.rb +1 -1
- data/lib/trailblazer/activity/task_wrap/merge.rb +1 -1
- data/lib/trailblazer/activity/task_wrap/runner.rb +14 -4
- data/lib/trailblazer/activity/task_wrap/trace.rb +25 -9
- data/lib/trailblazer/activity/task_wrap.rb +7 -19
- data/lib/trailblazer/activity/testing.rb +32 -0
- data/lib/trailblazer/activity/trace.rb +4 -7
- data/lib/trailblazer/activity/version.rb +1 -1
- data/lib/trailblazer/activity.rb +10 -10
- data/lib/trailblazer/circuit.rb +9 -21
- data/lib/trailblazer-activity.rb +1 -0
- metadata +3 -3
- data/inspeccccccccct.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 656825c80059310cf4a2d89a2214a20618bbd688c182285e8d3c24c8475b8233
|
4
|
+
data.tar.gz: 4fb358255fe07a12fcb94172a05f466ce3ac0cb66d3b9502a3622d2a4392a71f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 74361dffc29b0108e198a3a2bee9637b6519b2ad56b4fb9172aceffc92bee1bcb5dc5e1417dab33d9ba48340749bd5f4306bd16a2c22a1f5eb66cfea4991f04b
|
7
|
+
data.tar.gz: ad2fd6a2d6d4df1a2c8e167fd395ef05899f7389b95f8219239d4533c75632001992ff38eb240b300d1b2260544b85abd276372783f8a4c2480afc2a3e45a1a5
|
data/.travis.yml
CHANGED
@@ -1,14 +1,8 @@
|
|
1
1
|
sudo: false
|
2
2
|
language: ruby
|
3
3
|
rvm:
|
4
|
-
|
5
|
-
- 2.
|
6
|
-
- 2.
|
7
|
-
- 2.
|
8
|
-
- 2.4.3
|
9
|
-
- 2.5.0
|
10
|
-
matrix:
|
11
|
-
include:
|
12
|
-
- rvm: jruby-head
|
13
|
-
env: JRUBY_OPTS="--profile.api"
|
4
|
+
- 2.5.1
|
5
|
+
- 2.4.4
|
6
|
+
- 2.3.7
|
7
|
+
- 2.2.10
|
14
8
|
before_install: gem install bundler
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,25 @@
|
|
1
|
+
# 0.6.0
|
2
|
+
|
3
|
+
* The `:task` option in `Circuit::call` is now named `:start_task` for consistency.
|
4
|
+
* Removed the `:argumenter` option for `Activity::call`. Instead, an `Activity` passes itself via the `:activity` option.
|
5
|
+
* Removed the `:extension` option. Instead, any option from the DSL that `is_a?(DSL::Extension)` will be processed in `add_task!`.
|
6
|
+
* Replace argumenters with `TaskWrap::invoke`. This simplifies the whole `call` process, and moves all initialization of args to the top.
|
7
|
+
* Added `Introspect::Graph::find`.
|
8
|
+
* Removed `Introspect::Enumerator` in favor of the `Graph` API.
|
9
|
+
|
10
|
+
# 0.5.4
|
11
|
+
|
12
|
+
* Introducing `Introspect::Enumerator` and removing `Introspect.find`. `Enumerator` contains `Enumerable` and exposes all necessary utility methods.
|
13
|
+
|
14
|
+
# 0.5.3
|
15
|
+
|
16
|
+
* In Path(), allow referencing an existing task, instead of creating an end event.
|
17
|
+
This avoids having to use two `Output() => ..` and is much cleaner.
|
18
|
+
|
19
|
+
```ruby
|
20
|
+
Path( end_id: :find_model) do .. end
|
21
|
+
```
|
22
|
+
|
1
23
|
# 0.5.2
|
2
24
|
|
3
25
|
* In `Path()`, we removed the `#path` method in favor of a cleaner `task` DSL method. We now use the default plus_poles `success` and `failure` everywhere for consistency. This means that a `task` has two outputs, and if you referenced `Output(:success)`, that would be only one of them. We're planning to have `pass` back which has one `success` plus_pole, only. This change makes the DSL wiring behavior much more consistent.
|
@@ -12,10 +12,10 @@ class Trailblazer::Activity < Module
|
|
12
12
|
self[:circuit] = circuit
|
13
13
|
self[:outputs] = outputs
|
14
14
|
|
15
|
-
_, local_options = returned_options
|
15
|
+
_, local_options, connections, sequence_options, extension_options = returned_options
|
16
16
|
|
17
17
|
# {Extension API} call all extensions.
|
18
|
-
|
18
|
+
extension_options.keys.collect { |ext| ext.( self, *returned_options, original_dsl_args: [name, task, options, block] ) }
|
19
19
|
end
|
20
20
|
end
|
21
21
|
end
|
@@ -15,6 +15,11 @@ module Trailblazer
|
|
15
15
|
# @api private
|
16
16
|
OutputSemantic = Struct.new(:value)
|
17
17
|
Track = Struct.new(:color)
|
18
|
+
Extension = Struct.new(:callable) do
|
19
|
+
def call(*args, &block)
|
20
|
+
callable.(*args, &block)
|
21
|
+
end
|
22
|
+
end
|
18
23
|
|
19
24
|
# Shortcut functions for the DSL. These have no state.
|
20
25
|
module Helper
|
@@ -5,8 +5,8 @@ module Trailblazer
|
|
5
5
|
# task Callable, id: "success", before: "another"
|
6
6
|
class DefaultNormalizer
|
7
7
|
# Declarative::Variables
|
8
|
-
def self.build(plus_poles:,
|
9
|
-
return new(plus_poles: plus_poles
|
8
|
+
def self.build(plus_poles:, **options)
|
9
|
+
return new(plus_poles: plus_poles), options
|
10
10
|
end
|
11
11
|
|
12
12
|
def initialize(**default_options)
|
@@ -19,7 +19,7 @@ module Trailblazer
|
|
19
19
|
|
20
20
|
local_options, sequence_options = Options.normalize( local_options, Activity::Schema::Dependencies.sequence_keywords )
|
21
21
|
|
22
|
-
return task, local_options, {}, sequence_options
|
22
|
+
return task, local_options, {}, sequence_options, {}
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -30,9 +30,9 @@ module Trailblazer
|
|
30
30
|
default_outputs: @default_outputs,
|
31
31
|
}
|
32
32
|
|
33
|
-
signal, (ctx, ) = @pipeline.( [ctx] )
|
33
|
+
signal, (ctx, ) = @pipeline.( [ctx], {} )
|
34
34
|
|
35
|
-
return ctx[:options][:task], ctx[:local_options], ctx[:connection_options], ctx[:sequence_options]
|
35
|
+
return ctx[:options][:task], ctx[:local_options], ctx[:connection_options], ctx[:sequence_options], ctx[:extension_options]
|
36
36
|
end
|
37
37
|
|
38
38
|
# needs the basic Normalizer
|
@@ -42,15 +42,18 @@ module Trailblazer
|
|
42
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
43
|
|
44
44
|
def self.split_options( ctx, task:, options:, ** )
|
45
|
-
keywords
|
45
|
+
keywords = extract_dsl_keywords(options)
|
46
|
+
extensions = extract_extensions(options)
|
46
47
|
|
47
48
|
# sort through the "original" user DSL options.
|
49
|
+
options, extension_options = Options.normalize( options, extensions ) # DISCUSS:
|
48
50
|
options, local_options = Options.normalize( options, keywords ) # DISCUSS:
|
49
51
|
local_options, sequence_options = Options.normalize( local_options, Activity::Schema::Dependencies.sequence_keywords )
|
50
52
|
|
51
53
|
ctx[:local_options],
|
52
54
|
ctx[:connection_options],
|
53
|
-
ctx[:sequence_options]
|
55
|
+
ctx[:sequence_options],
|
56
|
+
ctx[:extension_options] = local_options, options, sequence_options, extension_options
|
54
57
|
end
|
55
58
|
|
56
59
|
# Filter out connections, e.g. `Output(:fail_fast) => :success` and return only the keywords like `:id` or `:replace`.
|
@@ -58,17 +61,19 @@ module Trailblazer
|
|
58
61
|
options.keys - options.keys.find_all { |k| connection_classes.include?( k.class ) }
|
59
62
|
end
|
60
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
|
+
|
61
68
|
# FIXME; why don't we use the extensions passed into the initializer?
|
62
|
-
def self.
|
63
|
-
|
69
|
+
def self.initialize_extension_option( ctx, options:, ** )
|
70
|
+
ctx[:options] = options.merge( Activity::DSL::Extension.new( Activity::DSL.method(:record) ) => true )
|
64
71
|
end
|
65
72
|
|
66
|
-
# Normalizes ctx[:options]
|
73
|
+
# Normalizes ctx[:options] (the user-options via the DSL) into the internal Hash format.
|
67
74
|
def self.normalize_for_macro( ctx, task:, options:, task_builder:, ** )
|
68
75
|
ctx[:options] =
|
69
76
|
if task.is_a?(::Hash) # macro.
|
70
|
-
options = options.merge(extension: (options[:extension]||[])+(task[:extension]||[]) ) # FIXME.
|
71
|
-
|
72
77
|
task.merge(options) # Note that the user options are merged over the macro options.
|
73
78
|
else # user step
|
74
79
|
{ id: task }
|
@@ -93,9 +98,9 @@ module Trailblazer
|
|
93
98
|
.merge(local_options)
|
94
99
|
end
|
95
100
|
|
101
|
+
task Activity::TaskBuilder::Binary( method(:initialize_extension_option) ), id: "initialize_extension_option"
|
96
102
|
task Activity::TaskBuilder::Binary( method(:normalize_for_macro) ), id: "normalize_for_macro"
|
97
103
|
task Activity::TaskBuilder::Binary( method(:split_options) ), id: "split_options"
|
98
|
-
task Activity::TaskBuilder::Binary( method(:normalize_extension_option) ), id: "normalize_extension_option"
|
99
104
|
task Activity::TaskBuilder::Binary( method(:initialize_plus_poles) ), id: "initialize_plus_poles"
|
100
105
|
# task ->((ctx, _), **) { pp ctx; [Activity::Right, [ctx, _]] }
|
101
106
|
end
|
@@ -24,11 +24,15 @@ module Trailblazer
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# @return [Adds] list of Adds instances that can be chained or added to an existing sequence.
|
27
|
-
def self.InitialAdds(
|
27
|
+
def self.InitialAdds(**options)
|
28
|
+
StartAdds(**options) + EndAdds(**options)
|
29
|
+
end
|
28
30
|
|
31
|
+
# TODO: make this nicer.
|
32
|
+
def self.StartAdds(track_color:, end_semantic:, start_outputs: {success: self.default_outputs[:success]}, **)
|
29
33
|
builder_options={ track_color: track_color, end_semantic: end_semantic }
|
30
34
|
|
31
|
-
|
35
|
+
adds(
|
32
36
|
Activity::Start.new(semantic: :default),
|
33
37
|
|
34
38
|
TaskPolarizations(builder_options),
|
@@ -39,20 +43,31 @@ module Trailblazer
|
|
39
43
|
magnetic_to: [],
|
40
44
|
plus_poles: PlusPoles.initial(start_outputs), # FIXME: this is actually redundant with Normalizer
|
41
45
|
)
|
46
|
+
end
|
42
47
|
|
43
|
-
|
44
|
-
|
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 }
|
45
58
|
|
46
|
-
|
59
|
+
adds(
|
60
|
+
track_end,
|
47
61
|
|
48
|
-
|
62
|
+
EndEventPolarizations(builder_options), # only sets :magnetic_to.
|
49
63
|
|
50
|
-
|
51
|
-
plus_poles: {},
|
52
|
-
magnetic_to: nil,
|
53
|
-
)
|
64
|
+
{}, { group: :end },
|
54
65
|
|
55
|
-
|
66
|
+
id: "End.#{track_color}",
|
67
|
+
plus_poles: {},
|
68
|
+
magnetic_to: nil,
|
69
|
+
)
|
70
|
+
end
|
56
71
|
end
|
57
72
|
|
58
73
|
def self.TaskPolarizations(track_color:, **)
|
@@ -42,23 +42,23 @@ module Trailblazer
|
|
42
42
|
def insert(strategy, polarizer, task, options, &block)
|
43
43
|
normalizer = options[:normalizer] || @normalizer # DISCUSS: do this at a deeper point?
|
44
44
|
|
45
|
-
task, local_options, connection_options, sequence_options = normalizer.(task, options)
|
45
|
+
task, local_options, connection_options, sequence_options, extension_options = normalizer.(task, options)
|
46
46
|
|
47
47
|
polarizations = strategy.send(polarizer, @builder_options) # Railway.StepPolarizations( @builder_options )
|
48
48
|
|
49
|
-
insert_element( polarizations, task, local_options, connection_options, sequence_options, &block )
|
49
|
+
insert_element( polarizations, task, local_options, connection_options, sequence_options, extension_options, &block )
|
50
50
|
end
|
51
51
|
|
52
52
|
private
|
53
53
|
|
54
54
|
# Internal top-level entry point to add task(s) and connections.
|
55
55
|
# High level interface for DSL calls like ::task or ::step.
|
56
|
-
def insert_element(polarizations, task, local_options, connection_options, sequence_options, &block)
|
57
|
-
adds, *returned_options = Builder.adds_for(polarizations, task, local_options, connection_options, sequence_options, &block)
|
56
|
+
def insert_element(polarizations, task, local_options, connection_options, sequence_options, extension_options, &block)
|
57
|
+
adds, *returned_options = Builder.adds_for(polarizations, task, local_options, connection_options, sequence_options, extension_options, &block)
|
58
58
|
end
|
59
59
|
|
60
60
|
# @return Adds
|
61
|
-
def self.adds_for(polarizations, task, local_options, connection_options, sequence_options, &block)
|
61
|
+
def self.adds_for(polarizations, task, local_options, connection_options, sequence_options, extension_options, &block)
|
62
62
|
# go through all wiring options such as Output()=>:color.
|
63
63
|
polarizations_from_user_options, additional_adds = process_dsl_options(connection_options, local_options, &block)
|
64
64
|
|
@@ -66,7 +66,7 @@ module Trailblazer
|
|
66
66
|
|
67
67
|
result = adds(task, polarizations, local_options, sequence_options, local_options)
|
68
68
|
|
69
|
-
return result + (local_options[:adds] || []) + additional_adds, task, local_options, connection_options, sequence_options
|
69
|
+
return result + (local_options[:adds] || []) + additional_adds, task, local_options, connection_options, sequence_options, extension_options
|
70
70
|
end
|
71
71
|
|
72
72
|
def self.process_dsl_options(options, id:nil, plus_poles:, **, &block)
|
@@ -34,7 +34,7 @@ module Trailblazer
|
|
34
34
|
def self.circuit_hash_to_process(circuit_hash)
|
35
35
|
end_events = end_events_for(circuit_hash)
|
36
36
|
|
37
|
-
return Circuit.new(circuit_hash, end_events), end_events
|
37
|
+
return Circuit.new(circuit_hash, end_events, start_task: circuit_hash.keys.first), end_events
|
38
38
|
end
|
39
39
|
|
40
40
|
# Find all end events that don't have outgoing connections.
|
@@ -55,11 +55,11 @@ module Trailblazer
|
|
55
55
|
Polarization.new( output: output, color: task.color )
|
56
56
|
]
|
57
57
|
else # ID: existing step
|
58
|
-
new_edge = "#{id}-#{output.signal}-#{task}"
|
58
|
+
new_edge = "#{id}-#{output.signal}-#{task}" # edge from <id> to <target>
|
59
59
|
|
60
60
|
[
|
61
61
|
Polarization.new( output: output, color: new_edge ),
|
62
|
-
[[ :magnetic_to, [ task, [new_edge] ] ]],
|
62
|
+
[[ :magnetic_to, [ task, [new_edge] ] ]], # mark target (`task`) as magnetic to the new edge.
|
63
63
|
]
|
64
64
|
end
|
65
65
|
end
|
@@ -12,7 +12,6 @@ module Trailblazer
|
|
12
12
|
builder_class: Magnetic::Builder::Path, # we use the Activity-based Normalizer
|
13
13
|
normalizer_class: Magnetic::Normalizer,
|
14
14
|
default_outputs: Magnetic::Builder::Path.default_outputs, # binary outputs
|
15
|
-
extension: [ Introspect.method(:add_introspection) ],
|
16
15
|
|
17
16
|
extend: [
|
18
17
|
# DSL.def_dsl(:task, Magnetic::Builder::Path, :PassPolarizations),
|
@@ -1,27 +1,52 @@
|
|
1
1
|
module Trailblazer
|
2
|
-
class Activity < Module
|
2
|
+
class Activity < Module
|
3
|
+
# Compile-time.
|
4
|
+
# Introspection is not used at run-time except for rendering diagrams, tracing, and the like.
|
3
5
|
module Introspect
|
4
|
-
|
5
|
-
|
6
|
-
circuit_options = circuit_options.merge( introspect: activity.debug )
|
7
|
-
|
8
|
-
return activity, [ options, flow_options ], circuit_options
|
6
|
+
def self.Graph(*args)
|
7
|
+
Graph.new(*args)
|
9
8
|
end
|
10
9
|
|
11
|
-
#
|
12
|
-
|
13
|
-
activity
|
14
|
-
|
10
|
+
# @private This API is still under construction.
|
11
|
+
class Graph
|
12
|
+
def initialize(activity)
|
13
|
+
@activity = activity
|
14
|
+
@circuit = activity.to_h[:circuit]
|
15
|
+
@adds = activity.to_h[:adds].compact # FIXME: why are there nils in Adds?
|
16
|
+
end
|
17
|
+
|
18
|
+
def find(id=nil, &block)
|
19
|
+
return find_by_id(id) unless block_given?
|
20
|
+
find_with_block(&block)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def find_by_id(id)
|
26
|
+
(_, (id, triplett)) = @adds.find { |(op, (_id, triplett))| _id == id }
|
27
|
+
|
28
|
+
Node(triplett[1], id, triplett[0])
|
29
|
+
end
|
30
|
+
|
31
|
+
def find_with_block(&block)
|
32
|
+
adds = @adds.find { |(op, (id, triplett))| yield( Node(triplett[1], id, triplett[0]) ) }
|
33
|
+
return nil unless adds
|
34
|
+
|
35
|
+
(op, (id, triplett)) = adds
|
15
36
|
|
37
|
+
Node(triplett[1], id, triplett[0])
|
38
|
+
end
|
16
39
|
|
17
|
-
|
18
|
-
|
19
|
-
|
40
|
+
def Node(*args)
|
41
|
+
Node.new(*args).freeze
|
42
|
+
end
|
20
43
|
|
21
|
-
|
44
|
+
Node = Struct.new(:task, :id, :magnetic_to)
|
22
45
|
end
|
23
46
|
|
24
47
|
|
48
|
+
# FIXME: remove this
|
49
|
+
# @private This will be removed shortly.
|
25
50
|
def self.collect(activity, options={}, &block)
|
26
51
|
circuit = activity.to_h[:circuit]
|
27
52
|
circuit_hash = circuit.to_h[:map]
|
@@ -17,7 +17,10 @@ module Trailblazer
|
|
17
17
|
stack.each do |captured, *returned|
|
18
18
|
task = captured.task
|
19
19
|
|
20
|
-
|
20
|
+
graph = Introspect::Graph(captured.activity)
|
21
|
+
|
22
|
+
name = (node = graph.find { |node| node[:task] == task }) ? node[:id] : task
|
23
|
+
name ||= task # FIXME: bullshit
|
21
24
|
|
22
25
|
if returned.size == 1 # flat
|
23
26
|
tree << [ level, name ]
|
@@ -18,8 +18,8 @@
|
|
18
18
|
@options = options.merge(semantic: semantic)
|
19
19
|
end
|
20
20
|
|
21
|
-
def call(
|
22
|
-
return self,
|
21
|
+
def call(args, circuit_options)
|
22
|
+
return self, args, circuit_options
|
23
23
|
end
|
24
24
|
|
25
25
|
def to_h
|
@@ -34,8 +34,8 @@
|
|
34
34
|
end
|
35
35
|
|
36
36
|
class Start < End
|
37
|
-
def call(
|
38
|
-
return Activity::Right,
|
37
|
+
def call(args, circuit_options)
|
38
|
+
return Activity::Right, args, circuit_options
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
@@ -8,7 +8,7 @@ class Trailblazer::Activity < Module
|
|
8
8
|
|
9
9
|
# Call the actual task we're wrapping here.
|
10
10
|
# puts "~~~~wrap.call: #{task}"
|
11
|
-
return_signal, return_args = task.(
|
11
|
+
return_signal, return_args = task.(*original_args)
|
12
12
|
|
13
13
|
# DISCUSS: do we want original_args here to be passed on, or the "effective" return_args which are different to original_args now?
|
14
14
|
wrap_ctx = wrap_ctx.merge( return_signal: return_signal, return_args: return_args )
|
@@ -11,7 +11,7 @@ module Trailblazer
|
|
11
11
|
# {:extension API}
|
12
12
|
def call(activity, task, local_options, *returned_options)
|
13
13
|
# we could make the default initial_activity injectable via the DSL, the value would sit in returned_options or local_options.
|
14
|
-
static_wrap = Activity::TaskWrap.wrap_static_for(task,
|
14
|
+
static_wrap = Activity::TaskWrap.wrap_static_for(task, activity: activity)
|
15
15
|
|
16
16
|
# # macro might want to apply changes to the static task_wrap (e.g. Inject)
|
17
17
|
new_wrap = Activity::Path::Plan.merge( static_wrap, @extension_plan )
|
@@ -9,7 +9,7 @@ class Trailblazer::Activity < Module
|
|
9
9
|
#
|
10
10
|
# @api private
|
11
11
|
# @interface Runner
|
12
|
-
def self.call(task, args,
|
12
|
+
def self.call(task, args, circuit_options)
|
13
13
|
wrap_ctx = { task: task }
|
14
14
|
|
15
15
|
# this activity is "wrapped around" the actual `task`.
|
@@ -18,9 +18,11 @@ class Trailblazer::Activity < Module
|
|
18
18
|
# We save all original args passed into this Runner.call, because we want to return them later after this wrap
|
19
19
|
# is finished.
|
20
20
|
original_args = [ args, circuit_options ]
|
21
|
+
|
21
22
|
# call the wrap {Activity} around the task.
|
22
23
|
wrap_end_signal, ( wrap_ctx, _ ) = task_wrap_activity.(
|
23
|
-
[ wrap_ctx, original_args ] # we omit circuit_options here on purpose, so the wrapping activity uses the default, plain Runner.
|
24
|
+
[ wrap_ctx, original_args ], # we omit circuit_options here on purpose, so the wrapping activity uses the default, plain Runner.
|
25
|
+
{}
|
24
26
|
)
|
25
27
|
|
26
28
|
# don't return the wrap's end signal, but the one from call_task.
|
@@ -37,7 +39,10 @@ class Trailblazer::Activity < Module
|
|
37
39
|
# unnecessary computations at `call`-time since steps might not even be executed.
|
38
40
|
# TODO: make this faster.
|
39
41
|
def self.merge_static_with_runtime(task, wrap_runtime:, **circuit_options)
|
40
|
-
wrap_activity = TaskWrap.wrap_static_for(
|
42
|
+
wrap_activity = TaskWrap.wrap_static_for(
|
43
|
+
task,
|
44
|
+
circuit_options
|
45
|
+
) # find static wrap for this specific task, or default wrap activity.
|
41
46
|
|
42
47
|
# Apply runtime alterations.
|
43
48
|
# Grab the additional wirings for the particular `task` from `wrap_runtime` (returns default otherwise).
|
@@ -45,7 +50,12 @@ class Trailblazer::Activity < Module
|
|
45
50
|
end
|
46
51
|
end # Runner
|
47
52
|
|
48
|
-
|
53
|
+
# Retrieve the static wrap config from {activity}.
|
54
|
+
# I do not like this part too much, I'd prefer computing the {:wrap_static} at compile-time for the entire
|
55
|
+
# object graph (including nesteds) and simply pass it through to all Runner calls.
|
56
|
+
# TODO: simplify that. See above
|
57
|
+
def self.wrap_static_for(task, activity:, default_activity: TaskWrap.initial_activity, **)
|
58
|
+
wrap_static = activity[:wrap_static] || {}
|
49
59
|
wrap_static[task] || default_activity
|
50
60
|
end
|
51
61
|
end
|
@@ -2,26 +2,42 @@ class Trailblazer::Activity < Module
|
|
2
2
|
module TaskWrap
|
3
3
|
# TaskWrap tasks for tracing.
|
4
4
|
module Trace
|
5
|
-
|
6
|
-
def self.capture_args((wrap_config, original_args), **circuit_options)
|
7
|
-
(original_options, original_flow_options), original_circuit_options = original_args
|
5
|
+
module_function
|
8
6
|
|
9
|
-
|
7
|
+
# taskWrap step to capture incoming arguments of a step.
|
8
|
+
# def self.capture_args(direction, options, flow_options, wrap_config, original_flow_options)
|
9
|
+
def capture_args((wrap_config, original_args), **circuit_options)
|
10
10
|
|
11
|
-
|
11
|
+
original_args = capture_for(wrap_config[:task], *original_args)
|
12
12
|
|
13
|
-
|
13
|
+
return Trailblazer::Activity::Right, [wrap_config, original_args], circuit_options
|
14
14
|
end
|
15
15
|
|
16
|
-
|
16
|
+
# taskWrap step to capture outgoing arguments from a step.
|
17
|
+
def capture_return((wrap_config, original_args), **circuit_options)
|
17
18
|
(original_options, original_flow_options, _) = original_args[0]
|
18
19
|
|
19
|
-
original_flow_options[:stack] << Trailblazer::Activity::Trace::Entity.new(
|
20
|
+
original_flow_options[:stack] << Trailblazer::Activity::Trace::Entity.new(
|
21
|
+
wrap_config[:task], {}, :return, wrap_config[:return_signal]
|
22
|
+
)
|
20
23
|
|
21
24
|
original_flow_options[:stack].unindent!
|
22
25
|
|
23
26
|
|
24
|
-
|
27
|
+
return Trailblazer::Activity::Right, [wrap_config, original_args], circuit_options
|
28
|
+
end
|
29
|
+
|
30
|
+
# It's important to understand that {flow[:stack]} is mutated by design. This is needed so
|
31
|
+
# in case of exceptions we still have a "global" trace - unfortunately Ruby doesn't allow
|
32
|
+
# us a better way.
|
33
|
+
def capture_for(task, (ctx, flow), activity:, **circuit_options)
|
34
|
+
flow[:stack].indent!
|
35
|
+
|
36
|
+
flow[:stack] << Trailblazer::Activity::Trace::Entity.new(
|
37
|
+
task, activity, :args, nil, {}
|
38
|
+
)
|
39
|
+
|
40
|
+
return [ctx, flow], circuit_options.merge(activity: activity)
|
25
41
|
end
|
26
42
|
end
|
27
43
|
end
|
@@ -24,29 +24,17 @@ module Trailblazer
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Compute runtime arguments necessary to execute a taskWrap per task of the activity.
|
27
|
-
def self.
|
27
|
+
def self.invoke(activity, args, wrap_runtime: {}, **circuit_options)
|
28
28
|
circuit_options = circuit_options.merge(
|
29
29
|
runner: TaskWrap::Runner,
|
30
|
-
wrap_runtime:
|
31
|
-
wrap_static: activity[:wrap_static] || {},
|
32
|
-
)
|
33
|
-
|
34
|
-
return activity, [ options, flow_options ], circuit_options
|
35
|
-
end
|
30
|
+
wrap_runtime: wrap_runtime,
|
36
31
|
|
37
|
-
|
38
|
-
|
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
|
-
)
|
32
|
+
activity: { adds: [], circuit: {} }, # for Runner
|
33
|
+
)
|
44
34
|
|
45
|
-
|
46
|
-
|
35
|
+
# signal, (ctx, flow), circuit_options =
|
36
|
+
Runner.(activity, args, circuit_options)
|
47
37
|
end
|
48
|
-
|
49
|
-
# better: MyClass < Activity(TaskWrap, ...)
|
50
|
-
end
|
38
|
+
end # TaskWrap
|
51
39
|
end
|
52
40
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# DISCUSS: move to trailblazer-activity-test ?
|
2
|
+
|
3
|
+
# Helpers to quickly create steps and tasks.
|
4
|
+
module Trailblazer::Activity::Testing
|
5
|
+
# Creates a module with one step method for each name.
|
6
|
+
#
|
7
|
+
# @example
|
8
|
+
# extend T.def_steps(:create, :save)
|
9
|
+
def self.def_steps(*names)
|
10
|
+
Module.new do
|
11
|
+
names.each do |name|
|
12
|
+
define_method(name) do | ctx, ** |
|
13
|
+
ctx[:seq] << name
|
14
|
+
ctx.key?(name) ? ctx[name] : true
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
# Creates a method instance with a task interface.
|
21
|
+
#
|
22
|
+
# @example
|
23
|
+
# task task: T.def_task(:create)
|
24
|
+
def self.def_task(name)
|
25
|
+
Module.new do
|
26
|
+
define_singleton_method(name) do | (ctx, flow_options), ** |
|
27
|
+
ctx[:seq] << name
|
28
|
+
return Trailblazer::Activity::Right, [ctx, flow_options]
|
29
|
+
end
|
30
|
+
end.method(name)
|
31
|
+
end
|
32
|
+
end
|
@@ -22,13 +22,10 @@ module Trailblazer
|
|
22
22
|
return activity, [ options, flow_options.merge(tracing_flow_options) ], circuit_options.merge(tracing_circuit_options)
|
23
23
|
end
|
24
24
|
|
25
|
-
def self.call(activity, (options, flow_options),
|
26
|
-
activity, (options, flow_options), circuit_options = Trace.arguments_for_call( activity, [options, flow_options],
|
25
|
+
def self.call(activity, (options, flow_options), circuit_options={})
|
26
|
+
activity, (options, flow_options), circuit_options = Trace.arguments_for_call( activity, [options, flow_options], circuit_options ) # only run once for the entire circuit!
|
27
27
|
last_signal, (options, flow_options) =
|
28
|
-
|
29
|
-
[options, flow_options],
|
30
|
-
circuit_options.merge({ argumenter: [ Introspect.method(:arguments_for_call), TaskWrap.method(:arguments_for_call) ] })
|
31
|
-
)
|
28
|
+
Activity::TaskWrap.invoke(activity, [options, flow_options], circuit_options)
|
32
29
|
|
33
30
|
return flow_options[:stack].to_a, last_signal, [options, flow_options]
|
34
31
|
end
|
@@ -48,7 +45,7 @@ module Trailblazer
|
|
48
45
|
end
|
49
46
|
end
|
50
47
|
|
51
|
-
Entity = Struct.new(:task, :type, :value, :value2
|
48
|
+
Entity = Struct.new(:task, :activity, :type, :value, :value2)
|
52
49
|
|
53
50
|
# Mutable/stateful per design. We want a (global) stack!
|
54
51
|
class Stack
|
data/lib/trailblazer/activity.rb
CHANGED
@@ -1,10 +1,4 @@
|
|
1
|
-
require "trailblazer/activity/version"
|
2
|
-
|
3
1
|
module Trailblazer
|
4
|
-
def self.Activity(implementation=Activity::Path, options={})
|
5
|
-
Activity.new(implementation, state)
|
6
|
-
end
|
7
|
-
|
8
2
|
class Activity < Module
|
9
3
|
attr_reader :initial_state
|
10
4
|
|
@@ -51,6 +45,12 @@ module Trailblazer
|
|
51
45
|
end
|
52
46
|
end
|
53
47
|
|
48
|
+
# Reader and writer method for DSL objects.
|
49
|
+
# The writer {dsl[:key] = "value"} exposes immutable behavior and will replace the old
|
50
|
+
# @state with a new, modified copy.
|
51
|
+
#
|
52
|
+
# Always use the DSL::Accessor accessors to avoid leaking state to other components
|
53
|
+
# due to mutable write operations.
|
54
54
|
module Accessor
|
55
55
|
def []=(*args)
|
56
56
|
@state = State::Config.send(:[]=, @state, *args)
|
@@ -81,12 +81,12 @@ module Trailblazer
|
|
81
81
|
require "trailblazer/activity/dsl/magnetic/merge"
|
82
82
|
include Magnetic::Merge # Activity#merge!
|
83
83
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
self[:circuit].( args, circuit_options.merge(argumenter: argumenter) )
|
84
|
+
# @private Note that {Activity.call} is considered private until the public API is stable.
|
85
|
+
def call(args, circuit_options={})
|
86
|
+
self[:circuit].( args, circuit_options.merge(activity: self) )
|
88
87
|
end
|
89
88
|
end
|
89
|
+
|
90
90
|
end # Activity
|
91
91
|
end
|
92
92
|
|
data/lib/trailblazer/circuit.rb
CHANGED
@@ -14,7 +14,7 @@ module Trailblazer
|
|
14
14
|
#
|
15
15
|
# This is the "pipeline operator"'s implementation.
|
16
16
|
class Circuit
|
17
|
-
def initialize(map, stop_events, name: nil
|
17
|
+
def initialize(map, stop_events, start_task:, name: nil)
|
18
18
|
@map = map
|
19
19
|
@stop_events = stop_events
|
20
20
|
@name = name
|
@@ -36,8 +36,9 @@ module Trailblazer
|
|
36
36
|
# @return [last_signal, options, flow_options, *args]
|
37
37
|
#
|
38
38
|
# NOTE: returned circuit_options are discarded when calling the runner.
|
39
|
-
def call(args,
|
39
|
+
def call(args, start_task: @start_task, runner: Run, **circuit_options)
|
40
40
|
circuit_options = circuit_options.merge( runner: runner ).freeze # TODO: set the :runner option via arguments_for_call to save the merge?
|
41
|
+
task = start_task
|
41
42
|
|
42
43
|
loop do
|
43
44
|
last_signal, args, _discarded_circuit_options = runner.(
|
@@ -49,35 +50,22 @@ module Trailblazer
|
|
49
50
|
# Stop execution of the circuit when we hit a stop event (< End). This could be an task's End or Suspend.
|
50
51
|
return [ last_signal, args ] if @stop_events.include?(task) # DISCUSS: return circuit_options here?
|
51
52
|
|
52
|
-
task = next_for(task, last_signal)
|
53
|
-
raise IllegalInputError.new("#{task}") unless in_map
|
54
|
-
raise IllegalOutputSignalError.new("<#{@name}>[#{task}][ #{last_signal.inspect} ]") unless next_task
|
55
|
-
end
|
53
|
+
task = next_for(task, last_signal) or raise IllegalSignalError.new("<#{@name}>[#{task}][ #{last_signal.inspect} ]")
|
56
54
|
end
|
57
55
|
end
|
58
56
|
|
59
57
|
# Returns the circuit's components.
|
60
58
|
def to_h
|
61
|
-
{ map: @map, end_events: @stop_events }
|
59
|
+
{ map: @map, end_events: @stop_events, start_task: @start_task }
|
62
60
|
end
|
63
61
|
|
64
62
|
private
|
65
|
-
def next_for(last_task,
|
66
|
-
|
67
|
-
|
68
|
-
cfg = @map.keys.find { |t| t == last_task } and in_map = true
|
69
|
-
cfg = @map[cfg] if cfg
|
70
|
-
cfg ||= {}
|
71
|
-
next_task = cfg[emitted_signal]
|
72
|
-
yield next_task, in_map
|
73
|
-
|
74
|
-
next_task
|
75
|
-
end
|
76
|
-
|
77
|
-
class IllegalInputError < RuntimeError
|
63
|
+
def next_for(last_task, signal)
|
64
|
+
outputs = @map[last_task]
|
65
|
+
outputs[signal]
|
78
66
|
end
|
79
67
|
|
80
|
-
class
|
68
|
+
class IllegalSignalError < RuntimeError
|
81
69
|
end
|
82
70
|
end
|
83
71
|
end
|
data/lib/trailblazer-activity.rb
CHANGED
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
|
+
version: 0.6.0
|
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-03
|
11
|
+
date: 2018-05-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: hirb
|
@@ -111,7 +111,6 @@ files:
|
|
111
111
|
- NOTES
|
112
112
|
- README.md
|
113
113
|
- Rakefile
|
114
|
-
- inspeccccccccct.rb
|
115
114
|
- lib/trailblazer-activity.rb
|
116
115
|
- lib/trailblazer/activity.rb
|
117
116
|
- lib/trailblazer/activity/config.rb
|
@@ -150,6 +149,7 @@ files:
|
|
150
149
|
- lib/trailblazer/activity/task_wrap/merge.rb
|
151
150
|
- lib/trailblazer/activity/task_wrap/runner.rb
|
152
151
|
- lib/trailblazer/activity/task_wrap/trace.rb
|
152
|
+
- lib/trailblazer/activity/testing.rb
|
153
153
|
- lib/trailblazer/activity/trace.rb
|
154
154
|
- lib/trailblazer/activity/version.rb
|
155
155
|
- lib/trailblazer/circuit.rb
|
data/inspeccccccccct.rb
DELETED
@@ -1,19 +0,0 @@
|
|
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
|
-
|