trailblazer-operation 0.1.3 → 0.2.0

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
- SHA1:
3
- metadata.gz: 2f371c58b3c8fcd88c0c12a5e764be7a807c83c2
4
- data.tar.gz: 67e41d4d0b7e0480a5948b45a2b53b4f56170ba9
2
+ SHA256:
3
+ metadata.gz: aa73a58eaa839d57774f73fe429398d0902e0e60e1bc3544f47762a773708140
4
+ data.tar.gz: b6ceaf6448980129f728fcbad8914558d4556517c20f0a65ff1bbcfa4f70340b
5
5
  SHA512:
6
- metadata.gz: '00591cd8d45d48b909d03042e486ac14496c0156455ec89222e7a68b059e12c4398b38e6a6265e4e971f4735d9cd2e4f675d2a73749a2baf3fca9bc42680841d'
7
- data.tar.gz: f4aefde8d80cd7f822fbccf3ef9e513650db0f5caafc21cda3041e9fe6a9d220ea43eae000390933cf2d9546e04e5fc7d90dd41f5e72ae6d664c67701fb938ab
6
+ metadata.gz: 6d98db1f3a941c4547f0145148c3675c7892f535cbd90f7f30d722abfdb8b657979f21c2d383f7d656e064619738a250341538eddf6fb0d8d066131cb75433de
7
+ data.tar.gz: dda3c25bc10b64892344f5cdbf9ae3329dc10354f41b8b9907a383714dda6542c8607bc278b04a1e039687045a32b3cf30c58a8f0a15298bc60339c13569bd90
data/CHANGES.md CHANGED
@@ -14,6 +14,14 @@ lots of work on the DSL specific parts.
14
14
 
15
15
  params:, rest: ..
16
16
 
17
+ ## 0.2.0
18
+
19
+ * Cleanly separate `Activity` and `Operation` responsibilities. An operation is nothing more but a class around an activity, hosting instance methods and implementing inheritance.
20
+
21
+ ## 0.1.4
22
+
23
+ * `TaskWrap.arguments_for_call` now returns the correct `circuit_options` where the `:runner` etc.'s already merged.
24
+
17
25
  ## 0.1.3
18
26
 
19
27
  * New taskWrap API for `activity` 0.3.2.
data/Gemfile CHANGED
@@ -13,12 +13,12 @@ gem "benchmark-ips"
13
13
  # gem "trailblazer-circuit", git: "https://github.com/trailblazer/trailblazer-circuit"
14
14
  # gem "trailblazer-activity", path: "../trailblazer-activity"
15
15
  # gem "trailblazer-developer", path: "../developer"
16
- gem "trailblazer-developer", git: "https://github.com/trailblazer/trailblazer-developer"
16
+ # gem "trailblazer-developer", git: "https://github.com/trailblazer/trailblazer-developer"
17
17
  # gem "representable", path: "../representable"
18
18
 
19
19
  # gem "raise", path: "../raise"
20
20
 
21
21
  # gem "declarative", path: "../declarative"
22
22
 
23
- gem "trailblazer-activity", path: "../trailblazer-circuit"
23
+ # gem "trailblazer-activity", path: "../circuit"
24
24
  # gem "trailblazer-activity", git: "https://github.com/trailblazer/trailblazer-activity"
@@ -7,20 +7,19 @@ require "trailblazer/container_chain"
7
7
 
8
8
  require "trailblazer/activity"
9
9
  require "trailblazer/activity/magnetic"
10
- require "trailblazer/activity/wrap"
10
+
11
11
 
12
12
  require "trailblazer/operation/variable_mapping"
13
13
 
14
+ require "trailblazer/operation/heritage"
14
15
  require "trailblazer/operation/public_call" # TODO: Remove in 3.0.
15
16
  require "trailblazer/operation/skill"
16
17
  require "trailblazer/operation/deprecated_macro" # TODO: remove in 2.2.
17
18
  require "trailblazer/operation/result"
18
19
  require "trailblazer/operation/railway"
19
20
 
20
- require "trailblazer/operation/railway/task_builder"
21
21
  require "trailblazer/operation/railway/fast_track"
22
22
  require "trailblazer/operation/railway/normalizer"
23
- require "trailblazer/operation/task_wrap"
24
23
  require "trailblazer/operation/trace"
25
24
 
26
25
  require "trailblazer/operation/railway/macaroni"
@@ -29,6 +28,18 @@ module Trailblazer
29
28
  # The Trailblazer-style operation.
30
29
  # Note that you don't have to use our "opinionated" version with result object, skills, etc.
31
30
  class Operation
31
+
32
+ module FastTrackActivity
33
+ builder_options = {
34
+ track_end: Railway::End::Success.new(:success, semantic: :success),
35
+ failure_end: Railway::End::Failure.new(:failure, semantic: :failure),
36
+ pass_fast_end: Railway::End::PassFast.new(:pass_fast, semantic: :pass_fast),
37
+ fail_fast_end: Railway::End::FailFast.new(:fail_fast, semantic: :fail_fast),
38
+ }
39
+
40
+ extend Activity::FastTrack( pipeline: Railway::Normalizer::Pipeline, builder_options: builder_options )
41
+ end
42
+
32
43
  extend Skill::Accessors # ::[] and ::[]= # TODO: fade out this usage.
33
44
 
34
45
  def self.inherited(subclass)
@@ -37,69 +48,54 @@ module Trailblazer
37
48
  heritage.(subclass)
38
49
  end
39
50
 
40
- module Process
41
- def initialize!
42
- initialize_activity_dsl!
43
- recompile_process!
44
- end
45
-
46
- # builder is stateless, it's up to you to save @adds somewhere.
47
- def initialize_activity_dsl!
48
- builder_options = {
49
- track_end: Railway::End::Success.new(:success, semantic: :success),
50
- failure_end: Railway::End::Failure.new(:failure, semantic: :failure),
51
- pass_fast_end: Railway::End::PassFast.new(:pass_fast, semantic: :pass_fast),
52
- fail_fast_end: Railway::End::FailFast.new(:fail_fast, semantic: :fail_fast),
53
- }
54
-
55
- @builder, @adds = Activity::Magnetic::Builder::FastTrack.for( build_normalizer.freeze, builder_options )
56
- @debug = {}
57
- end
58
-
59
- def recompile_process!
60
- @process, @outputs = Activity::Recompile.( @adds )
61
- end
51
+ def self.initialize!
52
+ @activity = FastTrackActivity.clone
53
+ end
62
54
 
63
- def outputs
64
- @outputs
65
- end
66
55
 
67
- include Activity::Interface
56
+ extend Activity::Interface
68
57
 
58
+ module Process
69
59
  # Call the actual {Process} with the options prepared in PublicCall.
70
- def __call__(args, circuit_options={})
71
- @process.( args, circuit_options.merge( exec_context: new ) )
60
+ #
61
+ # @private
62
+ def __call__(args, argumenter: [], **circuit_options)
63
+ @activity.( args, circuit_options.merge(
64
+ exec_context: new,
65
+ argumenter: argumenter + [ Activity::TaskWrap.method(:arguments_for_call) ], # FIXME: should we move this outside?
66
+ )
67
+ )
72
68
  end
73
69
 
74
- private
75
-
76
- def build_normalizer
77
- Railway::Normalizer.new
70
+ def decompose
71
+ @activity.decompose.merge( activity: @activity )
78
72
  end
79
73
  end
80
74
 
81
75
  extend Process # make ::call etc. class methods on Operation.
82
76
 
83
- extend Activity::Heritage::Accessor
77
+ extend Heritage::Accessor
84
78
 
85
- extend Activity::DSL # #_task
86
- # delegate step, pass and fail via Operation::_task to the @builder, and save results in @adds.
87
- extend Activity::DSL.def_dsl! :step
88
- extend Activity::DSL.def_dsl! :pass
89
- extend Activity::DSL.def_dsl! :fail
90
79
  class << self
80
+ extend Forwardable # TODO: test those helpers
81
+ def_delegators :@activity, :Path, :Output, :End
82
+ def_delegators :@activity, :outputs, :debug
83
+
84
+ def step(task, options={}, &block); add_task!(:step, task, options, &block) end
85
+ def pass(task, options={}, &block); add_task!(:pass, task, options, &block) end
86
+ def fail(task, options={}, &block); add_task!(:fail, task, options, &block) end
87
+
91
88
  alias_method :success, :pass
92
89
  alias_method :failure, :fail
93
90
 
94
- extend Forwardable # TODO: test those helpers
95
- def_delegators :@builder, :Path, :Output, :End #, :task
91
+ def add_task!(name, task, options, &block)
92
+ heritage.record(name, task, options, &block)
93
+ @activity.send(name, task, options, &block)
94
+ end
96
95
  end
97
96
 
98
97
  extend PublicCall # ::call(params, { current_user: .. })
99
98
  extend Trace # ::trace
100
-
101
-
102
- include Railway::TaskWrap
103
99
  end
104
100
  end
105
101
 
@@ -2,18 +2,18 @@
2
2
  module Trailblazer
3
3
  module Operation::DeprecatedMacro
4
4
  # Allows old macros with the `(input, options)` signature.
5
- def self.call(proc, options={})
5
+ def self.call(proc, options)
6
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
7
 
8
8
  wrapped_proc = ->( (options, flow_options), **circuit_options ) do
9
9
  result = proc.(circuit_options[:exec_context], options) # run the macro, with the deprecated signature.
10
10
 
11
- direction = Operation::Railway::TaskBuilder.binary_direction_for(result, Activity::Right, Activity::Left)
11
+ direction = Activity::TaskBuilder::Binary.binary_direction_for(result, Activity::Right, Activity::Left)
12
12
 
13
13
  return direction, [options, flow_options]
14
14
  end
15
15
 
16
- return wrapped_proc, options
16
+ options.merge( task: wrapped_proc )
17
17
  end
18
18
  end
19
19
  end
@@ -0,0 +1,30 @@
1
+ module Trailblazer
2
+ # This is copied from the Declarative gem. This might get removed in favor of a real heritage gem.
3
+ class Operation
4
+ class Heritage < Array
5
+ # Record inheritable assignments for replay in an inheriting class.
6
+ def record(method, *args, &block)
7
+ self << { method: method, args: args, block: block }
8
+ end
9
+
10
+ # Replay the recorded assignments on inheritor.
11
+ # Accepts a block that will allow processing the arguments for every recorded statement.
12
+ def call(inheritor, &block)
13
+ each { |cfg| call!(inheritor, cfg, &block) }
14
+ end
15
+
16
+ private
17
+ def call!(inheritor, cfg)
18
+ yield cfg if block_given? # allow messing around with recorded arguments.
19
+
20
+ inheritor.send(cfg[:method], *cfg[:args], &cfg[:block])
21
+ end
22
+
23
+ module Accessor
24
+ def heritage
25
+ @heritage ||= Heritage.new
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -6,7 +6,9 @@ module Trailblazer
6
6
  # injection but need a default parameter to be set if not injected.
7
7
  # @returns ADDS
8
8
  def self.Defaults(default_dependencies)
9
- Activity::Magnetic::Builder::Path.plan do
9
+ Module.new do
10
+ extend Activity::Path::Plan()
11
+
10
12
  task ReverseMergeDefaults.new( default_dependencies ),
11
13
  id: "ReverseMergeDefaults#{default_dependencies}",
12
14
  before: "task_wrap.call_task"
@@ -17,8 +17,7 @@ module Trailblazer
17
17
  def call(operation, options={ style: :line })
18
18
  # TODO: better introspection API.
19
19
 
20
- adds = operation.instance_variable_get(:@adds)
21
- alterations = Activity::Magnetic::Builder::Finalizer.adds_to_alterations(adds)
20
+ alterations = Activity::Magnetic::Builder::Finalizer.adds_to_alterations(operation.decompose[:adds])
22
21
  # DISCUSS: any other way to retrieve the Alterations?
23
22
 
24
23
  # pp alterations
@@ -10,6 +10,8 @@ class Trailblazer::Operation
10
10
  # In workflows/Nested compositions, this method is not used anymore and it might probably
11
11
  # get removed in future versions of TRB. Currently, we use Operation::__call__ as an alternative.
12
12
  #
13
+ #
14
+ # @note Do not override this method as it will be removed in future versions. Also, you will break tracing.
13
15
  # @return Operation::Railway::Result binary result object
14
16
  def call(*args)
15
17
  ctx = PublicCall.options_for_public_call(*args)
@@ -21,11 +23,9 @@ class Trailblazer::Operation
21
23
  Railway::Result(last_signal, options, flow_options)
22
24
  end
23
25
 
24
- private
25
26
  # Compile a Context object to be passed into the Activity::call.
27
+ # @private
26
28
  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
29
  # generate the skill hash that embraces runtime options plus potential containers, the so called Runtime options.
30
30
  # This wrapping is supposed to happen once in the entire system.
31
31
 
@@ -35,28 +35,5 @@ class Trailblazer::Operation
35
35
 
36
36
  ctx = Trailblazer::Context(immutable_options)
37
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
38
  end
62
39
  end
@@ -7,7 +7,7 @@ module Trailblazer
7
7
  # def my_step( params:, options:, ** )
8
8
  module Macaroni
9
9
  def self.call(user_proc)
10
- Task.new( Trailblazer::Option.build( Macaroni::Option, user_proc ), user_proc )
10
+ Activity::TaskBuilder::Task.new( Trailblazer::Option.build( Macaroni::Option, user_proc ), user_proc )
11
11
  end
12
12
 
13
13
  class Option < Trailblazer::Option
@@ -5,73 +5,54 @@ module Trailblazer
5
5
  # task via {TaskBuilder} in order to translate true/false to `Right` or `Left`.
6
6
  #
7
7
  # The Normalizer sits in the `@builder`, which receives all DSL calls from the Operation subclass.
8
- class Normalizer
9
- def initialize(task_builder: TaskBuilder, **options)
10
- @task_builder = task_builder
11
- end
12
-
13
- def call(task, options, unknown_options, sequence_options)
14
- wrapped_task, options =
15
- if task.is_a?(::Hash) # macro.
16
- [
17
- task[:task],
18
- task.merge(options) # Note that the user options are merged over the macro options.
19
- ]
20
- elsif task.is_a?(Array) # TODO remove in 2.2
21
- Operation::DeprecatedMacro.( *task )
22
- else # user step
23
- [
24
- @task_builder.(task),
25
- { id: task }.merge(options) # default :id
26
- ]
27
- end
28
-
29
- options, unknown_options = deprecate_name(options, unknown_options) # TODO remove in 2.2
8
+ module Normalizer
9
+ Pipeline = Activity::Magnetic::Normalizer::Pipeline.clone
30
10
 
31
- raise "No :id given for #{wrapped_task}" unless options[:id]
11
+ Pipeline.module_eval do
12
+ # Handle the :override option which is specific to Operation.
13
+ def self.override(ctx, task:, options:, sequence_options:, **)
14
+ options, locals = Activity::Magnetic::Options.normalize(options, [:override])
15
+ sequence_options = sequence_options.merge( replace: options[:id] ) if locals[:override]
32
16
 
33
- options = defaultize(task, options) # :plus_poles
34
-
35
-
36
- options, locals, sequence_options = override(task, options, sequence_options) # :override
17
+ ctx[:options], ctx[:sequence_options] = options, sequence_options
18
+ end
37
19
 
38
- return wrapped_task, options, unknown_options, sequence_options
39
- end
20
+ # TODO remove in 2.2
21
+ def self.deprecate_macro_with_two_args(ctx, task:, **)
22
+ return true unless task.is_a?(Array) # TODO remove in 2.2
40
23
 
41
- # Merge user options over defaults.
42
- def defaultize(task, options)
43
- {
44
- plus_poles: InitialPlusPoles(),
45
- }.merge(options)
46
- end
24
+ ctx[:options] = Operation::DeprecatedMacro.( *task )
25
+ end
47
26
 
48
- # Handle the :override option which is specific to Operation.
49
- def override(task, options, sequence_options)
50
- options, locals = Activity::Magnetic::Builder.normalize(options, [:override])
51
- sequence_options = sequence_options.merge( replace: options[:id] ) if locals[:override]
27
+ # TODO remove in 2.2
28
+ def self.deprecate_name(ctx, local_options:, connection_options:, **)
29
+ connection_options, deprecated_options = Activity::Magnetic::Options.normalize(connection_options, [:name])
30
+ local_options, _deprecated_options = Activity::Magnetic::Options.normalize(local_options, [:name])
52
31
 
53
- return options, locals, sequence_options
54
- end
32
+ deprecated_options = deprecated_options.merge(_deprecated_options)
55
33
 
56
- def InitialPlusPoles
57
- Activity::Magnetic::DSL::PlusPoles.new.merge(
58
- Activity.Output(Activity::Right, :success) => nil,
59
- Activity.Output(Activity::Left, :failure) => nil,
60
- )
61
- end
34
+ local_options = local_options.merge( name: deprecated_options[:name] ) if deprecated_options[:name]
62
35
 
63
- def deprecate_name(options, unknown_options) # TODO remove in 2.2
64
- unknown_options, deprecated_options = Activity::Magnetic::Builder.normalize(unknown_options, [:name])
36
+ local_options, locals = Activity::Magnetic::Options.normalize(local_options, [:name])
37
+ if locals[:name]
38
+ warn "[Trailblazer] The :name option for #step, #success and #failure has been renamed to :id."
39
+ local_options = local_options.merge(id: locals[:name])
40
+ end
65
41
 
66
- options = options.merge( name: deprecated_options[:name] ) if deprecated_options[:name]
42
+ ctx[:local_options], ctx[:connection_options] = local_options, connection_options
43
+ end
67
44
 
68
- options, locals = Activity::Magnetic::Builder.normalize(options, [:name])
69
- if locals[:name]
70
- warn "[Trailblazer] The :name option for #step, #success and #failure has been renamed to :id."
71
- options = options.merge(id: locals[:name])
45
+ def self.raise_on_missing_id(ctx, local_options:, **)
46
+ raise "No :id given for #{local_options[:task]}" unless local_options[:id]
47
+ true
72
48
  end
73
- return options, unknown_options
49
+
50
+ # add more normalization tasks to the existing Magnetic::Normalizer::Pipeline
51
+ task Activity::TaskBuilder::Binary.( method(:deprecate_macro_with_two_args) ), before: "split_options"
52
+ task Activity::TaskBuilder::Binary.( method(:deprecate_name) )
53
+ task Activity::TaskBuilder::Binary.( method(:override) )
54
+ task Activity::TaskBuilder::Binary.( method(:raise_on_missing_id) )
74
55
  end
75
- end
56
+ end # Normalizer
76
57
  end
77
58
  end
@@ -20,7 +20,6 @@ module Trailblazer
20
20
  def initialize(task, user_proc)
21
21
  @task = task
22
22
  @user_proc = user_proc
23
-
24
23
  freeze
25
24
  end
26
25
 
@@ -1,21 +1,25 @@
1
1
  module Trailblazer
2
2
  class Operation
3
3
  module Trace
4
+ # @note The problem in this method is, we have redundancy with Operation::PublicCall
4
5
  def self.call(operation, *args)
5
- ctx = PublicCall.send(:options_for_public_call, *args)
6
+ ctx = PublicCall.options_for_public_call(*args) # redundant with PublicCall::call.
6
7
 
7
- # let Activity::Trace::call handle all parameters, just make sure it calls Operation.__call__
8
- call_block = ->(operation, *args) { operation.__call__(*args) }
8
+ # Prepare the tracing-specific arguments. This is only run once for the entire circuit!
9
+ operation, (options, flow_options), circuit_options = Trailblazer::Activity::Trace.arguments_for_call( operation, [ctx, {}], {} )
9
10
 
10
- stack, direction, options, flow_options = Activity::Trace.(
11
- operation,
12
- ctx,
13
- &call_block # instructs Trace to use __call__.
14
- )
11
+ circuit_options = circuit_options.merge({ argumenter: [ Trailblazer::Activity::Introspect.method(:arguments_for_call) ] }) # this is called for every Activity.
15
12
 
16
- result = Railway::Result(direction, options)
17
13
 
18
- Result.new(result, stack)
14
+ last_signal, (options, flow_options) =
15
+ operation.__call__( # FIXME: this is the only problem.
16
+ [options, flow_options],
17
+ circuit_options
18
+ )
19
+
20
+ result = Railway::Result(last_signal, options) # redundant with PublicCall::call.
21
+
22
+ Result.new(result, flow_options[:stack].to_a)
19
23
  end
20
24
 
21
25
  # `Operation::trace` is included for simple tracing of the flow.
@@ -37,7 +41,7 @@ module Trailblazer
37
41
  end
38
42
 
39
43
  def wtf
40
- Activity::Trace::Present.tree(@stack)
44
+ Trailblazer::Activity::Trace::Present.tree(@stack)
41
45
  end
42
46
 
43
47
  def wtf?
@@ -1,5 +1,5 @@
1
- class Trailblazer::Activity
2
- module Wrap
1
+ class Trailblazer::Activity < Module
2
+ module TaskWrap
3
3
  # TaskWrap step to compute the incoming {Context} for the wrapped task.
4
4
  # This allows renaming, filtering, hiding, of the options passed into the wrapped task.
5
5
  #
@@ -1,5 +1,5 @@
1
1
  module Trailblazer
2
2
  class Operation
3
- VERSION = "0.1.3"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
@@ -10,7 +10,7 @@ class MacaroniTaskBuilderTest < Minitest::Spec
10
10
  #:create
11
11
  class Memo::Create < Trailblazer::Operation
12
12
  #~ign
13
- Normalizer = Railway::Normalizer.new( task_builder: Railway::KwSignature )
13
+ Normalizer, _ = Trailblazer::Activity::Magnetic::Normalizer.build( task_builder: Railway::KwSignature, pipeline: Railway::Normalizer::Pipeline )
14
14
 
15
15
  step :create_model, normalizer: Normalizer
16
16
  step :save, normalizer: Normalizer
@@ -471,3 +471,89 @@ class WiringsDocCustomConnectionTest < Minitest::Spec
471
471
  result.inspect(:new?, :upload, :validate, :validation_error, :index).must_equal %{<Result:false [true, true, false, true, nil] >}
472
472
  end
473
473
  end
474
+
475
+ class WiringsDocDeciderTest < Minitest::Spec
476
+ Memo = Class.new(WiringDocsTest::Memo)
477
+
478
+ #:decider
479
+ class Memo::Upsert < Trailblazer::Operation
480
+ step :find_model, Output(:failure) => :create_route
481
+ step :update
482
+ step :create, magnetic_to: [:create_route]
483
+ step :save
484
+ #~decm
485
+ def find_model(options, id:nil, **)
486
+ options[:model] = Memo.find(id)
487
+ end
488
+
489
+ def find_model(options, id:, **)
490
+ options[:find_model] = id
491
+ end
492
+ def update(options, **)
493
+ options[:update] = true
494
+ end
495
+ def create(options, **)
496
+ options[:create] = true
497
+ end
498
+ def save(options, **)
499
+ options[:save] = true
500
+ end
501
+ #~decm end
502
+ end
503
+ #:decider end
504
+
505
+ it "goes the create route" do
506
+ Memo::Upsert.( id: false ).inspect(:find_model, :update, :create, :save).must_equal %{<Result:true [false, nil, true, true] >}
507
+ end
508
+
509
+ it "goes the update route" do
510
+ Memo::Upsert.( id: true ).inspect(:find_model, :update, :create, :save).must_equal %{<Result:true [true, true, nil, true] >}
511
+ end
512
+ end
513
+
514
+ class WiringsDocEndTest < Minitest::Spec
515
+ Memo = Class.new(WiringDocsTest::Memo)
516
+
517
+ #:end
518
+ class Memo::Update < Trailblazer::Operation
519
+ step :find_model, Output(:failure) => End("End.model_not_found", :model_not_found)
520
+ step :update
521
+ fail :db_error
522
+ step :save
523
+ #~methods
524
+ def find_model(options, id:nil, **)
525
+ options[:model] = Memo.find(id)
526
+ end
527
+
528
+ def find_model(options, id:, **)
529
+ options[:find_model] = id
530
+ end
531
+ def update(options, update: true, **)
532
+ options[:update] = update
533
+ end
534
+ def db_error(options, **)
535
+ options[:db_error] = 1
536
+ end
537
+ def save(options, **)
538
+ options[:save] = true
539
+ end
540
+ #~methods end
541
+ end
542
+ #:end end
543
+
544
+ it "goes success path" do
545
+ Memo::Update.( id: true ).inspect(:find_model, :update, :save, :db_error).must_equal %{<Result:true [true, true, true, nil] >}
546
+ end
547
+
548
+ it "errors out on End.model_not_found" do
549
+ result = Memo::Update.( id: false )
550
+ result.inspect(:find_model, :update, :save, :db_error).must_equal %{<Result:false [false, nil, nil, nil] >}
551
+ result.event.instance_variable_get(:@options).must_equal(semantic: :model_not_found)
552
+ end
553
+
554
+ it "takes normal error track" do
555
+ result = Memo::Update.( id: true, update: false )
556
+ result.inspect(:find_model, :update, :save, :db_error).must_equal %{<Result:false [true, false, nil, 1] >}
557
+ result.event.instance_variable_get(:@options).must_equal(semantic: :failure)
558
+ end
559
+ end
@@ -183,7 +183,7 @@ class NestedFastTrackTest < Minitest::Spec
183
183
  end
184
184
 
185
185
  # it { puts Trailblazer::Activity::Introspect.Cct(update.instance_variable_get(:@process)) }
186
- it { puts Trailblazer::Activity::Magnetic::Introspect.seq( update ) }
186
+ it { update.decompose[0] }
187
187
  # Edit returns End.success
188
188
  it { update.(edit_return: true).inspect("a", "b", "f").must_equal %{<Result:true [1, 2, nil] >} }
189
189
  # Edit returns End.failure
@@ -25,6 +25,7 @@ class IntrospectTest < Minitest::Spec
25
25
 
26
26
  describe "#collect" do
27
27
  it "iterates over each task element in the top activity" do
28
+ skip
28
29
  all_tasks = Activity::Introspect.collect(activity) do |task, connections|
29
30
  task
30
31
  end
@@ -59,15 +59,3 @@ class DeclarativeApiTest < Minitest::Spec
59
59
  it { Update.(decide: true).inspect("a", "b", "c").must_equal %{<Result:true [false, true, nil] >} }
60
60
  it { Update.(decide: false).inspect("a", "b", "c").must_equal %{<Result:false [false, false, true] >} }
61
61
  end
62
-
63
-
64
- =begin
65
- module MiniTest::Assertions
66
- def assert_inspect(text, subject)
67
- circuit, _ = subject.values
68
- map, _ = circuit.to_fields
69
- map.inspect.gsub(/0x.+?lambda\)/, "").gsub("Trailblazer::Circuit::", "").gsub("AlterTest::", "").must_equal(text)
70
- end
71
- end
72
- Trailblazer::Circuit::Activity.infect_an_assertion :assert_inspect, :must_inspect
73
- =end
@@ -15,14 +15,17 @@ class TaskWrapTest < Minitest::Spec
15
15
  task: MyMacro,
16
16
  id: "MyMacro",
17
17
 
18
- runner_options: {
19
- merge: Trailblazer::Activity::Magnetic::Builder::Path.plan do
20
- task Trailblazer::Operation::Wrap::Inject::ReverseMergeDefaults.new( contract: "MyDefaultContract" ),
21
- id: "inject.my_default",
22
- before: "task_wrap.call_task"
23
- end
24
- }
25
-
18
+ extension: [
19
+ Trailblazer::Activity::TaskWrap::Merge.new(
20
+ Module.new do
21
+ extend Trailblazer::Activity::Path::Plan()
22
+
23
+ task Trailblazer::Operation::Wrap::Inject::ReverseMergeDefaults.new( contract: "MyDefaultContract" ),
24
+ id: "inject.my_default",
25
+ before: "task_wrap.call_task"
26
+ end
27
+ )
28
+ ]
26
29
  )
27
30
 
28
31
  def model!(options, **)
@@ -42,7 +45,6 @@ class TaskWrapTest < Minitest::Spec
42
45
  it do
43
46
  direction, (options, _) = Create.__call__( [{}, {}] )
44
47
 
45
-
46
48
  inspect_hash(options, "options.contract", :contract, "MyMacro.contract").
47
49
  must_equal %{{"options.contract"=>nil, :contract=>"MyDefaultContract", "MyMacro.contract"=>"MyDefaultContract"}}
48
50
  end
@@ -73,12 +75,16 @@ class TaskWrapTest < Minitest::Spec
73
75
  step(
74
76
  task: AnotherMacro,
75
77
  id: "AnotherMacro",
76
- runner_options: {
77
- merge: Trailblazer::Activity::Magnetic::Builder::Path.plan do
78
- task Trailblazer::Operation::Wrap::Inject::ReverseMergeDefaults.new( another_contract: "AnotherDefaultContract" ), id: "inject.my_default",
79
- before: "task_wrap.call_task"
80
- end
81
- }
78
+ extension: [
79
+ Trailblazer::Activity::TaskWrap::Merge.new(
80
+ Module.new do
81
+ extend Trailblazer::Activity::Path::Plan()
82
+
83
+ task Trailblazer::Operation::Wrap::Inject::ReverseMergeDefaults.new( another_contract: "AnotherDefaultContract" ), id: "inject.my_default",
84
+ before: "task_wrap.call_task"
85
+ end
86
+ )
87
+ ]
82
88
  )
83
89
  end
84
90
 
@@ -28,7 +28,8 @@ class TraceTest < Minitest::Spec
28
28
  stack, _ = Trailblazer::Activity::Trace.(
29
29
  Create,
30
30
  [
31
- { a_return: true, "params" => {} },
31
+ { a_return: true, params: {} },
32
+ {}
32
33
  ]
33
34
  )
34
35
 
@@ -47,7 +48,7 @@ class TraceTest < Minitest::Spec
47
48
  end
48
49
 
49
50
  it "Operation::trace" do
50
- result = Create.trace({ "params" => { x: 1 }, a_return: true })
51
+ result = Create.trace({ params: { x: 1 }, a_return: true })
51
52
  result.wtf.gsub(/0x\w+/, "").gsub(/@.+_test/, "").must_equal %{|-- #<Trailblazer::Activity::Start:>
52
53
  |-- Create.task.a
53
54
  |-- MyNested
@@ -20,9 +20,11 @@ class VariableMappingTest < Minitest::Spec
20
20
  end
21
21
 
22
22
  let (:activity) do
23
- Activity.build do
24
- task Model
25
- task Uuid
23
+ Module.new do
24
+ extend Activity::Path()
25
+
26
+ task task: Model
27
+ task task: Uuid
26
28
  end
27
29
  end
28
30
 
@@ -34,18 +36,22 @@ class VariableMappingTest < Minitest::Spec
34
36
  uuid_input = ->(options) { { "a" => options["a"]*3, "model.a" => options["model.a"] } }
35
37
  uuid_output = ->(options) { { "uuid.a" => options["a"] } }
36
38
 
37
- runtime = Hash.new([])
39
+ runtime = {}
38
40
 
39
41
  # add filters around Model.
40
- runtime[ Model ] = Activity::Magnetic::Builder::Path.plan do
41
- task Activity::Wrap::Input.new( model_input ), id: "task_wrap.input", before: "task_wrap.call_task"
42
- task Activity::Wrap::Output.new( model_output ), id: "task_wrap.output", before: "End.success", group: :end
42
+ runtime[ Model ] = Module.new do
43
+ extend Activity::Path::Plan()
44
+
45
+ task Activity::TaskWrap::Input.new( model_input ), id: "task_wrap.input", before: "task_wrap.call_task"
46
+ task Activity::TaskWrap::Output.new( model_output ), id: "task_wrap.output", before: "End.success", group: :end
43
47
  end
44
48
 
45
49
  # add filters around Uuid.
46
- runtime[ Uuid ] = Activity::Magnetic::Builder::Path.plan do
47
- task Activity::Wrap::Input.new( uuid_input ), id: "task_wrap.input", before: "task_wrap.call_task"
48
- task Activity::Wrap::Output.new( uuid_output ), id: "task_wrap.output", before: "End.success", group: :end
50
+ runtime[ Uuid ] = Module.new do
51
+ extend Activity::Path::Plan()
52
+
53
+ task Activity::TaskWrap::Input.new( uuid_input ), id: "task_wrap.input", before: "task_wrap.call_task"
54
+ task Activity::TaskWrap::Output.new( uuid_output ), id: "task_wrap.output", before: "End.success", group: :end
49
55
  end
50
56
 
51
57
  signal, (options, flow_options) = activity.(
@@ -55,8 +61,9 @@ class VariableMappingTest < Minitest::Spec
55
61
  ],
56
62
 
57
63
  wrap_runtime: runtime, # dynamic additions from the outside (e.g. tracing), also per task.
58
- runner: Activity::Wrap::Runner,
59
- wrap_static: Hash.new( Activity::Wrap.initial_activity ), # per activity?
64
+ runner: Activity::TaskWrap::Runner,
65
+ argumenters: [ Activity::TaskWrap::NonStatic.method(:arguments_for_call) ],
66
+ wrap_static: Hash.new( Activity::TaskWrap.initial_activity ),
60
67
  )
61
68
 
62
69
  signal.must_equal activity.outputs[:success].signal
@@ -158,7 +158,7 @@ class WireDefaultsEarlyExitSuccessTest < Minitest::Spec
158
158
  end
159
159
  end
160
160
 
161
- it { puts Trailblazer::Activity::Magnetic::Introspect.seq( Connect ) }
161
+ # it { puts Trailblazer::Activity::Magnetic::Introspect.seq( Connect.decompose.first ) }
162
162
 
163
163
  # a => true
164
164
  it { Connect.( a_return: true, b_return: true,data: []).inspect(:data).must_equal %{<Result:true [[:a, :b, :d]] >} }
@@ -17,7 +17,7 @@ Gem::Specification.new do |spec|
17
17
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
18
18
  spec.require_paths = ["lib"]
19
19
 
20
- spec.add_dependency "trailblazer-activity", ">= 0.3.2", "< 0.4.0"
20
+ spec.add_dependency "trailblazer-activity", ">= 0.4.0", "< 0.5.0"
21
21
  spec.add_dependency "trailblazer-context", ">= 0.1.1", "< 0.3.0"
22
22
 
23
23
  spec.add_development_dependency "bundler"
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trailblazer-operation
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.3
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-12-23 00:00:00.000000000 Z
11
+ date: 2018-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trailblazer-activity
@@ -16,20 +16,20 @@ dependencies:
16
16
  requirements:
17
17
  - - ">="
18
18
  - !ruby/object:Gem::Version
19
- version: 0.3.2
19
+ version: 0.4.0
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: 0.4.0
22
+ version: 0.5.0
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
26
26
  requirements:
27
27
  - - ">="
28
28
  - !ruby/object:Gem::Version
29
- version: 0.3.2
29
+ version: 0.4.0
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: 0.4.0
32
+ version: 0.5.0
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: trailblazer-context
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -107,6 +107,7 @@ files:
107
107
  - Rakefile
108
108
  - lib/trailblazer/operation.rb
109
109
  - lib/trailblazer/operation/deprecated_macro.rb
110
+ - lib/trailblazer/operation/heritage.rb
110
111
  - lib/trailblazer/operation/inject.rb
111
112
  - lib/trailblazer/operation/inspect.rb
112
113
  - lib/trailblazer/operation/public_call.rb
@@ -117,7 +118,6 @@ files:
117
118
  - lib/trailblazer/operation/railway/task_builder.rb
118
119
  - lib/trailblazer/operation/result.rb
119
120
  - lib/trailblazer/operation/skill.rb
120
- - lib/trailblazer/operation/task_wrap.rb
121
121
  - lib/trailblazer/operation/trace.rb
122
122
  - lib/trailblazer/operation/variable_mapping.rb
123
123
  - lib/trailblazer/operation/version.rb
@@ -171,7 +171,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
171
171
  version: '0'
172
172
  requirements: []
173
173
  rubyforge_project:
174
- rubygems_version: 2.6.8
174
+ rubygems_version: 2.7.3
175
175
  signing_key:
176
176
  specification_version: 4
177
177
  summary: Trailblazer's operation object with railway flow and integrated error handling.
@@ -1,68 +0,0 @@
1
- module Trailblazer
2
- module Operation::Railway
3
- module TaskWrap
4
- def self.included(includer)
5
- includer.extend ClassMethods # ::__call__, ::inititalize_task_wraps!
6
- includer.extend DSL
7
-
8
- includer.initialize_task_wraps!
9
- end
10
-
11
- module ClassMethods
12
- def initialize_task_wraps!
13
- heritage.record :initialize_task_wraps!
14
-
15
- # The map of task_wrap per step/task. Note that it defaults to Wrap.initial_activity.
16
- # This gets extended at compile-time for particular tasks as the steps are created via the DSL.
17
- self["__static_task_wraps__"] = ::Hash.new(Activity::Wrap.initial_activity)
18
- end
19
-
20
- # __call__ prepares `flow_options` and `static_wraps` for {TaskWrap::Runner}.
21
- def __call__(args, **circuit_args)
22
- args, _circuit_args = TaskWrap.arguments_for_call(self, args, **circuit_args)
23
-
24
- super( args, circuit_args.merge(_circuit_args) ) # Railway::__call__
25
- end
26
- end
27
-
28
- def self.arguments_for_call(operation, (options, flow_options), **circuit_args)
29
- wrap_static = operation["__static_task_wraps__"]
30
-
31
- circuit_args = {
32
- runner: Activity::Wrap::Runner,
33
- # FIXME: this sucks, why do we even need to pass an empty runtime there?
34
- wrap_runtime: circuit_args[:wrap_runtime] || ::Hash.new([]), # FIXME:this sucks. (was:) this overwrites wrap_runtime from outside.
35
- wrap_static: wrap_static,
36
- }
37
-
38
- return [ options, flow_options ], circuit_args
39
- end
40
-
41
- module DSL
42
- # TODO: this override is hard to follow, we should have a pipeline circuit in DSL to add behavior.
43
- # @private
44
- def _task(*args)
45
- returned = super # TODO: do this with a circuit :)
46
- adds, (task, local_options) = returned
47
-
48
- runner_options = local_options[:runner_options]
49
-
50
- runner_options and apply_adds_from_runner_options!( task, runner_options )
51
-
52
- returned
53
- end
54
-
55
- # Extend the static wrap for a specific task, at compile time.
56
- def apply_adds_from_runner_options!(task, merge:raise, **ignored)
57
- static_wrap = self["__static_task_wraps__"][task]
58
-
59
- # macro might want to apply changes to the static task_wrap (e.g. Inject)
60
- self["__static_task_wraps__"][task] = Activity::Magnetic::Builder.merge( static_wrap, merge )
61
- end
62
- end
63
- end # TaskWrap
64
- end
65
- end
66
-
67
-
68
- # |-- Railway::Call "insert.exec_context"