trailblazer-circuit 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d3c9b6666028fb2423dace64b0d84dfd67427e3a
4
- data.tar.gz: a2ec4fb343197e3c512a0a0bb1c1a924ecdbee57
3
+ metadata.gz: f5dc593717272d4f702fc5f2f9f0ba48481cfbad
4
+ data.tar.gz: 108fd37110388fb3d4d45f79787ab284e7434b3a
5
5
  SHA512:
6
- metadata.gz: 72059d24e47902a25d385fd8103907bec6bcdccfbf1bccc443779c2b9d9390bd37c9cced154089aff1741f8974d586350e615ee98a422e32bd89957dc2974cf6
7
- data.tar.gz: 5a9312bd96dafe6e8675a17c0b8f6c6f32504a15437f48ade8f2131f8c0178ba458456f3102b03d62e1beab93bc08c56c7e7abafdd6c30ab4707e0fcf5bb91c8
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.
@@ -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/wrapped"
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: Activity::Wrapped::Runner,
12
- stack: Trace::Stack.new,
13
- wrap_alterations: Activity::Wrapped::Alterations.new(Trace.Alterations),
14
- task_wraps: Activity::Wrapped::Wraps.new(Activity::Wrapped::Activity),
15
- debug: {}, # TODO: set that in Activity::call?
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 = activity.( direction, options, tracing_flow_options.merge(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, Activity::Wrapped::Call, Trace.method(:capture_args), direction: Right ) },
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
@@ -1,5 +1,5 @@
1
1
  module Trailblazer
2
2
  class Circuit
3
- VERSION = "0.0.5"
3
+ VERSION = "0.0.6"
4
4
  end
5
5
  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.5
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-07 00:00:00.000000000 Z
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/wrapped.rb
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.5.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