trailblazer-operation 0.1.3 → 0.2.0

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