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 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