trailblazer-macro 2.1.6 → 2.1.10.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: d789d88096949c41a15147feed363efab5c86e586b4f76c819e12f6e8f2d4a70
4
- data.tar.gz: fbe7775b4330bc7b607058da66c896fe461e73b1337e747c23eb87acb04b8d30
3
+ metadata.gz: 4e07fee7d3fb35d6b830f020d3d3881be004a64ca3d6a82a9dce8ed314d732f5
4
+ data.tar.gz: e8a2f00963f34d5ac031e80df423700148110afd1f3ae7132837992de8542e5b
5
5
  SHA512:
6
- metadata.gz: df7f0de0c1107ea8c9b3803e8343907c0deb78e943ac2298a114db9fedb6de88252f5055a247b516fa3c80a2432f52913fd6d84ceb189779b58c87da6204a20f
7
- data.tar.gz: a1e7a11851d02b26badfbff8aa6932810bc2e32ae3d1f4ce5fd73f2bf26284bff62a88b1fd27d29f5b82a7962e61fd0655b97f483483ff6df5cffdb3326f51e0
6
+ metadata.gz: 2d304e5385fa03e95a51db017f7d53bb7afb6d9e6e52f90869f01642d3c40848c9cd4abc327daf5a7bfb8ede5d3266f6a73c704fd742fe55e7ee7a37f7634571
7
+ data.tar.gz: 971ffebfbcd3ef1ba280bc53efef3983ea489568aafa85e4e53089dda7401c2cfd988aea0d0f6cc425a523ecd8a1372ae4b502f21d15d20f49345ffd486ab6c4
@@ -6,7 +6,7 @@ jobs:
6
6
  fail-fast: false
7
7
  matrix:
8
8
  # Due to https://github.com/actions/runner/issues/849, we have to use quotes for '3.0'
9
- ruby: [2.5, 2.6, 2.7, '3.0', head, jruby, jruby-head]
9
+ ruby: [2.5, 2.6, 2.7, '3.0', "3.1", head, jruby]
10
10
  runs-on: ubuntu-latest
11
11
  steps:
12
12
  - uses: actions/checkout@v2
data/CHANGES.md CHANGED
@@ -1,3 +1,23 @@
1
+ # 2.1.10
2
+
3
+ * In `Nested()`, we no longer use `Railway::End::Success` and `Railway::End::Failure` as static outputs but
4
+ simply use `Railway`'s default termini objects.
5
+ * Use `dsl`'s new `Inject()` API instead of a overriding `:inject` in `Model()` and `Policy()`.
6
+
7
+ # 2.1.9
8
+
9
+ * Allow omitting `:params` when calling the operation by defaulting it to `{}` in `Model()`.
10
+ * Use `dsl-linear` 0.5.0 and above, which allows removing `Inject()` uses.
11
+
12
+ # 2.1.8
13
+
14
+ Yanked due to inconsistency.
15
+
16
+ # 2.1.7
17
+
18
+ * Improve `Nested()` warning message.
19
+ * Fix exception in `Rescue()` macro when it's handler is a `Module`.
20
+
1
21
  # 2.1.6
2
22
 
3
23
  * Allow connecting ends of the dynamically selected activity for `Nested()` using `:auto_wire`.
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  All common Macro's for Trailblazer::Operation, will come here
3
3
 
4
4
  ## TODO
5
- Describe the following Macro's:
5
+ Describe the following Macros:
6
6
  - Nested
7
7
  - Rescue
8
8
  - Wrap
@@ -8,7 +8,6 @@ module Trailblazer::Macro
8
8
  def self.build(callable)
9
9
  option = Trailblazer::Option(callable)
10
10
 
11
- # this gets wrapped in a Operation::Result object.
12
11
  ->((ctx, *), **circuit_args) do
13
12
  Trailblazer::Operation::Result.new(!!option.call(ctx, keyword_arguments: ctx.to_hash, **circuit_args), {})
14
13
  end
@@ -1,54 +1,60 @@
1
- module Trailblazer::Macro
1
+ module Trailblazer
2
+ module Macro
2
3
 
3
- Linear = Trailblazer::Activity::DSL::Linear
4
+ def self.Model(model_class = nil, action = :new, find_by_key = :id, id: 'model.build', not_found_terminus: false)
5
+ task = Activity::TaskBuilder::Binary(Model.new)
4
6
 
5
- def self.Model(model_class, action = nil, find_by_key = nil, id: 'model.build', not_found_terminus: false)
6
- task = Trailblazer::Activity::TaskBuilder::Binary(Model.new)
7
+ injections = {
8
+ Activity::Railway.Inject() => [:params], # pass-through {:params} if it's in ctx.
7
9
 
8
- injection = Trailblazer::Activity::TaskWrap::Inject::Defaults::Extension(
9
- :"model.class" => model_class,
10
- :"model.action" => action,
11
- :"model.find_by_key" => find_by_key
12
- )
10
+ # defaulting as per Inject() API.
11
+ Activity::Railway.Inject() => {
12
+ :"model.class" => ->(*) { model_class },
13
+ :"model.action" => ->(*) { action },
14
+ :"model.find_by_key" => ->(*) { find_by_key },
15
+ }
16
+ }
13
17
 
14
- options = { task: task, id: id, extensions: [injection] }
15
- options = options.merge(Linear::Output(:failure) => Linear::End(:not_found)) if not_found_terminus
18
+ options = {task: task, id: id}.merge(injections)
16
19
 
17
- options
18
- end
20
+ options = options.merge(Activity::Railway.Output(:failure) => Activity::Railway.End(:not_found)) if not_found_terminus
19
21
 
20
- class Model
21
- def call(options, params: nil, **)
22
- builder = Model::Builder.new
23
- options[:model] = model = builder.call(options, params)
24
- options[:"result.model"] = result = Trailblazer::Operation::Result.new(!model.nil?, {})
25
-
26
- result.success?
22
+ options
27
23
  end
28
24
 
29
- class Builder
30
- def call(options, params)
31
- action = options[:"model.action"] || :new
32
- model_class = options[:"model.class"]
33
- find_by_key = options[:"model.find_by_key"] || :id
34
- action = :pass_through unless %i[new find_by].include?(action)
35
-
36
- send("#{action}!", model_class, params, options[:"model.action"], find_by_key)
37
- end
38
-
39
- def new!(model_class, params, *)
40
- model_class.new
41
- end
25
+ class Model
26
+ def call(ctx, params: {}, **)
27
+ builder = Model::Builder.new
28
+ ctx[:model] = model = builder.call(ctx, params)
29
+ ctx[:"result.model"] = result = Operation::Result.new(!model.nil?, {})
42
30
 
43
- # Doesn't throw an exception and will return false to divert to Left.
44
- def find_by!(model_class, params, action, find_by_key, *)
45
- model_class.find_by(find_by_key.to_sym => params[find_by_key])
31
+ result.success?
46
32
  end
47
33
 
48
- # Call any method on the model class and pass find_by_key, for example find(params[:id]).
49
- def pass_through!(model_class, params, action, find_by_key, *)
50
- model_class.send(action, params[find_by_key])
34
+ class Builder
35
+ def call(ctx, params)
36
+ action = ctx[:"model.action"]
37
+ model_class = ctx[:"model.class"]
38
+ find_by_key = ctx[:"model.find_by_key"]
39
+ action = :pass_through unless %i[new find_by].include?(action)
40
+
41
+ send("#{action}!", model_class, params, ctx[:"model.action"], find_by_key)
42
+ end
43
+
44
+ def new!(model_class, params, *)
45
+ model_class.new
46
+ end
47
+
48
+ # Doesn't throw an exception and will return false to divert to Left.
49
+ def find_by!(model_class, params, action, find_by_key, *)
50
+ model_class.find_by(find_by_key.to_sym => params[find_by_key])
51
+ end
52
+
53
+ # Call any method on the model class and pass find_by_key, for example find(params[:id]).
54
+ def pass_through!(model_class, params, action, find_by_key, *)
55
+ model_class.send(action, params[find_by_key])
56
+ end
51
57
  end
52
58
  end
53
- end
59
+ end # Macro
54
60
  end
@@ -4,25 +4,31 @@ module Trailblazer
4
4
  # {Nested} macro.
5
5
  def self.Nested(callable, id: "Nested(#{callable})", auto_wire: [])
6
6
  if callable.is_a?(Class) && callable < Nested.operation_class
7
- warn %{[Trailblazer] Using the `Nested()` macro with operations and activities is deprecated. Replace `Nested(Create)` with `Subprocess(Create)`.}
8
- return Nested.operation_class.Subprocess(callable)
7
+ caller_location = caller_locations(2, 1)[0]
8
+ warn "[Trailblazer]#{caller_location.absolute_path}: " \
9
+ "Using the `Nested()` macro with operations and activities is deprecated. " \
10
+ "Replace `Nested(#{callable})` with `Subprocess(#{callable})`."
11
+
12
+ return Activity::Railway.Subprocess(callable)
9
13
  end
10
14
 
11
- # dynamic
12
- task = Nested::Dynamic.new(callable, auto_wire: auto_wire)
15
+ task, outputs, compute_legacy_return_signal = Nested.Dynamic(callable, auto_wire: auto_wire)
13
16
 
14
17
  merge = [
15
- [Activity::TaskWrap::Pipeline.method(:insert_before), "task_wrap.call_task", ["Nested.compute_nested_activity", task.method(:compute_nested_activity)]],
16
- [Activity::TaskWrap::Pipeline.method(:insert_after), "task_wrap.call_task", ["Nested.compute_return_signal", task.method(:compute_return_signal)]],
18
+ [task, id: "Nested.compute_nested_activity", prepend: "task_wrap.call_task"],
17
19
  ]
18
20
 
19
- task_wrap_extension = Activity::TaskWrap::Extension(merge: merge)
21
+ if compute_legacy_return_signal
22
+ merge << [compute_legacy_return_signal, id: "Nested.compute_return_signal", append: "task_wrap.call_task"]
23
+ end
24
+
25
+ task_wrap_extension = Activity::TaskWrap::Extension::WrapStatic.new(extension: Activity::TaskWrap::Extension(*merge))
20
26
 
21
27
  {
22
28
  task: task,
23
29
  id: id,
24
30
  extensions: [task_wrap_extension],
25
- outputs: task.outputs,
31
+ outputs: outputs,
26
32
  }
27
33
  end
28
34
 
@@ -41,57 +47,64 @@ module Trailblazer
41
47
  # by passing their list to {:auto_wire} option.
42
48
  #
43
49
  # step Nested(:compute_nested, auto_wire: [Create, Update])
44
- class Dynamic
45
- STATIC_OUTPUTS = {
46
- :success => Activity::Output(Activity::Railway::End::Success.new(semantic: :success), :success),
47
- :failure => Activity::Output(Activity::Railway::End::Failure.new(semantic: :failure), :failure),
48
- }
49
-
50
- def initialize(nested_activity_decider, auto_wire: [])
51
- @nested_activity_decider = Trailblazer::Option(nested_activity_decider)
52
- @known_activities = Array(auto_wire)
53
- @outputs = compute_task_outputs
50
+ def self.Dynamic(nested_activity_decider, auto_wire:)
51
+ if auto_wire.empty?
52
+ is_legacy = true # no auto_wire means we need to compute the legacy return signal.
53
+ auto_wire = [Class.new(Activity::Railway)]
54
54
  end
55
55
 
56
- attr_reader :outputs
56
+ outputs = outputs_for(auto_wire)
57
+ task = Dynamic.new(nested_activity_decider)
58
+ compute_legacy_return_signal = Dynamic::ComputeLegacyReturnSignal.new(outputs) if is_legacy
59
+
60
+ return task, outputs, compute_legacy_return_signal
61
+ end
62
+
63
+ # Go through the list of all possible nested activities and compile the total sum of possible outputs.
64
+ # FIXME: WHAT IF WE HAVE TWO IDENTICALLY NAMED OUTPUTS?
65
+ # @private
66
+ def self.outputs_for(activities)
67
+ activities.map do |activity|
68
+ Activity::Railway.Subprocess(activity)[:outputs]
69
+ end.inject(:merge)
70
+ end
71
+
72
+ class Dynamic
73
+ def initialize(nested_activity_decider)
74
+ @nested_activity_decider = Trailblazer::Option(nested_activity_decider)
75
+ end
57
76
 
58
77
  # TaskWrap step.
59
- def compute_nested_activity(wrap_ctx, original_args)
78
+ def call(wrap_ctx, original_args)
60
79
  (ctx, _), original_circuit_options = original_args
61
80
 
62
81
  # TODO: evaluate the option to get the actual "object" to call.
63
82
  activity = @nested_activity_decider.(ctx, keyword_arguments: ctx.to_hash, **original_circuit_options)
64
83
 
65
84
  # Overwrite :task so task_wrap.call_task will call this activity.
66
- # This is a trick so we don't have to repeat logic from #call_task here.
85
+ # This is a taskWrap trick so we don't have to repeat logic from #call_task here.
67
86
  wrap_ctx[:task] = activity
68
87
 
69
88
  return wrap_ctx, original_args
70
89
  end
71
90
 
72
- def compute_return_signal(wrap_ctx, original_args)
73
- # NOOP when @known_activities are present as all possible signals have been registered already.
74
- if @known_activities.empty?
75
- # Translate the genuine nested signal to the generic Dynamic end (success/failure, only).
76
- # Note that here we lose information about what specific event was emitted.
77
- wrap_ctx[:return_signal] = wrap_ctx[:return_signal].kind_of?(Activity::Railway::End::Success) ?
78
- @outputs[:success].signal : @outputs[:failure].signal
91
+ # TODO: remove me when we make {:auto_wire} mandatory.
92
+ class ComputeLegacyReturnSignal
93
+ SUCCESS_SEMANTICS = [:success, :pass_fast] # TODO: make this injectable/or get it from operation.
94
+
95
+ def initialize(outputs)
96
+ @outputs = outputs # not needed for auto_wire!
79
97
  end
80
98
 
81
- return wrap_ctx, original_args
82
- end
99
+ def call(wrap_ctx, original_args)
100
+ actual_semantic = wrap_ctx[:return_signal].to_h[:semantic]
101
+ applied_semantic = SUCCESS_SEMANTICS.include?(actual_semantic) ? :success : :failure
83
102
 
84
- private def compute_task_outputs
85
- # If :auto_wire is empty, we map outputs to :success and :failure only, for backward compatibility.
86
- # This is what {Nested} in 2.0 used to do, where the outcome could only be true/false (or success/failure).
87
- return STATIC_OUTPUTS if @known_activities.empty?
103
+ wrap_ctx[:return_signal] = @outputs.fetch(applied_semantic).signal
88
104
 
89
- # Merge activity#outputs from all given auto_wirable activities to wire up for this dynamic task.
90
- @known_activities.map do |activity|
91
- # TODO: Replace this when it's helper gets added.
92
- Hash[activity.to_h[:outputs].collect{ |output| [output.semantic, output] }]
93
- end.inject(:merge)
94
- end
105
+ return wrap_ctx, original_args
106
+ end
107
+ end # ComputeLegacyReturnSignal
95
108
  end
96
109
  end
97
110
  end
@@ -8,35 +8,38 @@ module Trailblazer::Macro
8
8
  @path = path
9
9
  end
10
10
 
11
- # incoming low-level {Task API}.
11
+ # incoming low-level {circuit interface}.
12
12
  # outgoing Task::Binary API.
13
- def call((options, flow_options), **circuit_options)
14
- condition = options[@path] # this allows dependency injection.
15
- result = condition.([options, flow_options], **circuit_options)
13
+ #
14
+ # Retrieve the injectable {condition}, execute it and interpret its {Result} object.
15
+ def call((ctx, flow_options), **circuit_options)
16
+ condition = ctx[@path] # this allows dependency injection.
17
+ result = condition.([ctx, flow_options], **circuit_options)
16
18
 
17
- options[:"policy.#{@name}"] = result[:policy] # assign the policy as a skill.
18
- options[:"result.policy.#{@name}"] = result
19
+ ctx[:"policy.#{@name}"] = result[:policy] # assign the policy as a ctx variable.
20
+ ctx[:"result.policy.#{@name}"] = result
19
21
 
20
22
  # flow control
21
- signal = result.success? ? Trailblazer::Activity::Right : Trailblazer::Activity::Left # since we & this, it's only executed OnRight and the return boolean decides the direction, input is passed straight through.
23
+ signal = result.success? ? Trailblazer::Activity::Right : Trailblazer::Activity::Left
22
24
 
23
- return signal, [options, flow_options]
25
+ return signal, [ctx, flow_options]
24
26
  end
25
27
  end
26
28
 
27
- # Adds the `yield` result to the pipe and treats it like a
29
+ # Adds the `yield` result to the Railway and treats it like a
28
30
  # policy-compatible object at runtime.
29
- def self.step(condition, options, &block)
30
- name = options[:name]
31
+ def self.step(condition, name: nil, &block)
31
32
  path = :"policy.#{name}.eval"
32
-
33
33
  task = Eval.new(name: name, path: path)
34
34
 
35
- injection = Trailblazer::Activity::TaskWrap::Inject::Defaults::Extension(
36
- path => condition
37
- )
35
+ injections = {
36
+ Trailblazer::Activity::Railway.Inject() => {
37
+ # :"policy.default.eval"
38
+ path => ->(*) { condition }
39
+ }
40
+ }
38
41
 
39
- {task: task, id: path, extensions: [injection]}
42
+ {task: task, id: path}.merge(injections)
40
43
  end
41
44
  end
42
45
  end
@@ -28,11 +28,8 @@ module Trailblazer
28
28
  # TODO: remove me in 2.2.
29
29
  module Rescue
30
30
  def self.deprecate_positional_handler_signature(handler)
31
- return handler if handler.is_a?(Symbol) # can't do nutting about this.
32
-
33
- arity = handler.is_a?(Class) ? handler.method(:call).arity : handler.arity
34
-
35
- return handler if arity != 2 # means (exception, (ctx, flow_options), *, &block), "new style"
31
+ return handler if handler.is_a?(Symbol) # can't do nothing about this.
32
+ return handler if handler.method(:call).arity != 2 # means (exception, (ctx, flow_options), *, &block), "new style"
36
33
 
37
34
  ->(exception, (ctx, flow_options), **circuit_options, &block) do
38
35
  warn "[Trailblazer] Rescue handlers have a new signature: (exception, *, &block)"
@@ -1,7 +1,7 @@
1
1
  module Trailblazer
2
2
  module Version
3
3
  module Macro
4
- VERSION = "2.1.6"
4
+ VERSION = "2.1.10.beta1"
5
5
  end
6
6
  end
7
7
  end
@@ -1,5 +1,4 @@
1
1
  require "forwardable"
2
- require "trailblazer/activity"
3
2
  require "trailblazer/activity/dsl/linear"
4
3
  require "trailblazer/operation" # TODO: remove this dependency
5
4
 
@@ -17,12 +16,13 @@ module Trailblazer
17
16
 
18
17
  # All macros sit in the {Trailblazer::Macro} namespace, where we forward calls from
19
18
  # operations and activities to.
19
+
20
20
  module Activity::DSL::Linear::Helper
21
- Policy = Trailblazer::Macro::Policy
21
+ Constants::Policy = Trailblazer::Macro::Policy
22
22
 
23
- module ClassMethods
24
- extend Forwardable
25
- def_delegators Trailblazer::Macro, :Model, :Nested, :Wrap, :Rescue
26
- end # ClassMethods
23
+ # Extending the {Linear::Helper} namespace is the canonical way to import
24
+ # macros into Railway, FastTrack, Operation, etc.
25
+ extend Forwardable
26
+ def_delegators Trailblazer::Macro, :Model, :Nested, :Wrap, :Rescue
27
27
  end # Helper
28
28
  end
@@ -16,11 +16,22 @@ class DocsModelTest < Minitest::Spec
16
16
 
17
17
  #:op
18
18
  class Create < Trailblazer::Operation
19
- step Model( Song, :new )
19
+ step Model(Song, :new)
20
20
  # ..
21
21
  end
22
22
  #:op end
23
23
 
24
+
25
+ it "defaults {:params} to empty hash when not passed" do
26
+ result = Create.({})
27
+ assert_equal true, result.success?
28
+ assert_equal %{#<struct DocsModelTest::Song id=nil, title=nil>}, result[:model].inspect
29
+
30
+ result = Update.({})
31
+ assert_equal false, result.success?
32
+ assert_equal "nil", result[:model].inspect
33
+ end
34
+
24
35
  it do
25
36
  #:create
26
37
  result = Create.(params: {})
@@ -121,4 +132,43 @@ class DocsModelTest < Minitest::Spec
121
132
  result.success?.must_equal true
122
133
  result[:model].inspect.must_equal %{#<struct DocsModelTest::Song id=100, title=nil>}
123
134
  end
135
+
136
+ it "allows injecting {:model.class} and friends" do
137
+ class Hit < Song
138
+ end
139
+
140
+ #:di-model-class
141
+ result = Create.(params: {}, :"model.class" => Hit)
142
+ #:di-model-class end
143
+
144
+ result[:model].inspect.must_equal %{#<struct DocsModelTest::Hit id=nil, title=nil>}
145
+
146
+ # inject all variables
147
+ #:di-all
148
+ result = Create.(
149
+ params: {title: "Olympia"}, # some random variable.
150
+ "model.class": Hit,
151
+ "model.action": :find_by,
152
+ "model.find_by_key": :title
153
+ )
154
+ #:di-all end
155
+
156
+ result[:model].inspect.must_equal %{#<struct DocsModelTest::Hit id=2, title="Olympia">}
157
+
158
+ # use empty Model() and inject {model.class} and {model.action}
159
+ module A
160
+ #:op-model-empty
161
+ class Create < Trailblazer::Operation
162
+ step Model()
163
+ # ..
164
+ end
165
+ #:op-model-empty end
166
+ end # A
167
+
168
+ result = A::Create.(params: {}, :"model.class" => Hit)
169
+
170
+ result[:model].inspect.must_equal %{#<struct DocsModelTest::Hit id=nil, title=nil>}
171
+
172
+
173
+ end
124
174
  end
@@ -151,7 +151,8 @@ class NestedInput < Minitest::Spec
151
151
  end
152
152
  #:nested-with-pass-fast end
153
153
 
154
- # pass fast
154
+ #= {#save} is still called because the {End.pass_fast} terminus is automatically wired to
155
+ #= the success "output" of Nested().
155
156
  create.(seq: []).inspect(:seq).must_equal %{<Result:true [[:create, :just_pass_fast, :save]] >}
156
157
  end
157
158
  end
@@ -159,15 +160,16 @@ class NestedInput < Minitest::Spec
159
160
  it "Nested(:method, auto_wire: *activities) with :pass_fast => End()" do
160
161
  module E
161
162
  class JsonValidate < Trailblazer::Operation
162
- step :validate, Output(:success) => End(:json_validate)
163
- include T.def_steps(:validate)
163
+ step :validate, Output(:failure) => End(:invalid_json)
164
+ step :save
165
+ include T.def_steps(:validate, :save)
164
166
  end
165
167
 
166
168
  #:nested-with-auto-wire
167
169
  class Create < Trailblazer::Operation
168
170
  step :create
169
171
  step Nested(:compute_nested, auto_wire: [Validate, JsonValidate]),
170
- Output(:json_validate) => End(:jsoned)
172
+ Output(:invalid_json) => End(:jsoned)
171
173
 
172
174
  #~meths
173
175
  def compute_nested(ctx, what:, **)
@@ -179,10 +181,36 @@ class NestedInput < Minitest::Spec
179
181
  end
180
182
  #:nested-with-auto-wire end
181
183
 
182
- result = Create.(seq: [], what: JsonValidate)
184
+
185
+ #@ nested {JsonValidate} ends on {End.success}
186
+ result = Create.(seq: [], what: JsonValidate, validate: true)
187
+
188
+ result.inspect(:seq).must_equal %{<Result:true [[:create, :validate, :save]] >}
189
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Success semantic=:success>}
190
+
191
+ #@ nested {JsonValidate} ends on {End.invalid_json} because validate fails.
192
+ result = Create.(seq: [], what: JsonValidate, validate: false)
183
193
 
184
194
  result.inspect(:seq).must_equal %{<Result:false [[:create, :validate]] >}
185
195
  result.event.inspect.must_equal %{#<Trailblazer::Activity::End semantic=:jsoned>}
196
+
197
+ #@ nested {JsonValidate} ends on {End.failure} because save fails.
198
+ result = Create.(seq: [], what: JsonValidate, save: false)
199
+
200
+ result.inspect(:seq).must_equal %{<Result:false [[:create, :validate, :save]] >}
201
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Failure semantic=:failure>}
202
+
203
+ #@ nested {Validate} ends on {End.failure} because validate fails.
204
+ result = Create.(seq: [], what: Validate, validate: false)
205
+
206
+ result.inspect(:seq).must_equal %{<Result:false [[:create, :validate]] >}
207
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Failure semantic=:failure>}
208
+
209
+ #@ nested {Validate} ends on {End.success}.
210
+ result = Create.(seq: [], what: Validate)
211
+
212
+ result.inspect(:seq).must_equal %{<Result:true [[:create, :validate]] >}
213
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Success semantic=:success>}
186
214
  end
187
215
  end
188
216
  end
@@ -66,7 +66,7 @@ plain Rescue()
66
66
  =begin
67
67
  Rescue( handler: X )
68
68
  =end
69
- class RescueWithHandlerTest < Minitest::Spec
69
+ class RescueWithClassHandlerTest < Minitest::Spec
70
70
  Memo = Class.new
71
71
 
72
72
  #:rescue-handler
@@ -97,10 +97,35 @@ Rescue( handler: X )
97
97
  it { Memo::Create.( { seq: [], rehash_raise: true } ).inspect(:seq, :exception_class).must_equal %{<Result:false [[:find_model, :update, :rehash, :log_error], RuntimeError] >} }
98
98
  end
99
99
 
100
+ class RescueWithModuleHandlerTest < Minitest::Spec
101
+ Memo = Class.new
102
+
103
+ module MyHandler
104
+ def self.call(exception, (ctx), *)
105
+ ctx[:exception_class] = exception.class
106
+ end
107
+ end
108
+
109
+ class Memo::Create < Trailblazer::Operation
110
+ step :find_model
111
+ step Rescue( RuntimeError, handler: MyHandler ) {
112
+ step :update
113
+ step :rehash
114
+ }
115
+ step :notify
116
+ fail :log_error
117
+ include T.def_steps(:find_model, :update, :notify, :log_error)
118
+ include Rehash
119
+ end
120
+
121
+ it { Memo::Create.( { seq: [], } ).inspect(:seq, :exception_class).must_equal %{<Result:true [[:find_model, :update, :rehash, :notify], nil] >} }
122
+ it { Memo::Create.( { seq: [], rehash_raise: true } ).inspect(:seq, :exception_class).must_equal %{<Result:false [[:find_model, :update, :rehash, :log_error], RuntimeError] >} }
123
+ end
124
+
100
125
  =begin
101
126
  Rescue( handler: :instance_method )
102
127
  =end
103
- class RescueWithHandlerTest < Minitest::Spec
128
+ class RescueWithMethodHandlerTest < Minitest::Spec
104
129
  Memo = Class.new
105
130
 
106
131
  #:rescue-method
@@ -49,6 +49,28 @@ class NestedTest < Minitest::Spec
49
49
  result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Success semantic=:success>}
50
50
  end
51
51
 
52
+ #@ unit test
53
+ # TODO: make me a non-Operation test.
54
+ it "allows using multiple Nested() per operation" do
55
+ create = Class.new(Trailblazer::Operation) do
56
+ def compute_nested(ctx, what:, **)
57
+ what
58
+ end
59
+
60
+ step Nested(:compute_nested)
61
+ step Nested(:compute_nested), id: :compute_nested_again
62
+ end
63
+
64
+ #@ we want both Nested executed
65
+ result = create.(seq: [], what: SignIn)
66
+ result.inspect(:seq).must_equal %{<Result:true [[:c, :c]] >}
67
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Success semantic=:success>}
68
+
69
+ result = create.wtf?(seq: [], what: SignUp)
70
+ result.inspect(:seq).must_equal %{<Result:false [[:b]] >}
71
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Failure semantic=:failure>}
72
+ end
73
+
52
74
  it "raises RuntimeError if dynamically nested activities with custom output are not auto wired" do
53
75
  exception = assert_raises RuntimeError do
54
76
  Class.new(Trailblazer::Operation) do
@@ -62,4 +84,15 @@ class NestedTest < Minitest::Spec
62
84
 
63
85
  exception.inspect.must_match 'No `db_error` output found'
64
86
  end
87
+
88
+ it "shows warning if `Nested()` is being used instead of `Subprocess()` for static activities" do
89
+ _, warnings = capture_io do
90
+ Class.new(Trailblazer::Operation) do
91
+ step Nested(SignUp)
92
+ end
93
+ end
94
+
95
+ warnings.must_equal %Q{[Trailblazer]#{__FILE__}: Using the `Nested()` macro with operations and activities is deprecated. Replace `Nested(NestedTest::SignUp)` with `Subprocess(NestedTest::SignUp)`.
96
+ }
97
+ end
65
98
  end
@@ -25,8 +25,8 @@ Gem::Specification.new do |spec|
25
25
  spec.add_development_dependency "roar"
26
26
  spec.add_development_dependency "trailblazer-developer"
27
27
 
28
- spec.add_dependency "trailblazer-activity-dsl-linear", ">= 0.4.0", "< 0.5.0"
29
- spec.add_dependency "trailblazer-operation", ">= 0.7.0" # TODO: this dependency will be removed.
28
+ spec.add_dependency "trailblazer-activity-dsl-linear", ">= 1.0.0.beta1", "< 1.1.0"
29
+ spec.add_dependency "trailblazer-operation", ">= 0.8.0.beta1" # TODO: this dependency will be removed. currently needed for tests?!
30
30
 
31
31
  spec.required_ruby_version = ">= 2.2.0"
32
32
  end
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trailblazer-macro
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.6
4
+ version: 2.1.10.beta1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  - Marc Tich
9
- autorequire:
9
+ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2021-03-11 00:00:00.000000000 Z
12
+ date: 2022-07-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -101,34 +101,34 @@ dependencies:
101
101
  requirements:
102
102
  - - ">="
103
103
  - !ruby/object:Gem::Version
104
- version: 0.4.0
104
+ version: 1.0.0.beta1
105
105
  - - "<"
106
106
  - !ruby/object:Gem::Version
107
- version: 0.5.0
107
+ version: 1.1.0
108
108
  type: :runtime
109
109
  prerelease: false
110
110
  version_requirements: !ruby/object:Gem::Requirement
111
111
  requirements:
112
112
  - - ">="
113
113
  - !ruby/object:Gem::Version
114
- version: 0.4.0
114
+ version: 1.0.0.beta1
115
115
  - - "<"
116
116
  - !ruby/object:Gem::Version
117
- version: 0.5.0
117
+ version: 1.1.0
118
118
  - !ruby/object:Gem::Dependency
119
119
  name: trailblazer-operation
120
120
  requirement: !ruby/object:Gem::Requirement
121
121
  requirements:
122
122
  - - ">="
123
123
  - !ruby/object:Gem::Version
124
- version: 0.7.0
124
+ version: 0.8.0.beta1
125
125
  type: :runtime
126
126
  prerelease: false
127
127
  version_requirements: !ruby/object:Gem::Requirement
128
128
  requirements:
129
129
  - - ">="
130
130
  - !ruby/object:Gem::Version
131
- version: 0.7.0
131
+ version: 0.8.0.beta1
132
132
  description: Macros for Trailblazer's operation
133
133
  email:
134
134
  - apotonick@gmail.com
@@ -173,7 +173,7 @@ homepage: http://trailblazer.to
173
173
  licenses:
174
174
  - LGPL-3.0
175
175
  metadata: {}
176
- post_install_message:
176
+ post_install_message:
177
177
  rdoc_options: []
178
178
  require_paths:
179
179
  - lib
@@ -184,12 +184,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
184
184
  version: 2.2.0
185
185
  required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  requirements:
187
- - - ">="
187
+ - - ">"
188
188
  - !ruby/object:Gem::Version
189
- version: '0'
189
+ version: 1.3.1
190
190
  requirements: []
191
191
  rubygems_version: 3.2.3
192
- signing_key:
192
+ signing_key:
193
193
  specification_version: 4
194
194
  summary: 'Macros for Trailblazer''s operation: Policy, Wrap, Rescue and more.'
195
195
  test_files: