trailblazer-operation 0.0.13 → 0.1.1
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/.travis.yml +5 -3
- data/CHANGES.md +44 -0
- data/Gemfile +13 -2
- data/Rakefile +8 -6
- data/lib/trailblazer/operation.rb +86 -12
- data/lib/trailblazer/operation/deprecated_macro.rb +19 -0
- data/lib/trailblazer/operation/inject.rb +34 -0
- data/lib/trailblazer/operation/inspect.rb +80 -0
- data/lib/trailblazer/operation/public_call.rb +62 -0
- data/lib/trailblazer/operation/railway.rb +32 -0
- data/lib/trailblazer/operation/railway/fast_track.rb +13 -0
- data/lib/trailblazer/operation/railway/normalizer.rb +73 -0
- data/lib/trailblazer/operation/railway/task_builder.rb +44 -0
- data/lib/trailblazer/operation/result.rb +6 -4
- data/lib/trailblazer/operation/skill.rb +8 -24
- data/lib/trailblazer/operation/task_wrap.rb +68 -0
- data/lib/trailblazer/operation/trace.rb +49 -0
- data/lib/trailblazer/operation/variable_mapping.rb +91 -0
- data/lib/trailblazer/operation/version.rb +1 -1
- data/test/call_test.rb +27 -8
- data/test/class_dependencies_test.rb +16 -0
- data/test/docs/doormat_test.rb +189 -0
- data/test/docs/wiring_test.rb +421 -0
- data/test/dry_container_test.rb +4 -0
- data/test/fast_track_test.rb +197 -0
- data/test/gemfiles/Gemfile.ruby-2.0 +1 -2
- data/test/gemfiles/Gemfile.ruby-2.0.lock +40 -0
- data/test/inheritance_test.rb +1 -1
- data/test/inspect_test.rb +43 -0
- data/test/introspect_test.rb +50 -0
- data/test/macro_test.rb +61 -0
- data/test/operation_test.rb +94 -0
- data/test/result_test.rb +14 -8
- data/test/ruby-2.0.0/operation_test.rb +73 -0
- data/test/ruby-2.0.0/step_test.rb +136 -0
- data/test/skill_test.rb +66 -48
- data/test/step_test.rb +228 -0
- data/test/task_wrap_test.rb +91 -0
- data/test/test_helper.rb +37 -0
- data/test/trace_test.rb +62 -0
- data/test/variable_mapping_test.rb +66 -0
- data/test/wire_test.rb +113 -0
- data/test/wiring/defaults_test.rb +197 -0
- data/test/wiring/subprocess_test.rb +70 -0
- data/trailblazer-operation.gemspec +3 -5
- metadata +62 -36
- data/lib/trailblazer/operation/1.9.3/option.rb +0 -36
- data/lib/trailblazer/operation/generic.rb +0 -12
- data/lib/trailblazer/operation/option.rb +0 -54
- data/lib/trailblazer/operation/pipetree.rb +0 -142
- data/lib/trailblazer/skill.rb +0 -70
- data/test/2.0.0-pipetree_test.rb +0 -100
- data/test/2.1.0-pipetree_test.rb +0 -100
- data/test/operation_skill_test.rb +0 -89
- data/test/pipetree_test.rb +0 -185
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e11de8247c38298cb548d31fb21ca138949204da
|
4
|
+
data.tar.gz: fd3a2a39355bc6e064d174e098d542f69e8f0fbc
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b65963cfacea4a758ee64ede04d7c67a6e84433503d0278ebf8e163509205c1a75360fad353a76a271eb2392f5bdeecba66faebe6d78438b6c9b9d1eda36834
|
7
|
+
data.tar.gz: e8edfcc04c39863635ee3123e90c9ea1a024240b61b54ea3356906a687c62a4929041949dad345f9e214ef104b4a6060d655d4461ecff637966d73c495e676a5
|
data/.travis.yml
CHANGED
@@ -3,13 +3,15 @@ before_install:
|
|
3
3
|
- gem install bundler
|
4
4
|
matrix:
|
5
5
|
include:
|
6
|
-
- rvm: 1.9.3
|
7
|
-
gemfile: "test/gemfiles/Gemfile.ruby-1.9"
|
8
6
|
# - rvm: 2.0.0
|
9
7
|
# gemfile: "test/gemfiles/Gemfile.ruby-2.0"
|
10
8
|
- rvm: 2.1
|
11
9
|
gemfile: Gemfile
|
12
10
|
- rvm: 2.2.4
|
13
11
|
gemfile: Gemfile
|
14
|
-
- rvm: 2.3.
|
12
|
+
- rvm: 2.3.3
|
15
13
|
gemfile: Gemfile
|
14
|
+
- rvm: 2.4.0
|
15
|
+
gemfile: Gemfile
|
16
|
+
- rvm: jruby-9.1.13.0
|
17
|
+
env: JRUBY_OPTS="--profile.api"
|
data/CHANGES.md
CHANGED
@@ -1,3 +1,47 @@
|
|
1
|
+
TODO:
|
2
|
+
* api to add your own task.
|
3
|
+
|
4
|
+
lots of work on the DSL specific parts.
|
5
|
+
Graph and Sequence to make it easier to wire anything.
|
6
|
+
macros can now add/modify the wiring, e.g. their end to the our end or the next task.
|
7
|
+
[ use circuit for actual step_args/initialize process, too? ]
|
8
|
+
You can now add an unlimited number of "your own" end events, which can then be interpreted on the outside (e.g. Endpoint)
|
9
|
+
* Introduced the `fast_track: true` option for steps. If you were returning `Railway.fail_fast!` and the like, you now need to declare that option, e.g.
|
10
|
+
|
11
|
+
```ruby
|
12
|
+
step :my_validate!, fast_track: true
|
13
|
+
```
|
14
|
+
|
15
|
+
params:, rest: ..
|
16
|
+
|
17
|
+
## 0.1.0
|
18
|
+
|
19
|
+
inspect: failure is << and success is >>
|
20
|
+
|
21
|
+
call vs __call__: it's now designed to be run in a composition where the skills stuff is done only once, and the reslt object is not necessary
|
22
|
+
|
23
|
+
FastTrack optional
|
24
|
+
Wrapped optional
|
25
|
+
|
26
|
+
* Add `pass` and `fail` as four-character aliases for `success` and `failure`.
|
27
|
+
* Remove `Uber::Callable` requirement and treat all non-`:symbol` steps as callable objects.
|
28
|
+
* Remove non-kw options for steps. All steps receive keyword args now:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
def model(options)
|
32
|
+
```
|
33
|
+
|
34
|
+
now must have a minimal signature as follows.
|
35
|
+
|
36
|
+
```ruby
|
37
|
+
def model(options, **)
|
38
|
+
```
|
39
|
+
* Remove `Operation#[]` and `Operation#[]=`. Please only change state in `options`.
|
40
|
+
* API change for `step Macro()`: the macro's return value is now called with the low-level "Task API" signature `(direction, options, flow_options)`. You need to return `[direction, options, flow_options]`. There's a soft-deprecation warning.
|
41
|
+
* Remove support for Ruby 1.9.3 for now. This can be re-introduced on demand.
|
42
|
+
* Remove `pipetree` in favor of [`trailblazer-circuit`](https://github.com/trailblazer/trailblazer-circuit). This allows rich workflows and state machines in an operation.
|
43
|
+
* Remove `uber` dependency.
|
44
|
+
|
1
45
|
## 0.0.13
|
2
46
|
|
3
47
|
* Rename `Operation::New` to `:Instantiate` to avoid name clashes with `New` operations in applications.
|
data/Gemfile
CHANGED
@@ -9,5 +9,16 @@ gem "dry-auto_inject"
|
|
9
9
|
|
10
10
|
gem "minitest-line"
|
11
11
|
gem "benchmark-ips"
|
12
|
-
|
13
|
-
# gem "
|
12
|
+
|
13
|
+
# gem "trailblazer-circuit", git: "https://github.com/trailblazer/trailblazer-circuit"
|
14
|
+
# gem "trailblazer-activity", path: "../trailblazer-activity"
|
15
|
+
# gem "trailblazer-developer", path: "../developer"
|
16
|
+
gem "trailblazer-developer", git: "https://github.com/trailblazer/trailblazer-developer"
|
17
|
+
# gem "representable", path: "../representable"
|
18
|
+
|
19
|
+
# gem "raise", path: "../raise"
|
20
|
+
|
21
|
+
# gem "declarative", path: "../declarative"
|
22
|
+
|
23
|
+
gem "trailblazer-activity", path: "../circuit"
|
24
|
+
# gem "trailblazer-activity", git: "https://github.com/trailblazer/trailblazer-activity"
|
data/Rakefile
CHANGED
@@ -4,15 +4,17 @@ require "rake/testtask"
|
|
4
4
|
task :default => [:test]
|
5
5
|
|
6
6
|
Rake::TestTask.new(:test) do |test|
|
7
|
-
test.libs <<
|
7
|
+
test.libs << "test"
|
8
8
|
test.verbose = true
|
9
9
|
|
10
|
-
test_files = FileList[
|
10
|
+
test_files = FileList["test/**/*_test.rb"]
|
11
11
|
|
12
|
-
if
|
13
|
-
test_files = test_files - %w{test/dry_container_test.rb test/2.1.0-pipetree_test.rb
|
14
|
-
|
15
|
-
test_files = test_files - %w{test/
|
12
|
+
if RUBY_VERSION == "2.0.0"
|
13
|
+
# test_files = test_files - %w{test/dry_container_test.rb test/2.1.0-pipetree_test.rb}
|
14
|
+
test_files = test_files - %w{test/step_test.rb} + %w{test/ruby-2.0.0/step_test.rb}
|
15
|
+
test_files = test_files - %w{test/operation_test.rb} + %w{test/ruby-2.0.0/operation_test.rb}
|
16
|
+
else
|
17
|
+
test_files -= FileList["test/ruby-2.0.0/*"]
|
16
18
|
end
|
17
19
|
|
18
20
|
test.test_files = test_files
|
@@ -1,24 +1,98 @@
|
|
1
1
|
require "forwardable"
|
2
|
-
|
2
|
+
|
3
|
+
# trailblazer-context
|
4
|
+
require "trailblazer/option"
|
5
|
+
require "trailblazer/context"
|
6
|
+
require "trailblazer/container_chain"
|
7
|
+
|
8
|
+
require "trailblazer/activity"
|
9
|
+
require "trailblazer/activity/magnetic"
|
10
|
+
require "trailblazer/activity/wrap"
|
11
|
+
|
12
|
+
require "trailblazer/operation/variable_mapping"
|
13
|
+
|
14
|
+
require "trailblazer/operation/public_call" # TODO: Remove in 3.0.
|
3
15
|
require "trailblazer/operation/skill"
|
4
|
-
require "trailblazer/operation/
|
5
|
-
require "trailblazer/operation/
|
16
|
+
require "trailblazer/operation/deprecated_macro" # TODO: remove in 2.2.
|
17
|
+
require "trailblazer/operation/result"
|
18
|
+
require "trailblazer/operation/railway"
|
19
|
+
|
20
|
+
require "trailblazer/operation/railway/task_builder"
|
21
|
+
require "trailblazer/operation/railway/fast_track"
|
22
|
+
require "trailblazer/operation/railway/normalizer"
|
23
|
+
require "trailblazer/operation/task_wrap"
|
24
|
+
require "trailblazer/operation/trace"
|
6
25
|
|
7
26
|
module Trailblazer
|
8
27
|
# The Trailblazer-style operation.
|
9
28
|
# Note that you don't have to use our "opinionated" version with result object, skills, etc.
|
10
29
|
class Operation
|
11
|
-
extend
|
12
|
-
|
30
|
+
extend Skill::Accessors # ::[] and ::[]= # TODO: fade out this usage.
|
31
|
+
|
32
|
+
def self.inherited(subclass)
|
33
|
+
super
|
34
|
+
subclass.initialize!
|
35
|
+
heritage.(subclass)
|
36
|
+
end
|
37
|
+
|
38
|
+
module Process
|
39
|
+
def initialize!
|
40
|
+
initialize_activity_dsl!
|
41
|
+
recompile_process!
|
42
|
+
end
|
43
|
+
|
44
|
+
# builder is stateless, it's up to you to save @adds somewhere.
|
45
|
+
def initialize_activity_dsl!
|
46
|
+
builder_options = {
|
47
|
+
track_end: Railway::End::Success.new(:success, semantic: :success),
|
48
|
+
failure_end: Railway::End::Failure.new(:failure, semantic: :failure),
|
49
|
+
pass_fast_end: Railway::End::PassFast.new(:pass_fast, semantic: :pass_fast),
|
50
|
+
fail_fast_end: Railway::End::FailFast.new(:fail_fast, semantic: :fail_fast),
|
51
|
+
}
|
52
|
+
|
53
|
+
@builder, @adds = Activity::Magnetic::Builder::FastTrack.for( Railway::Normalizer, builder_options )
|
54
|
+
@debug = {}
|
55
|
+
end
|
13
56
|
|
14
|
-
|
57
|
+
def recompile_process!
|
58
|
+
@process, @outputs = Activity::Recompile.( @adds )
|
59
|
+
end
|
15
60
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
extend Skill::Call::Positional # ::call(params, options)
|
61
|
+
def outputs
|
62
|
+
@outputs
|
63
|
+
end
|
20
64
|
|
21
|
-
|
22
|
-
|
65
|
+
include Activity::Interface
|
66
|
+
|
67
|
+
# Call the actual {Process} with the options prepared in PublicCall.
|
68
|
+
def __call__(args, circuit_options={})
|
69
|
+
@process.( args, circuit_options.merge( exec_context: new ) )
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
extend Process # make ::call etc. class methods on Operation.
|
74
|
+
|
75
|
+
extend Activity::Heritage::Accessor
|
76
|
+
|
77
|
+
extend Activity::DSL # #_task
|
78
|
+
# delegate step, pass and fail via Operation::_task to the @builder, and save results in @adds.
|
79
|
+
extend Activity::DSL.def_dsl! :step
|
80
|
+
extend Activity::DSL.def_dsl! :pass
|
81
|
+
extend Activity::DSL.def_dsl! :fail
|
82
|
+
class << self
|
83
|
+
alias_method :success, :pass
|
84
|
+
alias_method :failure, :fail
|
85
|
+
|
86
|
+
extend Forwardable # TODO: test those helpers
|
87
|
+
def_delegators :@builder, :Path, :Output, :End #, :task
|
88
|
+
end
|
89
|
+
|
90
|
+
extend PublicCall # ::call(params, { current_user: .. })
|
91
|
+
extend Trace # ::trace
|
92
|
+
|
93
|
+
|
94
|
+
include Railway::TaskWrap
|
23
95
|
end
|
24
96
|
end
|
97
|
+
|
98
|
+
require "trailblazer/operation/inspect"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# TODO: REMOVE IN 2.2.
|
2
|
+
module Trailblazer
|
3
|
+
module Operation::DeprecatedMacro
|
4
|
+
# Allows old macros with the `(input, options)` signature.
|
5
|
+
def self.call(proc, options={})
|
6
|
+
warn %{[Trailblazer] Macros with API (input, options) are deprecated. Please use the "Task API" signature (options, flow_options) or use a simpler Callable. (#{proc})}
|
7
|
+
|
8
|
+
wrapped_proc = ->( (options, flow_options), **circuit_options ) do
|
9
|
+
result = proc.(circuit_options[:exec_context], options) # run the macro, with the deprecated signature.
|
10
|
+
|
11
|
+
direction = Operation::Railway::TaskBuilder.binary_direction_for(result, Activity::Right, Activity::Left)
|
12
|
+
|
13
|
+
return direction, [options, flow_options]
|
14
|
+
end
|
15
|
+
|
16
|
+
return wrapped_proc, options
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
module Operation::Wrap
|
3
|
+
module Inject
|
4
|
+
# Returns an Alteration wirings that, when applied, inserts the {ReverseMergeDefaults} task
|
5
|
+
# before the {Wrap::Call} task. This is meant for macros and steps that accept a dependency
|
6
|
+
# injection but need a default parameter to be set if not injected.
|
7
|
+
# @returns ADDS
|
8
|
+
def self.Defaults(default_dependencies)
|
9
|
+
Activity::Magnetic::Builder::Path.plan do
|
10
|
+
task ReverseMergeDefaults.new( default_dependencies ),
|
11
|
+
id: "ReverseMergeDefaults#{default_dependencies}",
|
12
|
+
before: "task_wrap.call_task"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
# @api private
|
17
|
+
# @returns Task
|
18
|
+
# @param Hash list of key/value that should be set if not already assigned/set before (or injected from the outside).
|
19
|
+
class ReverseMergeDefaults
|
20
|
+
def initialize(defaults)
|
21
|
+
@defaults = defaults
|
22
|
+
end
|
23
|
+
|
24
|
+
def call((wrap_ctx, original_args), **circuit_options)
|
25
|
+
ctx = original_args[0][0]
|
26
|
+
|
27
|
+
@defaults.each { |k, v| ctx[k] ||= v }
|
28
|
+
|
29
|
+
return Activity::Right, [ wrap_ctx, original_args ]
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end # Inject
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
# Operation-specific circuit rendering. This is optimized for a linear railway circuit.
|
3
|
+
#
|
4
|
+
# @private
|
5
|
+
#
|
6
|
+
# NOTE: this is absolutely to be considered as prototyping and acts more like a test helper ATM as
|
7
|
+
# Inspect is not a mission-critical part.
|
8
|
+
class Operation
|
9
|
+
def self.introspect(*args)
|
10
|
+
Operation::Inspect.(*args)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
module Operation::Inspect
|
15
|
+
module_function
|
16
|
+
|
17
|
+
def call(operation, options={ style: :line })
|
18
|
+
# TODO: better introspection API.
|
19
|
+
|
20
|
+
adds = operation.instance_variable_get(:@adds)
|
21
|
+
alterations = Activity::Magnetic::Builder::Finalizer.adds_to_alterations(adds)
|
22
|
+
# DISCUSS: any other way to retrieve the Alterations?
|
23
|
+
|
24
|
+
# pp alterations
|
25
|
+
railway = alterations.instance_variable_get(:@groups).instance_variable_get(:@groups)[:main]
|
26
|
+
|
27
|
+
rows = railway.each_with_index.collect do |element, i|
|
28
|
+
magnetic_to, task, plus_poles = element.configuration
|
29
|
+
|
30
|
+
created_by =
|
31
|
+
if magnetic_to == [:failure]
|
32
|
+
:fail
|
33
|
+
elsif plus_poles.size > 1
|
34
|
+
plus_poles[0].color == plus_poles[1].color ? :pass : :step
|
35
|
+
else
|
36
|
+
:pass # this is wrong for Nested, sometimes
|
37
|
+
end
|
38
|
+
|
39
|
+
[ i, [ created_by, element.id ] ]
|
40
|
+
end
|
41
|
+
|
42
|
+
return inspect_line(rows) if options[:style] == :line
|
43
|
+
return inspect_rows(rows)
|
44
|
+
end
|
45
|
+
|
46
|
+
def inspect_func(step)
|
47
|
+
@inspect[step]
|
48
|
+
end
|
49
|
+
|
50
|
+
Operator = { :fail => "<<", :pass => ">>", :step => ">"}
|
51
|
+
|
52
|
+
def inspect_line(names)
|
53
|
+
string = names.collect { |i, (end_of_edge, name)| "#{Operator[end_of_edge]}#{name}" }.join(",")
|
54
|
+
"[#{string}]"
|
55
|
+
end
|
56
|
+
|
57
|
+
def inspect_rows(names)
|
58
|
+
string = names.collect do |i, (end_of_edge, name)|
|
59
|
+
operator = Operator[end_of_edge]
|
60
|
+
|
61
|
+
op = "#{operator}#{name}"
|
62
|
+
padding = 38
|
63
|
+
|
64
|
+
proc = if operator == "<<"
|
65
|
+
sprintf("%- #{padding}s", op)
|
66
|
+
elsif [">", ">>", "&"].include?(operator.to_s)
|
67
|
+
sprintf("% #{padding}s", op)
|
68
|
+
else
|
69
|
+
pad = " " * ((padding - op.length) / 2)
|
70
|
+
"#{pad}#{op}#{pad}"
|
71
|
+
end
|
72
|
+
|
73
|
+
proc = proc.gsub(" ", "=")
|
74
|
+
|
75
|
+
sprintf("%2d %s", i, proc)
|
76
|
+
end.join("\n")
|
77
|
+
"\n#{string}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
class Trailblazer::Operation
|
2
|
+
module PublicCall
|
3
|
+
# This is the outer-most public `call` method that gets invoked when calling `Create.()`.
|
4
|
+
# The signature of this is `params, options, *containers`. This was a mistake, as the
|
5
|
+
# first argument could've been part of `options` hash in the first place.
|
6
|
+
#
|
7
|
+
# Create.(params, runtime_data, *containers)
|
8
|
+
# #=> Result<Context...>
|
9
|
+
#
|
10
|
+
# In workflows/Nested compositions, this method is not used anymore and it might probably
|
11
|
+
# get removed in future versions of TRB. Currently, we use Operation::__call__ as an alternative.
|
12
|
+
#
|
13
|
+
# @return Operation::Railway::Result binary result object
|
14
|
+
def call(*args)
|
15
|
+
ctx = PublicCall.options_for_public_call(*args)
|
16
|
+
|
17
|
+
# call the activity.
|
18
|
+
last_signal, (options, flow_options) = __call__( [ctx, {}] ) # Railway::call # DISCUSS: this could be ::call_with_context.
|
19
|
+
|
20
|
+
# Result is successful if the activity ended with an End event derived from Railway::End::Success.
|
21
|
+
Railway::Result(last_signal, options, flow_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
private
|
25
|
+
# Compile a Context object to be passed into the Activity::call.
|
26
|
+
def self.options_for_public_call(options={}, *containers)
|
27
|
+
# options, *containers = Deprecations.accept_positional_options(params, options, *containers) # TODO: make this optional for "power users".
|
28
|
+
|
29
|
+
# generate the skill hash that embraces runtime options plus potential containers, the so called Runtime options.
|
30
|
+
# This wrapping is supposed to happen once in the entire system.
|
31
|
+
|
32
|
+
hash_transformer = ->(containers) { containers[0].to_hash } # FIXME: don't transform any containers into kw args.
|
33
|
+
|
34
|
+
immutable_options = Trailblazer::Context::ContainerChain.new( [options, *containers], to_hash: hash_transformer ) # Runtime options, immutable.
|
35
|
+
|
36
|
+
ctx = Trailblazer::Context(immutable_options)
|
37
|
+
end
|
38
|
+
|
39
|
+
module Deprecations
|
40
|
+
# Merge the first argument to the public Create.() into the second.
|
41
|
+
#
|
42
|
+
# DISCUSS: this is experimental since we can never know whether the call is the old or new API.
|
43
|
+
#
|
44
|
+
# The following situations are _not_ covered here:
|
45
|
+
# * You're using a Hash instance as a container.
|
46
|
+
# * You're using more than one container.
|
47
|
+
#
|
48
|
+
# If you do so (we're assuming you know what you're doing then), please update your `call`s.
|
49
|
+
def self.accept_positional_options( *args )
|
50
|
+
if args.size == 1 && args[0].instance_of?(Hash) # new style, you're doing it right.
|
51
|
+
args
|
52
|
+
elsif args.size == 2 && args[0].instance_of?(Hash) && !args[1].instance_of?(Hash) # new style with container, you're doing it right.
|
53
|
+
args
|
54
|
+
else
|
55
|
+
warn "[Trailblazer] Passing two positional arguments to `Operation.( params, current_user: .. )` is deprecated. Please use one hash like `Operation.( params: params, current_user: .. )`"
|
56
|
+
params, options, *containers = args
|
57
|
+
[ options.merge("params" => params), *containers ]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Trailblazer
|
2
|
+
# Operations is simply a thin API to define, inherit and run circuits by passing the options object.
|
3
|
+
# It encourages the linear railway style (http://trb.to/gems/workflow/circuit.html#operation) but can
|
4
|
+
# easily be extend for more complex workflows.
|
5
|
+
class Operation
|
6
|
+
# End event: All subclasses of End:::Success are interpreted as "success".
|
7
|
+
module Railway
|
8
|
+
# @param options Context
|
9
|
+
# @param end_event The last emitted signal in a circuit is usually the end event.
|
10
|
+
def self.Result(end_event, options, *)
|
11
|
+
Result.new(end_event.kind_of?(End::Success), options, end_event)
|
12
|
+
end
|
13
|
+
|
14
|
+
# The Railway::Result knows about its binary state, the context (data), and the last event in the circuit.
|
15
|
+
class Result < Result # Operation::Result
|
16
|
+
def initialize(success, data, event)
|
17
|
+
super(success, data)
|
18
|
+
|
19
|
+
@event = event
|
20
|
+
end
|
21
|
+
|
22
|
+
attr_reader :event
|
23
|
+
end
|
24
|
+
|
25
|
+
module End
|
26
|
+
class Success < Activity::End; end
|
27
|
+
class Failure < Activity::End; end
|
28
|
+
end
|
29
|
+
|
30
|
+
end # Railway
|
31
|
+
end
|
32
|
+
end
|