trailblazer-macro 2.1.0.rc12 → 2.1.2

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: 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) {