trailblazer-macro 2.1.5 → 2.1.6

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
2
  SHA256:
3
- metadata.gz: 4d1d66ce0e6bf576b852792bdee95a0d67148cee1fbb21fdb791e83984154b1f
4
- data.tar.gz: d274da669e987828fbfbf8b45b677d5596558e22e7729f882a35546fd3244e74
3
+ metadata.gz: d789d88096949c41a15147feed363efab5c86e586b4f76c819e12f6e8f2d4a70
4
+ data.tar.gz: fbe7775b4330bc7b607058da66c896fe461e73b1337e747c23eb87acb04b8d30
5
5
  SHA512:
6
- metadata.gz: 10aac4d11e1b286e27101955722ff1ae581df1608dd268f40dcfb8a559db0b91f2cc2a0a72ace708a9a83f34ec3c55efb059d0117e3605df012fd81800714a84
7
- data.tar.gz: 6227e472b59a584de223884a8111b7da5b43bfa3e5f07a5522caef1ff7cf765fb1801aff192f070214513d61cfe0d23b0c66cf2298e6532a9fb04dc6fd06efd0
6
+ metadata.gz: df7f0de0c1107ea8c9b3803e8343907c0deb78e943ac2298a114db9fedb6de88252f5055a247b516fa3c80a2432f52913fd6d84ceb189779b58c87da6204a20f
7
+ data.tar.gz: a1e7a11851d02b26badfbff8aa6932810bc2e32ae3d1f4ce5fd73f2bf26284bff62a88b1fd27d29f5b82a7962e61fd0655b97f483483ff6df5cffdb3326f51e0
@@ -0,0 +1,17 @@
1
+ name: CI
2
+ on: [push, pull_request]
3
+ jobs:
4
+ test:
5
+ strategy:
6
+ fail-fast: false
7
+ matrix:
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]
10
+ runs-on: ubuntu-latest
11
+ steps:
12
+ - uses: actions/checkout@v2
13
+ - uses: ruby/setup-ruby@v1
14
+ with:
15
+ ruby-version: ${{ matrix.ruby }}
16
+ bundler-cache: true # runs 'bundle install' and caches installed gems automatically
17
+ - run: bundle exec rake
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 2.1.6
2
+
3
+ * Allow connecting ends of the dynamically selected activity for `Nested()` using `:auto_wire`.
4
+
1
5
  # 2.1.5
2
6
 
3
7
  * Support for Ruby 3.0.
@@ -2,14 +2,14 @@
2
2
  module Trailblazer
3
3
  module Macro
4
4
  # {Nested} macro.
5
- def self.Nested(callable, id: "Nested(#{callable})")
5
+ def self.Nested(callable, id: "Nested(#{callable})", auto_wire: [])
6
6
  if callable.is_a?(Class) && callable < Nested.operation_class
7
7
  warn %{[Trailblazer] Using the `Nested()` macro with operations and activities is deprecated. Replace `Nested(Create)` with `Subprocess(Create)`.}
8
8
  return Nested.operation_class.Subprocess(callable)
9
9
  end
10
10
 
11
11
  # dynamic
12
- task = Nested::Dynamic.new(callable)
12
+ task = Nested::Dynamic.new(callable, auto_wire: auto_wire)
13
13
 
14
14
  merge = [
15
15
  [Activity::TaskWrap::Pipeline.method(:insert_before), "task_wrap.call_task", ["Nested.compute_nested_activity", task.method(:compute_nested_activity)]],
@@ -33,17 +33,24 @@ module Trailblazer
33
33
  end
34
34
 
35
35
  # For dynamic `Nested`s that do not expose an {Activity} interface.
36
- # Since we do not know its outputs, we have to map them to :success and :failure, only.
37
36
  #
38
- # This is what {Nested} in 2.0 used to do, where the outcome could only be true/false (or success/failure).
37
+ # Dynamic doesn't automatically connect outputs of runtime {Activity}
38
+ # at compile time (as we don't know which activity will be nested, obviously).
39
+ # So by default, it only connects good old success/failure ends. But it is also
40
+ # possible to connect all the ends of all possible dynamic activities
41
+ # by passing their list to {:auto_wire} option.
42
+ #
43
+ # step Nested(:compute_nested, auto_wire: [Create, Update])
39
44
  class Dynamic
40
- def initialize(nested_activity_decider)
41
- @nested_activity_decider = Trailblazer::Option(nested_activity_decider)
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
+ }
42
49
 
43
- @outputs = {
44
- :success => Activity::Output(Activity::Railway::End::Success.new(semantic: :success), :success),
45
- :failure => Activity::Output(Activity::Railway::End::Failure.new(semantic: :failure), :failure)
46
- }
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
47
54
  end
48
55
 
49
56
  attr_reader :outputs
@@ -63,13 +70,28 @@ module Trailblazer
63
70
  end
64
71
 
65
72
  def compute_return_signal(wrap_ctx, original_args)
66
- # Translate the genuine nested signal to the generic Dynamic end (success/failure, only).
67
- # Note that here we lose information about what specific event was emitted.
68
- wrap_ctx[:return_signal] = wrap_ctx[:return_signal].kind_of?(Activity::Railway::End::Success) ?
69
- @outputs[:success].signal : @outputs[:failure].signal
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
79
+ end
70
80
 
71
81
  return wrap_ctx, original_args
72
82
  end
83
+
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?
88
+
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
73
95
  end
74
96
  end
75
97
  end
@@ -1,7 +1,7 @@
1
1
  module Trailblazer
2
2
  module Version
3
3
  module Macro
4
- VERSION = "2.1.5"
4
+ VERSION = "2.1.6"
5
5
  end
6
6
  end
7
7
  end
@@ -22,6 +22,11 @@ class NestedInput < Minitest::Spec
22
22
  include T.def_steps(:validate)
23
23
  end
24
24
 
25
+ class JsonValidate < Validate
26
+ step :json
27
+ include T.def_steps(:json)
28
+ end
29
+
25
30
  it "Nested(Edit), without any options" do
26
31
  module A
27
32
 
@@ -79,11 +84,6 @@ class NestedInput < Minitest::Spec
79
84
  #~meths end
80
85
  end
81
86
  #:nested-dynamic end
82
-
83
- class JsonValidate < Validate
84
- step :json
85
- include T.def_steps(:json)
86
- end
87
87
  # `edit` and `update` can be called from Nested()
88
88
 
89
89
  # edit/success
@@ -119,11 +119,6 @@ class NestedInput < Minitest::Spec
119
119
  end
120
120
  #:nested-dynamic end
121
121
 
122
- class JsonValidate < Validate
123
- step :json
124
- include T.def_steps(:json)
125
- end
126
-
127
122
  # `edit` and `update` can be called from Nested()
128
123
  end
129
124
 
@@ -161,29 +156,34 @@ class NestedInput < Minitest::Spec
161
156
  end
162
157
  end
163
158
 
164
- let(:compute_edit) {
165
- ->(ctx, what:, **) { what }
166
- }
167
-
168
- it "Nested(:method), :pass_fast => :fail_fast doesn't work with standard wiring" do
169
- skip "we need to allow adding :outputs"
159
+ it "Nested(:method, auto_wire: *activities) with :pass_fast => End()" do
160
+ module E
161
+ class JsonValidate < Trailblazer::Operation
162
+ step :validate, Output(:success) => End(:json_validate)
163
+ include T.def_steps(:validate)
164
+ end
170
165
 
171
- compute_edit = self.compute_edit
166
+ #:nested-with-auto-wire
167
+ class Create < Trailblazer::Operation
168
+ step :create
169
+ step Nested(:compute_nested, auto_wire: [Validate, JsonValidate]),
170
+ Output(:json_validate) => End(:jsoned)
172
171
 
173
- pass_fast = Class.new(Trailblazer::Operation) do
174
- step :p, pass_fast: true
175
- include T.def_steps(:p)
176
- end
172
+ #~meths
173
+ def compute_nested(ctx, what:, **)
174
+ what
175
+ end
177
176
 
178
- create = Class.new(Trailblazer::Operation) do
179
- step :a
180
- step Nested(compute_edit, auto_wire: [pass_fast]), Output(:pass_fast) => Track(:fail_fast)
181
- step :b
182
- include T.def_steps(:a, :b)
183
- end
177
+ include T.def_steps(:create)
178
+ #~meths end
179
+ end
180
+ #:nested-with-auto-wire end
184
181
 
182
+ result = Create.(seq: [], what: JsonValidate)
185
183
 
186
- create.(seq: [], what: pass_fast).inspect(:seq).must_equal %{<Result:false [[:a, :c]] >}
184
+ result.inspect(:seq).must_equal %{<Result:false [[:create, :validate]] >}
185
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::End semantic=:jsoned>}
186
+ end
187
187
  end
188
188
  end
189
189
 
@@ -0,0 +1,65 @@
1
+ require 'test_helper'
2
+
3
+ class NestedTest < Minitest::Spec
4
+ DatabaseError = Class.new(Trailblazer::Activity::Signal)
5
+
6
+ class SignUp < Trailblazer::Operation
7
+ def self.b(ctx, **)
8
+ ctx[:seq] << :b
9
+ return DatabaseError
10
+ end
11
+
12
+ step method(:b), Output(DatabaseError, :db_error) => End(:db_error)
13
+ end
14
+
15
+ class SignIn < Trailblazer::Operation
16
+ include T.def_steps(:c)
17
+ step :c
18
+ end
19
+
20
+ it "allows connection with custom output of a nested activity" do
21
+ create = Class.new(Trailblazer::Operation) do
22
+ include T.def_steps(:a, :d)
23
+
24
+ step :a
25
+ step Nested(SignUp), Output(:db_error) => Track(:no_user)
26
+ step :d, magnetic_to: :no_user
27
+ end
28
+
29
+ result = create.(seq: [])
30
+ result.inspect(:seq).must_equal %{<Result:true [[:a, :b, :d]] >}
31
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Success semantic=:success>}
32
+ end
33
+
34
+ it "allows connecting dynamically nested activities with custom output when auto wired" do
35
+ create = Class.new(Trailblazer::Operation) do
36
+ def compute_nested(ctx, what:, **)
37
+ what
38
+ end
39
+
40
+ include T.def_steps(:a, :d)
41
+
42
+ step :a
43
+ step Nested(:compute_nested, auto_wire: [SignUp, SignIn]), Output(:db_error) => Track(:no_user)
44
+ step :d, magnetic_to: :no_user
45
+ end
46
+
47
+ result = create.(seq: [], what: SignUp)
48
+ result.inspect(:seq).must_equal %{<Result:true [[:a, :b, :d]] >}
49
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::Railway::End::Success semantic=:success>}
50
+ end
51
+
52
+ it "raises RuntimeError if dynamically nested activities with custom output are not auto wired" do
53
+ exception = assert_raises RuntimeError do
54
+ Class.new(Trailblazer::Operation) do
55
+ def compute_nested(ctx, what:, **)
56
+ what
57
+ end
58
+
59
+ step Nested(:compute_nested), Output(:db_error) => Track(:no_user)
60
+ end
61
+ end
62
+
63
+ exception.inspect.must_match 'No `db_error` output found'
64
+ end
65
+ 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.5
4
+ version: 2.1.6
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-03 00:00:00.000000000 Z
12
+ date: 2021-03-11 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bundler
@@ -137,10 +137,10 @@ executables: []
137
137
  extensions: []
138
138
  extra_rdoc_files: []
139
139
  files:
140
+ - ".github/workflows/ci.yml"
140
141
  - ".gitignore"
141
142
  - ".rubocop.yml"
142
143
  - ".rubocop_todo.yml"
143
- - ".travis.yml"
144
144
  - CHANGES.md
145
145
  - Gemfile
146
146
  - LICENSE
@@ -165,6 +165,7 @@ files:
165
165
  - test/docs/wrap_test.rb
166
166
  - test/operation/integration_test.rb
167
167
  - test/operation/model_test.rb
168
+ - test/operation/nested_test.rb
168
169
  - test/operation/pundit_test.rb
169
170
  - test/test_helper.rb
170
171
  - trailblazer-macro.gemspec
@@ -172,7 +173,7 @@ homepage: http://trailblazer.to
172
173
  licenses:
173
174
  - LGPL-3.0
174
175
  metadata: {}
175
- post_install_message:
176
+ post_install_message:
176
177
  rdoc_options: []
177
178
  require_paths:
178
179
  - lib
@@ -188,7 +189,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
188
189
  version: '0'
189
190
  requirements: []
190
191
  rubygems_version: 3.2.3
191
- signing_key:
192
+ signing_key:
192
193
  specification_version: 4
193
194
  summary: 'Macros for Trailblazer''s operation: Policy, Wrap, Rescue and more.'
194
195
  test_files:
@@ -201,5 +202,6 @@ test_files:
201
202
  - test/docs/wrap_test.rb
202
203
  - test/operation/integration_test.rb
203
204
  - test/operation/model_test.rb
205
+ - test/operation/nested_test.rb
204
206
  - test/operation/pundit_test.rb
205
207
  - test/test_helper.rb
data/.travis.yml DELETED
@@ -1,12 +0,0 @@
1
- language: ruby
2
- rvm:
3
- - ruby-head
4
- - 2.7
5
- - 2.6
6
- - 2.5
7
- - 2.4
8
- cache: bundler
9
- jobs:
10
- allow_failures:
11
- - rvm: ruby-head
12
- - rvm: 2.7