trailblazer-macro 2.1.0.rc12 → 2.1.2

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: f5ce55419b3272e247bb23453c3eda1543ad0de9b7308e173fc7532ed0b3c837
4
- data.tar.gz: da8e59a55b392c9220ba8038ce809d52136ee712a4f31489172176a01ef117a5
3
+ metadata.gz: 40b0e15f1f350730e29523549e1093931d345d118f24dfc186e201d92e674f4a
4
+ data.tar.gz: 07d680040a3404a155636a8998321684609ce3bdee9988ac43dafd163d96d2eb
5
5
  SHA512:
6
- metadata.gz: e871c4cf8f7e11af5339a40493b7175919b3c965bc1fbeefa925f41f17d8a89e936fdc39e688725f30115370539c8fcc5cee9f5a3c69f4e411b9a1002ea63a87
7
- data.tar.gz: cd97aa45a6d27af7f4f60e4ab34f80a235a73338188d7e27a48e2a12bcbc693ea1534f4075f95ceaef7918b9f5cebc0e87320bd3f69dd130b5bad814bef080e1
6
+ metadata.gz: c61f315deeed6243a45810a92ebfd11d4f832e86de66b7e7d6896bcc8cb5cd7bc0eb9f76985e8f632e6986c03696ad8a4ca96dd92504c05f11519abb8577e89e
7
+ data.tar.gz: 3c8ca095a7bf17d821d1209817604bd1416d04a8c7aff6ddc967a89248781c6fee9356db7333e1a64d7955f211b853b8b1de7a6f56a6656327bf5258b57bc149
@@ -1,11 +1,9 @@
1
- sudo: false
2
1
  language: ruby
3
2
  rvm:
4
- - 2.6.2
3
+ - 2.6.5
5
4
  - 2.5.5
6
5
  - 2.4.4
7
6
  - 2.3.7
8
7
  - 2.2
9
- - 2.1
10
8
 
11
9
  cache: bundler
data/CHANGES.md CHANGED
@@ -1,3 +1,25 @@
1
+ # 2.1.2
2
+
3
+ * Fix to make macros available in all Linear::DSL strategies.
4
+ * Make `params` optional in `Model`.
5
+ * Support for adding `End.not_found` end in `Model`.
6
+
7
+ # 2.1.1
8
+
9
+ * Fix case when Macros generate same id due to small entropy
10
+
11
+ # 2.1.0
12
+
13
+ * Finally.
14
+
15
+ # 2.1.0.rc14
16
+
17
+ * Remove the explicit `dsl-linear` dependency.
18
+
19
+ # 2.1.0.rc13
20
+
21
+ * Use symbol keys on `ctx`, only.
22
+
1
23
  # 2.1.0.rc12
2
24
 
3
25
  * Dependency bumps.
data/LICENSE ADDED
@@ -0,0 +1,9 @@
1
+ Copyright (c) 2018 Trailblazer GmbH
2
+
3
+ Trailblazer is an Open Source project licensed under the terms of
4
+ the LGPLv3 license. Please see <http://www.gnu.org/licenses/lgpl-3.0.html>
5
+ for license text.
6
+
7
+ Trailblazer PRO has a commercial-friendly license allowing private forks
8
+ and modifications of Trailblazer. Please see http://trailblazer.to/pro for
9
+ more detail.
@@ -1,5 +1,6 @@
1
+ require "forwardable"
1
2
  require "trailblazer/activity"
2
- require "trailblazer/activity/dsl/linear" # TODO: remove this dependency
3
+ require "trailblazer/activity/dsl/linear"
3
4
  require "trailblazer/operation" # TODO: remove this dependency
4
5
 
5
6
  require "trailblazer/macro/model"
@@ -12,18 +13,16 @@ require "trailblazer/macro/wrap"
12
13
 
13
14
  module Trailblazer
14
15
  module Macro
15
- # All macros sit in the {Trailblazer::Macro} namespace, where we forward calls from
16
- # operations and activities to.
17
- def self.forward_macros(target)
18
- target.singleton_class.def_delegators Trailblazer::Macro, :Model, :Wrap, :Rescue, :Nested
19
- target.const_set(:Policy, Trailblazer::Macro::Policy)
20
- end
21
16
  end
22
- end
23
17
 
24
- # TODO: Forwardable.def_delegators(Operation, Macro, :Model, :Wrap) would be amazing. It really sucks to extend a foreign class.
25
- # Trailblazer::Operation.singleton_class.extend Forwardable
26
- # Trailblazer::Macro.forward_macros(Trailblazer::Operation)
18
+ # All macros sit in the {Trailblazer::Macro} namespace, where we forward calls from
19
+ # operations and activities to.
20
+ module Activity::DSL::Linear::Helper
21
+ Policy = Trailblazer::Macro::Policy
27
22
 
28
- Trailblazer::Activity::FastTrack.singleton_class.extend Forwardable
29
- Trailblazer::Macro.forward_macros(Trailblazer::Activity::FastTrack) # monkey-patching sucks.
23
+ module ClassMethods
24
+ extend Forwardable
25
+ def_delegators Trailblazer::Macro, :Model, :Nested, :Wrap, :Rescue
26
+ end # ClassMethods
27
+ end # Helper
28
+ end
@@ -1,33 +1,39 @@
1
1
  module Trailblazer::Macro
2
- def self.Model(model_class, action = nil, find_by_key = nil)
2
+
3
+ Linear = Trailblazer::Activity::DSL::Linear
4
+
5
+ def self.Model(model_class, action = nil, find_by_key = nil, id: 'model.build', not_found_end: false)
3
6
  task = Trailblazer::Activity::TaskBuilder::Binary(Model.new)
4
7
 
5
8
  injection = Trailblazer::Activity::TaskWrap::Inject::Defaults::Extension(
6
- "model.class" => model_class,
7
- "model.action" => action,
8
- "model.find_by_key" => find_by_key
9
+ :"model.class" => model_class,
10
+ :"model.action" => action,
11
+ :"model.find_by_key" => find_by_key
9
12
  )
10
13
 
11
- {task: task, id: "model.build", extensions: [injection]}
14
+ options = { task: task, id: id, extensions: [injection] }
15
+ options = options.merge(Linear::Output(:failure) => Linear::End(:not_found)) if not_found_end
16
+
17
+ options
12
18
  end
13
19
 
14
20
  class Model
15
- def call(options, params:, **)
21
+ def call(options, params: nil, **)
16
22
  builder = Model::Builder.new
17
23
  options[:model] = model = builder.call(options, params)
18
- options["result.model"] = result = Trailblazer::Operation::Result.new(!model.nil?, {})
24
+ options[:"result.model"] = result = Trailblazer::Operation::Result.new(!model.nil?, {})
19
25
 
20
26
  result.success?
21
27
  end
22
28
 
23
29
  class Builder
24
30
  def call(options, params)
25
- action = options["model.action"] || :new
26
- model_class = options["model.class"]
27
- find_by_key = options["model.find_by_key"] || :id
31
+ action = options[:"model.action"] || :new
32
+ model_class = options[:"model.class"]
33
+ find_by_key = options[:"model.find_by_key"] || :id
28
34
  action = :pass_through unless %i[new find_by].include?(action)
29
35
 
30
- send("#{action}!", model_class, params, options["model.action"], find_by_key)
36
+ send("#{action}!", model_class, params, options[:"model.action"], find_by_key)
31
37
  end
32
38
 
33
39
  def new!(model_class, params, *)
@@ -14,8 +14,8 @@ module Trailblazer::Macro
14
14
  condition = options[@path] # this allows dependency injection.
15
15
  result = condition.([options, flow_options], **circuit_options)
16
16
 
17
- options["policy.#{@name}"] = result["policy"] # assign the policy as a skill.
18
- options["result.policy.#{@name}"] = result
17
+ options[:"policy.#{@name}"] = result[:policy] # assign the policy as a skill.
18
+ options[:"result.policy.#{@name}"] = result
19
19
 
20
20
  # flow control
21
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.
@@ -28,7 +28,7 @@ module Trailblazer::Macro
28
28
  # policy-compatible object at runtime.
29
29
  def self.step(condition, options, &block)
30
30
  name = options[:name]
31
- path = "policy.#{name}.eval"
31
+ path = :"policy.#{name}.eval"
32
32
 
33
33
  task = Eval.new(name: name, path: path)
34
34
 
@@ -27,8 +27,8 @@ module Trailblazer::Macro
27
27
  end
28
28
 
29
29
  def result!(success, policy)
30
- data = {"policy" => policy}
31
- data["message"] = "Breach" if !success # TODO: how to allow messages here?
30
+ data = { policy: policy }
31
+ data[:message] = "Breach" if !success # TODO: how to allow messages here?
32
32
 
33
33
  Trailblazer::Operation::Result.new(success, data)
34
34
  end
@@ -20,7 +20,7 @@ module Trailblazer
20
20
  end
21
21
  end
22
22
 
23
- Wrap(rescue_block, id: "Rescue(#{rand(100)})", &block)
23
+ Wrap(rescue_block, id: "Rescue(#{SecureRandom.hex(4)})", &block)
24
24
  # FIXME: name
25
25
  # [ step, name: "Rescue:#{block.source_location.last}" ]
26
26
  end
@@ -1,7 +1,7 @@
1
1
  module Trailblazer
2
2
  module Version
3
3
  module Macro
4
- VERSION = "2.1.0.rc12".freeze
4
+ VERSION = "2.1.2"
5
5
  end
6
6
  end
7
7
  end
@@ -1,6 +1,8 @@
1
+ require 'securerandom'
2
+
1
3
  module Trailblazer
2
4
  module Macro
3
- def self.Wrap(user_wrap, id: "Wrap/#{rand(100)}", &block)
5
+ def self.Wrap(user_wrap, id: "Wrap/#{SecureRandom.hex(4)}", &block)
4
6
  activity = Class.new(Activity::FastTrack, &block) # This is currently coupled to {dsl-linear}.
5
7
 
6
8
  outputs = activity.to_h[:outputs]
@@ -6,22 +6,22 @@ class DocsGuardProcTest < Minitest::Spec
6
6
  #:proc
7
7
  class Create < Trailblazer::Operation
8
8
  step Policy::Guard(->(options, pass:, **) { pass })
9
- #~pipeonly
9
+ #:pipeonly
10
10
  step :process
11
11
 
12
12
  def process(options, **)
13
- options["x"] = true
13
+ options[:x] = true
14
14
  end
15
- #~pipeonly end
15
+ #:pipeonly end
16
16
  end
17
17
  #:proc end
18
18
 
19
- it { Create.(pass: false)["x"].must_be_nil }
20
- it { Create.(pass: true)["x"].must_equal true }
19
+ it { Create.(pass: false)[:x].must_be_nil }
20
+ it { Create.(pass: true)[:x].must_equal true }
21
21
 
22
22
  #- result object, guard
23
- it { Create.(pass: true)["result.policy.default"].success?.must_equal true }
24
- it { Create.(pass: false)["result.policy.default"].success?.must_equal false }
23
+ it { Create.(pass: true)[:"result.policy.default"].success?.must_equal true }
24
+ it { Create.(pass: false)[:"result.policy.default"].success?.must_equal false }
25
25
 
26
26
  #---
27
27
  #- Guard inheritance
@@ -46,13 +46,15 @@ class DocsGuardTest < Minitest::Spec
46
46
  #:callable-op
47
47
  class Create < Trailblazer::Operation
48
48
  step Policy::Guard( MyGuard.new )
49
- #~pipe-only
49
+ #:pipe-only
50
50
  step :process
51
51
 
52
+ #~methods
52
53
  def process(options, **)
53
54
  options[:x] = true
54
55
  end
55
- #~pipe-only end
56
+ #~methods end
57
+ #:pipe-only end
56
58
  end
57
59
  #:callable-op end
58
60
 
@@ -72,16 +74,17 @@ class DocsGuardMethodTest < Minitest::Spec
72
74
  end
73
75
  #~pipe-onlyy
74
76
  step :process
75
-
77
+ #~methods
76
78
  def process(options, **)
77
- options["x"] = true
79
+ options[:x] = true
78
80
  end
81
+ #~methods end
79
82
  #~pipe-onlyy end
80
83
  end
81
84
  #:method end
82
85
 
83
- it { Create.(pass: false).inspect("x").must_equal %{<Result:false [nil] >} }
84
- it { Create.(pass: true).inspect("x").must_equal %{<Result:true [true] >} }
86
+ it { Create.(pass: false).inspect(:x).must_equal %{<Result:false [nil] >} }
87
+ it { Create.(pass: true).inspect(:x).must_equal %{<Result:true [true] >} }
85
88
  end
86
89
 
87
90
  #---
@@ -94,13 +97,13 @@ class DocsGuardNamedTest < Minitest::Spec
94
97
  end
95
98
  #:name end
96
99
 
97
- it { Create.(:current_user => nil )["result.policy.user"].success?.must_equal false }
98
- it { Create.(:current_user => Module)["result.policy.user"].success?.must_equal true }
100
+ it { Create.(:current_user => nil )[:"result.policy.user"].success?.must_equal false }
101
+ it { Create.(:current_user => Module)[:"result.policy.user"].success?.must_equal true }
99
102
 
100
103
  it {
101
104
  #:name-result
102
105
  result = Create.(:current_user => true)
103
- result["result.policy.user"].success? #=> true
106
+ result[:"result.policy.user"].success? #=> true
104
107
  #:name-result end
105
108
  }
106
109
  end
@@ -123,7 +126,7 @@ class DocsGuardInjectionTest < Minitest::Spec
123
126
  Create.(
124
127
  {},
125
128
  :current_user => Module,
126
- "policy.default.eval" => Trailblazer::Operation::Policy::Guard.build(->(options, **) { false })
129
+ :"policy.default.eval" => Trailblazer::Operation::Policy::Guard.build(->(options, **) { false })
127
130
  )
128
131
  #:di-call end
129
132
  result.inspect("").must_equal %{<Result:false [nil] >} }
@@ -45,6 +45,13 @@ class DocsModelTest < Minitest::Spec
45
45
  end
46
46
  #:update-with-find-by-key end
47
47
 
48
+ #:update-with-not-found-end
49
+ class UpdateFailureWithModelNotFound < Trailblazer::Operation
50
+ step Model( Song, :find_by, not_found_end: true )
51
+ # ..
52
+ end
53
+ #:update-with-not-found-end end
54
+
48
55
  it do
49
56
  #:update-ok
50
57
  result = Update.(params: { id: 1 })
@@ -83,6 +90,19 @@ class DocsModelTest < Minitest::Spec
83
90
  result.success?.must_equal false
84
91
  end
85
92
 
93
+ it do
94
+ #:update-with-not-found-end-use
95
+ result = UpdateFailureWithModelNotFound.(params: {title: nil})
96
+ result[:model] #=> nil
97
+ result.success? #=> false
98
+ result.event #=> #<Trailblazer::Activity::End semantic=:not_found>
99
+ #:update-with-not-found-end-use end
100
+
101
+ result[:model].must_be_nil
102
+ result.success?.must_equal false
103
+ result.event.inspect.must_equal %{#<Trailblazer::Activity::End semantic=:not_found>}
104
+ end
105
+
86
106
  #:show
87
107
  class Show < Trailblazer::Operation
88
108
  step Model( Song, :[] )
@@ -16,22 +16,33 @@ class NestedInput < Minitest::Spec
16
16
  end
17
17
  end
18
18
 
19
- it "Nested(Edit), without any options" do
20
- edit = self.edit
21
-
22
- create = Class.new(Trailblazer::Operation) do
23
- step :a
24
- step Nested( edit )
25
- step :b
26
-
27
- include T.def_steps(:a, :b)
28
- end
19
+ class Validate < Trailblazer::Operation
20
+ step :validate
21
+ # ... more steps ...
22
+ include T.def_steps(:validate)
23
+ end
29
24
 
30
- # this will print a DEPRECATION warning.
31
- # success
32
- create.(seq: []).inspect(:seq).must_equal %{<Result:true [[:a, :c, :b]] >}
33
- # failure in Nested
34
- create.(seq: [], c: false).inspect(:seq).must_equal %{<Result:false [[:a, :c]] >}
25
+ it "Nested(Edit), without any options" do
26
+ module A
27
+
28
+ create =
29
+ #:nested
30
+ class Create < Trailblazer::Operation
31
+ step :create
32
+ step Nested(Validate)
33
+ step :save
34
+ #~meths
35
+ include T.def_steps(:create, :save)
36
+ #~meths end
37
+ end
38
+ #:nested end
39
+
40
+ # this will print a DEPRECATION warning.
41
+ # success
42
+ create.(seq: []).inspect(:seq).must_equal %{<Result:true [[:create, :validate, :save]] >}
43
+ # failure in Nested
44
+ create.(seq: [], validate: false).inspect(:seq).must_equal %{<Result:false [[:create, :validate]] >}
45
+ end
35
46
  end
36
47
 
37
48
  it "Nested(Edit), with Output rewiring" do
@@ -52,32 +63,102 @@ class NestedInput < Minitest::Spec
52
63
  end
53
64
 
54
65
  it "Nested(:method)" do
55
- create = Class.new(Trailblazer::Operation) do
56
- step :a
57
- step Nested(:compute_edit)
58
- step :b
59
-
60
- def compute_edit(ctx, what:, **)
61
- what
66
+ module B
67
+ create =
68
+ #:nested-dynamic
69
+ class Create < Trailblazer::Operation
70
+ step :create
71
+ step Nested(:compute_nested)
72
+ step :save
73
+
74
+ def compute_nested(ctx, params:, **)
75
+ params.is_a?(Hash) ? Validate : JsonValidate
76
+ end
77
+ #~meths
78
+ include T.def_steps(:create, :save)
79
+ #~meths end
62
80
  end
81
+ #:nested-dynamic end
63
82
 
64
- include T.def_steps(:a, :b)
65
- end
66
-
83
+ class JsonValidate < Validate
84
+ step :json
85
+ include T.def_steps(:json)
86
+ end
67
87
  # `edit` and `update` can be called from Nested()
68
88
 
69
89
  # edit/success
70
- create.(seq: [], what: edit).inspect(:seq).must_equal %{<Result:true [[:a, :c, :b]] >}
90
+ create.(seq: [], params: {}).inspect(:seq).must_equal %{<Result:true [[:create, :validate, :save]] >}
71
91
 
72
92
  # update/success
73
- create.(seq: [], what: update).inspect(:seq).must_equal %{<Result:true [[:a, :d, :b]] >}
93
+ create.(seq: [], params: nil).inspect(:seq).must_equal %{<Result:true [[:create, :validate, :json, :save]] >}
74
94
 
75
95
 
76
96
  # wiring of fail:
77
97
  # edit/failure
78
- create.(seq: [], what: edit, c: false).inspect(:seq).must_equal %{<Result:false [[:a, :c]] >}
98
+ create.(seq: [], params: {}, validate: false).inspect(:seq).must_equal %{<Result:false [[:create, :validate]] >}
79
99
  # update/failure
80
- create.(seq: [], what: update, d: false).inspect(:seq).must_equal %{<Result:false [[:a, :d]] >}
100
+ create.(seq: [], params: nil, json: false).inspect(:seq).must_equal %{<Result:false [[:create, :validate, :json]] >}
101
+ end
102
+ end
103
+
104
+ it "Nested(:method), input: :my_input" do
105
+ module C
106
+ #:nested-dynamic
107
+ class Create < Trailblazer::Operation
108
+ step :create
109
+ step Nested(:compute_nested), input: ->(ctx, *) {{foo: :bar, seq: ctx[:seq]}}
110
+ step :save
111
+
112
+ def compute_nested(ctx, params:, **)
113
+ params.is_a?(Hash) ? Validate : JsonValidate
114
+ end
115
+
116
+ #~meths
117
+ include T.def_steps(:create, :save)
118
+ #~meths end
119
+ end
120
+ #:nested-dynamic end
121
+
122
+ class JsonValidate < Validate
123
+ step :json
124
+ include T.def_steps(:json)
125
+ end
126
+
127
+ # `edit` and `update` can be called from Nested()
128
+ end
129
+
130
+ C::Create.(seq: [], params: {}).inspect(:seq).must_equal %{<Result:true [[:create, :validate, :save]] >}
131
+ C::Create.(seq: [], params: nil).inspect(:seq).must_equal %{<Result:true [[:create, :validate, :json, :save]] >}
132
+ end
133
+
134
+ it "Nested(:method), with pass_fast returned from nested" do
135
+ class JustPassFast < Trailblazer::Operation
136
+ step :just_pass_fast, pass_fast: true
137
+ include T.def_steps(:just_pass_fast)
138
+ end
139
+
140
+ module D
141
+
142
+ create =
143
+ #:nested-with-pass-fast
144
+ class Create < Trailblazer::Operation
145
+
146
+ def compute_nested(ctx, **)
147
+ JustPassFast
148
+ end
149
+
150
+ step :create
151
+ step Nested(:compute_nested)
152
+ step :save
153
+ #~meths
154
+ include T.def_steps(:create, :save)
155
+ #~meths end
156
+ end
157
+ #:nested-with-pass-fast end
158
+
159
+ # pass fast
160
+ create.(seq: []).inspect(:seq).must_equal %{<Result:true [[:create, :just_pass_fast, :save]] >}
161
+ end
81
162
  end
82
163
 
83
164
  let(:compute_edit) {