trailblazer-circuit 0.0.5 → 0.0.6
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/lib/trailblazer/circuit.rb +1 -1
- data/lib/trailblazer/circuit/trace.rb +12 -8
- data/lib/trailblazer/circuit/version.rb +1 -1
- data/lib/trailblazer/circuit/wrap.rb +107 -0
- metadata +4 -4
- data/lib/trailblazer/circuit/wrapped.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f5dc593717272d4f702fc5f2f9f0ba48481cfbad
|
4
|
+
data.tar.gz: 108fd37110388fb3d4d45f79787ab284e7434b3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 69bbd08cd6cba1c394bc5da24c4d1df1cf7cf6420a3a60c23caf085bd627d5460ffe9c965d7f703466b37f3756347b220c3f8d1fcbf6ddf06abab5b1b6dc220e
|
7
|
+
data.tar.gz: 1714df50a75d590b5ce04c914b1ab0ac6910bf583998551b577697367a22ca69d43d8e47ba8f5b8bb04bbc868c140f5d16bfc0cb7c3f9cd0dd2f3d178da1dd5b
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
# 0.0.6
|
2
|
+
|
3
|
+
* `Wrapped` is now `Wrap`. Also, a consistent `Alterations` interface allows tweaking here.
|
4
|
+
|
1
5
|
# 0.0.5
|
2
6
|
|
3
7
|
* The `Wrapped::Runner` now applies `Alterations` to each task's `Circuit`. This means you can inject `:task_alterations` into `Circuit#call`, which will then be merged into the task's original circuit, and then run. While this might sound like crazy talk, this allows any kind of external injection (tracing, input/output contracts, step dependency injections, ...) for specific or all tasks of any circuit.
|
data/lib/trailblazer/circuit.rb
CHANGED
@@ -123,6 +123,6 @@ require "trailblazer/circuit/task"
|
|
123
123
|
require "trailblazer/circuit/alter"
|
124
124
|
require "trailblazer/circuit/trace"
|
125
125
|
require "trailblazer/circuit/present"
|
126
|
-
require "trailblazer/circuit/
|
126
|
+
require "trailblazer/circuit/wrap"
|
127
127
|
|
128
128
|
require "trailblazer/context"
|
@@ -6,26 +6,30 @@ module Trailblazer
|
|
6
6
|
# stack, _ = Trailblazer::Circuit::Trace.(activity, activity[:Start], { id: 1 })
|
7
7
|
# puts Trailblazer::Circuit::Present.tree(stack) # renders the trail.
|
8
8
|
module Trace
|
9
|
-
def self.call(activity, direction, options, flow_options={})
|
9
|
+
def self.call(activity, direction, options, flow_options={}, &block)
|
10
10
|
tracing_flow_options = {
|
11
|
-
runner:
|
12
|
-
stack:
|
13
|
-
|
14
|
-
|
15
|
-
debug:
|
11
|
+
runner: Wrap::Runner,
|
12
|
+
stack: Trace::Stack.new,
|
13
|
+
wrap_runtime: Wrap::Alterations.new(default: Trace.Alterations),
|
14
|
+
wrap_static: Wrap::Alterations.new,
|
15
|
+
debug: {}, # usually set that in Activity::call.
|
16
16
|
}
|
17
17
|
|
18
|
-
direction, options, flow_options =
|
18
|
+
direction, options, flow_options = call_circuit( activity, direction, options, tracing_flow_options.merge(flow_options), &block )
|
19
19
|
|
20
20
|
return flow_options[:stack].to_a, direction, options, flow_options
|
21
21
|
end
|
22
22
|
|
23
23
|
# TODO: test alterations with any wrap_circuit.
|
24
|
+
def self.call_circuit(activity, *args, &block)
|
25
|
+
return activity.(*args) unless block
|
26
|
+
block.(activity, *args)
|
27
|
+
end
|
24
28
|
|
25
29
|
# Default tracing tasks to be plugged into the wrap circuit.
|
26
30
|
def self.Alterations
|
27
31
|
[
|
28
|
-
->(wrap_circuit) { Activity::Before( wrap_circuit,
|
32
|
+
->(wrap_circuit) { Activity::Before( wrap_circuit, Wrap::Call, Trace.method(:capture_args), direction: Right ) },
|
29
33
|
->(wrap_circuit) { Activity::Before( wrap_circuit, wrap_circuit[:End], Trace.method(:capture_return), direction: Right ) },
|
30
34
|
]
|
31
35
|
end
|
@@ -0,0 +1,107 @@
|
|
1
|
+
class Trailblazer::Circuit
|
2
|
+
module Wrap
|
3
|
+
# The runner is passed into Circuit#call( runner: Runner ) and is called for every task in the circuit.
|
4
|
+
# Its primary job is to actually `call` the task.
|
5
|
+
#
|
6
|
+
# Here, we extend this, and wrap the task `call` into its own pipeline, so we can add external behavior per task.
|
7
|
+
module Runner
|
8
|
+
NIL_WRAPS = "Please provide :wrap_static" # here for Ruby 2.0 compat.
|
9
|
+
NIL_ALTERATION = "Please provide :wrap_runtime" # here for Ruby 2.0 compat.
|
10
|
+
|
11
|
+
# @api private
|
12
|
+
def self.call(task, direction, options, wrap_static:raise(NIL_WRAPS), wrap_runtime:raise(NIL_ALTERATION), **flow_options)
|
13
|
+
task_wrap = apply_alterations(task, wrap_static, wrap_runtime)
|
14
|
+
|
15
|
+
wrap_config = { task: task }
|
16
|
+
|
17
|
+
# Call the task_wrap circuit:
|
18
|
+
# |-- Start
|
19
|
+
# |-- Trace.capture_args [optional]
|
20
|
+
# |-- Call (call actual task)
|
21
|
+
# |-- Trace.capture_return [optional]
|
22
|
+
# |-- End
|
23
|
+
# Pass empty flow_options to the task_wrap, so it doesn't infinite-loop.
|
24
|
+
task_wrap.( task_wrap[:Start], options, {}, wrap_config, flow_options.merge( wrap_static: wrap_static, wrap_runtime: wrap_runtime) )
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
# Compute the task's wrap by applying alterations both static and from runtime.
|
30
|
+
def self.apply_alterations(task, wrap_static, wrap_runtime, default_wrap=Activity)
|
31
|
+
task_wrap = wrap_static.(task, Activity) # find static wrap for this specific task, Activity is the default wrap.
|
32
|
+
task_wrap = wrap_runtime.(task, task_wrap) # apply runtime alterations.
|
33
|
+
end
|
34
|
+
end # Runner
|
35
|
+
|
36
|
+
# The call_task method implements one default step `Call` in the Wrap::Activity circuit.
|
37
|
+
# It calls the actual, wrapped task.
|
38
|
+
def self.call_task(direction, options, flow_options, wrap_config, original_flow_options)
|
39
|
+
task = wrap_config[:task]
|
40
|
+
|
41
|
+
# Call the actual task we're wrapping here.
|
42
|
+
wrap_config[:result_direction], options, flow_options = task.( direction, options, original_flow_options )
|
43
|
+
|
44
|
+
[ direction, options, flow_options, wrap_config, original_flow_options ]
|
45
|
+
end
|
46
|
+
|
47
|
+
Call = method(:call_task)
|
48
|
+
|
49
|
+
class End < Trailblazer::Circuit::End
|
50
|
+
def call(direction, options, flow_options, wrap_config, *args)
|
51
|
+
[ wrap_config[:result_direction], options, flow_options ] # note how we don't return the appended internal args.
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
# Wrap::Activity is the actual circuit that implements the Task wrap. This circuit is
|
56
|
+
# also known as `task_wrap`.
|
57
|
+
#
|
58
|
+
# Example with tracing:
|
59
|
+
#
|
60
|
+
# |-- Start
|
61
|
+
# |-- Trace.capture_args [optional]
|
62
|
+
# |-- Call (call actual task)
|
63
|
+
# |-- Trace.capture_return [optional]
|
64
|
+
# |-- End
|
65
|
+
Activity = Trailblazer::Circuit::Activity({ id: "task.wrap" }, end: { default: End.new(:default) }) do |act|
|
66
|
+
{
|
67
|
+
act[:Start] => { Right => Call }, # see Wrap::call_task
|
68
|
+
Call => { Right => act[:End] },
|
69
|
+
}
|
70
|
+
end # Activity
|
71
|
+
|
72
|
+
# Alterations#call finds alterations for `task` and applies them to `task_wrap`.
|
73
|
+
# Each alteration receives the result of the former one, starting with `task_wrap`.
|
74
|
+
#
|
75
|
+
# This is used to add tracing steps, input/output contracts, and more at runtime,
|
76
|
+
# or to maintain specific static task_wraps, as for each step in an operation.
|
77
|
+
#
|
78
|
+
# Note that an alteration doesn't have to respect its `task_wrap` and can simply return
|
79
|
+
# an arbitrary Circuit.
|
80
|
+
#
|
81
|
+
# === DESIGN
|
82
|
+
# By moving the "default" decision to this object, you can control what task gets wrapped
|
83
|
+
# with what wrap, allowing you to only wrap "focussed" tasks, for example.
|
84
|
+
#
|
85
|
+
# It also allows to inject, say, a tracing alteration that is only applied to a specific task
|
86
|
+
# and returns all others unchanged.
|
87
|
+
class Alterations
|
88
|
+
PassThrough = ->(task_wrap) { task_wrap }
|
89
|
+
|
90
|
+
def initialize(map: {}, default: [ PassThrough ])
|
91
|
+
@default_alterations, @map = default, map
|
92
|
+
end
|
93
|
+
|
94
|
+
# @returns Circuit
|
95
|
+
def call(task, target_wrap)
|
96
|
+
get(task). # list of alterations.
|
97
|
+
inject(target_wrap) { |circuit, alteration| alteration.(circuit) }
|
98
|
+
end
|
99
|
+
|
100
|
+
private
|
101
|
+
|
102
|
+
def get(task)
|
103
|
+
@map[task] || @default_alterations
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: trailblazer-circuit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nick Sutterer
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-06-
|
11
|
+
date: 2017-06-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -103,7 +103,7 @@ files:
|
|
103
103
|
- lib/trailblazer/circuit/testing.rb
|
104
104
|
- lib/trailblazer/circuit/trace.rb
|
105
105
|
- lib/trailblazer/circuit/version.rb
|
106
|
-
- lib/trailblazer/circuit/
|
106
|
+
- lib/trailblazer/circuit/wrap.rb
|
107
107
|
- lib/trailblazer/context.rb
|
108
108
|
- trailblazer-circuit.gemspec
|
109
109
|
homepage: http://trailblazer.to/gems/workflow
|
@@ -125,7 +125,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
125
|
version: '0'
|
126
126
|
requirements: []
|
127
127
|
rubyforge_project:
|
128
|
-
rubygems_version: 2.
|
128
|
+
rubygems_version: 2.6.8
|
129
129
|
signing_key:
|
130
130
|
specification_version: 4
|
131
131
|
summary: BPMN-compliant workflows or state machines.
|
@@ -1,72 +0,0 @@
|
|
1
|
-
class Trailblazer::Circuit
|
2
|
-
# Lingo: task_wrap
|
3
|
-
module Activity::Wrapped
|
4
|
-
# The runner is passed into Circuit#call( runner: Runner ) and is called for every task in the circuit.
|
5
|
-
# Its primary job is to actually `call` the task.
|
6
|
-
#
|
7
|
-
# Here, we extend this, and wrap the task `call` into its own pipeline, so we can add external behavior per task.
|
8
|
-
class Runner
|
9
|
-
# private flow_options[ :task_wraps ] # DISCUSS: move to separate arg?
|
10
|
-
# @api private
|
11
|
-
def self.call(task, direction, options, task_wraps:raise, wrap_alterations:{}, **flow_options)
|
12
|
-
# TODO: test this decider!
|
13
|
-
task_wrap = task_wraps[task] || raise("test me!")
|
14
|
-
task_wrap = wrap_alterations.(task, task_wrap)
|
15
|
-
|
16
|
-
wrap_config = { task: task }
|
17
|
-
|
18
|
-
# Call the task_wrap circuit:
|
19
|
-
# |-- Start
|
20
|
-
# |-- Trace.capture_args [optional]
|
21
|
-
# |-- Call (call actual task)
|
22
|
-
# |-- Trace.capture_return [optional]
|
23
|
-
# |-- End
|
24
|
-
# Pass empty flow_options to the task_wrap, so it doesn't infinite-loop.
|
25
|
-
task_wrap.( task_wrap[:Start], options, {}, wrap_config, flow_options.merge( task_wraps: task_wraps, wrap_alterations: wrap_alterations) )
|
26
|
-
end
|
27
|
-
end # Runner
|
28
|
-
|
29
|
-
class Wraps
|
30
|
-
def initialize(default, hash={})
|
31
|
-
@default, @hash = default, hash
|
32
|
-
end
|
33
|
-
|
34
|
-
def [](task)
|
35
|
-
@hash.fetch(task) { @default }
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
class Alterations < Wraps
|
40
|
-
# Find alterations for `task` and apply them to `task_wrap`.
|
41
|
-
# This usually means that tracing steps/tasks are added, input/output contracts added, etc.
|
42
|
-
def call(task, task_wrap)
|
43
|
-
self[task].
|
44
|
-
inject(task_wrap) { |circuit, alteration| alteration.(circuit) }
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def self.call_activity(direction, options, flow_options, wrap_config, original_flow_options)
|
49
|
-
task = wrap_config[:task]
|
50
|
-
|
51
|
-
# Call the actual task we're wrapping here.
|
52
|
-
wrap_config[:result_direction], options, flow_options = task.( direction, options, original_flow_options )
|
53
|
-
|
54
|
-
[ direction, options, flow_options, wrap_config, original_flow_options ]
|
55
|
-
end
|
56
|
-
|
57
|
-
Call = method(:call_activity)
|
58
|
-
|
59
|
-
class End < Trailblazer::Circuit::End
|
60
|
-
def call(direction, options, flow_options, wrap_config, *args)
|
61
|
-
[ wrap_config[:result_direction], options, flow_options ] # note how we don't return the appended internal args.
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
Activity = Trailblazer::Circuit::Activity({ id: "task.wrap" }, end: { default: End.new(:default) }) do |act|
|
66
|
-
{
|
67
|
-
act[:Start] => { Right => Call }, # options from outside
|
68
|
-
Call => { Right => act[:End] },
|
69
|
-
}
|
70
|
-
end # Activity
|
71
|
-
end
|
72
|
-
end
|