trailblazer 2.0.3 → 2.0.4

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
  SHA1:
3
- metadata.gz: a1f0c47cf26109508aa2f58b38a69f0a4b5f9b07
4
- data.tar.gz: 98cddf35489a1ea61a95e01237d459682d9ab3df
3
+ metadata.gz: c715d450be489fd1d47e0e9543044dbecc683db8
4
+ data.tar.gz: 3212afa6969b12ed86cab5b73cb43a84ffa56ac0
5
5
  SHA512:
6
- metadata.gz: 60ef0796bcfa0c12255595c47b514f4a0cbfbac1d90091172459cd4a23b7250d444bff6ecb90d74504c216bebca893bab5cfbe6643d9779ecddd0f7bfc093f2f
7
- data.tar.gz: 212e3134780b3146cd25e713b5b83beadd4219f291a772e31cdcb766b745fd334ec765b01f70b085c9fa999ca0e062ae7cff88064a86b65139e73d257241f2d2
6
+ metadata.gz: 7ff9d994e6c2176ed8dd418ed49fd9214edb7251c44251b6a1afaa93803063bf599f10f0f08b2e726ec69d979e550bee18567e73ffdb822210db93744d2689b4
7
+ data.tar.gz: 4f7a37983d925bd4e6c8722422aa97d067a1dec4ba11c3018c4887d9b5ec8e2fab57aed6ce6a062ad4a0ea2713dbfdd15fda98401343e0c7e5d934783e3abf24
data/CHANGES.md CHANGED
@@ -1,9 +1,13 @@
1
+ # 2.0.4
2
+
3
+ * When using `Nested(X)`, the automatic `:name` option is now `"Nested(X)"` instead of the cryptic proc string.
4
+
1
5
  # 2.0.3
2
6
 
3
7
  * `Guard` now allows kw args for its option.
4
8
  * Fix a bug where `Nested( ->{} )` wouldn't `_call` the nested operation and did too much work on re-nested the already nested params. Thanks to @eliranf for spotting this.
5
9
  * Add `Nested(..., input: )` to dynamically decide the input to the nested operation. http://trailblazer.to/gems/operation/2.0/api.html#nested-input
6
- * Add `Nested(..., output: )`: http://localhost:4000/gems/operation/2.0/api.html#nested-output
10
+ * Add `Nested(..., output: )`: http://trailblazer.to/gems/operation/2.0/api.html#nested-output
7
11
 
8
12
  # 2.0.2
9
13
 
data/Gemfile CHANGED
@@ -9,7 +9,7 @@ gemspec
9
9
  gem "reform-rails"
10
10
  gem "activesupport", "~> 4.2.0"
11
11
 
12
- gem "roar", github: "apotonick/roar"
12
+ # gem "roar", github: "apotonick/roar"
13
13
  # gem "reform", "~> 2.0.0"
14
14
  gem "reform"#, path: "../reform"
15
15
  # gem "roar", path: "../roar"
@@ -1,8 +1,8 @@
1
1
  class Trailblazer::Operation
2
- def self.Nested(step, input:nil, output:nil)
3
- step = Nested.for(step, input, output)
2
+ def self.Nested(callable, input:nil, output:nil)
3
+ step = Nested.for(callable, input, output)
4
4
 
5
- [ step, { name: "Nested(#{step})" } ]
5
+ [ step, { name: "Nested(#{callable})" } ]
6
6
  end
7
7
 
8
8
  # WARNING: this is experimental API, but it will end up with something like that.
@@ -22,9 +22,10 @@ class Trailblazer::Operation
22
22
  module Nested
23
23
  # Please note that the instance_variable_get are here on purpose since the
24
24
  # superinternal API is not entirely decided, yet.
25
- def self.for(step, input, output) # DISCUSS: use builders here?
25
+ # @api private
26
+ def self.for(step, input, output, is_nestable_object=method(:nestable_object?)) # DISCUSS: use builders here?
26
27
  invoker = Caller::Dynamic.new(step)
27
- invoker = Caller.new(step) if step.is_a?(Class) && step <= Trailblazer::Operation # interestingly, with < we get a weird nil exception. bug in Ruby?
28
+ invoker = Caller.new(step) if is_nestable_object.(step)
28
29
 
29
30
  options_for_nested = Options.new
30
31
  options_for_nested = Options::Dynamic.new(input) if input
@@ -42,6 +43,11 @@ class Trailblazer::Operation
42
43
  end
43
44
  end
44
45
 
46
+ def self.nestable_object?(object)
47
+ # interestingly, with < we get a weird nil exception. bug in Ruby?
48
+ object.is_a?(Class) && object <= Trailblazer::Operation
49
+ end
50
+
45
51
  # Is executed at runtime and calls the nested operation.
46
52
  class Caller
47
53
  include Element
@@ -1,5 +1,5 @@
1
1
  class Trailblazer::Operation
2
- def self.Rescue(*exceptions, handler: Rescue::Noop, &block)
2
+ def self.Rescue(*exceptions, handler: lambda { |*| }, &block)
3
3
  exceptions = [StandardError] unless exceptions.any?
4
4
  handler = Option.(handler)
5
5
 
@@ -17,9 +17,5 @@ class Trailblazer::Operation
17
17
 
18
18
  [ step, name: "Rescue:#{block.source_location.last}" ]
19
19
  end
20
-
21
- module Rescue
22
- Noop = ->(*) {}
23
- end
24
20
  end
25
21
 
@@ -0,0 +1,17 @@
1
+ module Trailblazer
2
+ module Test
3
+ module Run
4
+ # DISCUSS: use Endpoint here?
5
+ # DISCUSS: use Controller code here?
6
+ module_function
7
+ def run(operation_class, *args)
8
+ result = operation_class.(*args)
9
+
10
+ raise "[Trailblazer] #{operation_class} wasn't run successfully. #{result.inspect}" if result.failure?
11
+
12
+ result
13
+
14
+ end
15
+ end
16
+ end
17
+ end
@@ -1,3 +1,3 @@
1
1
  module Trailblazer
2
- VERSION = "2.0.3"
2
+ VERSION = "2.0.4"
3
3
  end
@@ -4,7 +4,7 @@ class DocsContractOverviewTest < Minitest::Spec
4
4
  Song = Struct.new(:length, :title)
5
5
 
6
6
  #:overv-reform
7
- # app/concepts/comment/create.rb
7
+ # app/concepts/song/create.rb
8
8
  class Create < Trailblazer::Operation
9
9
  #~bla
10
10
  extend Contract::DSL
@@ -126,29 +126,6 @@ class DocsContractExplicitTest < Minitest::Spec
126
126
  #:reform-inline-op end
127
127
  end
128
128
 
129
- #---
130
- #- Validate[key: :song]
131
- class DocsContractKeyTest < Minitest::Spec
132
- Song = Struct.new(:id, :title)
133
- #:key
134
- class Create < Trailblazer::Operation
135
- extend Contract::DSL
136
-
137
- contract do
138
- property :title
139
- end
140
-
141
- step Model( Song, :new )
142
- step Contract::Build()
143
- step Contract::Validate( key: "song" )
144
- step Contract::Persist( method: :sync )
145
- end
146
- #:key end
147
-
148
- it { Create.({}).inspect("model", "result.contract.default.extract").must_equal %{<Result:false [#<struct DocsContractKeyTest::Song id=nil, title=nil>, nil] >} }
149
- it { Create.({"song" => { title: "SVG" }}).inspect("model").must_equal %{<Result:true [#<struct DocsContractKeyTest::Song id=nil, title="SVG">] >} }
150
- end
151
-
152
129
  #- Validate with manual key extraction
153
130
  class DocsContractSeparateKeyTest < Minitest::Spec
154
131
  Song = Struct.new(:id, :title)
@@ -181,48 +158,165 @@ class DocsContractSeparateKeyTest < Minitest::Spec
181
158
  end
182
159
 
183
160
  #---
184
- #- Contract::Build[ constant: XXX ]
161
+ #- Contract::Build( constant: XXX )
185
162
  class ContractConstantTest < Minitest::Spec
186
- Song = Struct.new(:id, :title)
187
- #:constant
188
- class Create < Trailblazer::Operation
189
- class MyContract < Reform::Form
190
- property :title
191
- validates :title, length: 2..33
163
+ Song = Struct.new(:title, :length) do
164
+ def save
165
+ true
192
166
  end
167
+ end
193
168
 
169
+ #:constant-contract
170
+ # app/concepts/song/contract/create.rb
171
+ module Song::Contract
172
+ class Create < Reform::Form
173
+ property :title
174
+ property :length
194
175
 
176
+ validates :title, length: 2..33
177
+ validates :length, numericality: true
178
+ end
179
+ end
180
+ #:constant-contract end
195
181
 
182
+ #:constant
183
+ class Song::Create < Trailblazer::Operation
196
184
  step Model( Song, :new )
197
- step Contract::Build( constant: MyContract )
185
+ step Contract::Build( constant: Song::Contract::Create )
198
186
  step Contract::Validate()
199
- step Contract::Persist( method: :sync )
187
+ step Contract::Persist()
200
188
  end
201
189
  #:constant end
202
190
 
203
- it { Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractConstantTest::Song id=nil, title=nil>] >} }
204
- it { Create.({ title: "Anthony's Song" }).inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song id=nil, title="Anthony's Song">] >} }
191
+ it { Song::Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractConstantTest::Song title=nil, length=nil>] >} }
192
+ it { Song::Create.({ title: "Anthony's Song", length: 12 }).inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song title="Anthony's Song", length=12>] >} }
193
+ it do
194
+ #:constant-result
195
+ result = Song::Create.( title: "A" )
196
+ result.success? #=> false
197
+ result["contract.default"].errors.messages
198
+ #=> {:title=>["is too short (minimum is 2 characters)"], :length=>["is not a number"]}
199
+ #:constant-result end
200
+
201
+ #:constant-result-true
202
+ result = Song::Create.( title: "Rising Force", length: 13 )
203
+ result.success? #=> true
204
+ result["model"] #=> #<Song title="Rising Force", length=13>
205
+ #:constant-result-true end
206
+ end
207
+
208
+ #---
209
+ # Song::New
210
+ #:constant-new
211
+ class Song::New < Trailblazer::Operation
212
+ step Model( Song, :new )
213
+ step Contract::Build( constant: Song::Contract::Create )
214
+ end
215
+ #:constant-new end
216
+
217
+ it { Song::New.().inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song title=nil, length=nil>] >} }
218
+ it { Song::New.()["contract.default"].model.inspect.must_equal %{#<struct ContractConstantTest::Song title=nil, length=nil>} }
219
+ it do
220
+ #:constant-new-result
221
+ result = Song::New.()
222
+ result["model"] #=> #<struct Song title=nil, length=nil>
223
+ result["contract.default"]
224
+ #=> #<Song::Contract::Create model=#<struct Song title=nil, length=nil>>
225
+ #:constant-new-result end
226
+ end
227
+
228
+ #---
229
+ #:validate-only
230
+ class Song::ValidateOnly < Trailblazer::Operation
231
+ step Model( Song, :new )
232
+ step Contract::Build( constant: Song::Contract::Create )
233
+ step Contract::Validate()
234
+ end
235
+ #:validate-only end
236
+
237
+ it { Song::ValidateOnly.().inspect("model").must_equal %{<Result:false [#<struct ContractConstantTest::Song title=nil, length=nil>] >} }
238
+ it do
239
+ result = Song::ValidateOnly.({ title: "Rising Forse", length: 13 })
240
+ result.inspect("model").must_equal %{<Result:true [#<struct ContractConstantTest::Song title=nil, length=nil>] >}
241
+ end
242
+
243
+ it do
244
+ #:validate-only-result-false
245
+ result = Song::ValidateOnly.({}) # empty params
246
+ result.success? #=> false
247
+ #:validate-only-result-false end
248
+ end
249
+
250
+ it do
251
+ #:validate-only-result
252
+ result = Song::ValidateOnly.({ title: "Rising Force", length: 13 })
253
+
254
+ result.success? #=> true
255
+ result["model"] #=> #<struct Song title=nil, length=nil>
256
+ result["contract.default"].title #=> "Rising Force"
257
+ #:validate-only-result end
258
+ end
259
+ end
260
+
261
+ #---
262
+ #- Validate( key: :song )
263
+ class DocsContractKeyTest < Minitest::Spec
264
+ Song = Class.new(ContractConstantTest::Song)
265
+
266
+ module Song::Contract
267
+ Create = ContractConstantTest::Song::Contract::Create
268
+ end
269
+
270
+ #:key
271
+ class Song::Create < Trailblazer::Operation
272
+ step Model( Song, :new )
273
+ step Contract::Build( constant: Song::Contract::Create )
274
+ step Contract::Validate( key: "song" )
275
+ step Contract::Persist( )
276
+ end
277
+ #:key end
278
+
279
+ it { Song::Create.({}).inspect("model", "result.contract.default.extract").must_equal %{<Result:false [#<struct DocsContractKeyTest::Song title=nil, length=nil>, nil] >} }
280
+ it { Song::Create.({"song" => { title: "SVG", length: 13 }}).inspect("model").must_equal %{<Result:true [#<struct DocsContractKeyTest::Song title=\"SVG\", length=13>] >} }
281
+ it do
282
+ #:key-res
283
+ result = Song::Create.({ "song" => { title: "Rising Force", length: 13 } })
284
+ result.success? #=> true
285
+ #:key-res end
286
+
287
+ #:key-res-false
288
+ result = Song::Create.({ title: "Rising Force", length: 13 })
289
+ result.success? #=> false
290
+ #:key-res-false end
291
+ end
205
292
  end
206
293
 
207
294
  #- Contract::Build[ constant: XXX, name: AAA ]
208
295
  class ContractNamedConstantTest < Minitest::Spec
209
- Song = Struct.new(:id, :title)
210
- #:constant-name
211
- class Create < Trailblazer::Operation
212
- class MyContract < Reform::Form
213
- property :title
214
- validates :title, length: 2..33
215
- end
296
+ Song = Class.new(ContractConstantTest::Song)
297
+
298
+ module Song::Contract
299
+ Create = ContractConstantTest::Song::Contract::Create
300
+ end
216
301
 
302
+ #:constant-name
303
+ class Song::Create < Trailblazer::Operation
217
304
  step Model( Song, :new )
218
- step Contract::Build( constant: MyContract, name: "form" )
305
+ step Contract::Build( name: "form", constant: Song::Contract::Create )
219
306
  step Contract::Validate( name: "form" )
220
- step Contract::Persist( method: :sync, name: "form" )
307
+ step Contract::Persist( name: "form" )
221
308
  end
222
309
  #:constant-name end
223
310
 
224
- it { Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractNamedConstantTest::Song id=nil, title=nil>] >} }
225
- it { Create.({ title: "Anthony's Song" }).inspect("model").must_equal %{<Result:true [#<struct ContractNamedConstantTest::Song id=nil, title="Anthony's Song">] >} }
311
+ it { Song::Create.({ title: "A" }).inspect("model").must_equal %{<Result:false [#<struct ContractNamedConstantTest::Song title=nil, length=nil>] >} }
312
+ it { Song::Create.({ title: "Anthony's Song", length: 13 }).inspect("model").must_equal %{<Result:true [#<struct ContractNamedConstantTest::Song title="Anthony's Song", length=13>] >} }
313
+
314
+ it do
315
+ #:name-res
316
+ result = Song::Create.({ title: "A" })
317
+ result["contract.form"].errors.messages #=> {:title=>["is too short (minimum is 2 ch...
318
+ #:name-res end
319
+ end
226
320
  end
227
321
 
228
322
  #---
@@ -76,6 +76,7 @@ class DocsNestedOperationTest < Minitest::Spec
76
76
  class B < Trailblazer::Operation
77
77
  success ->(options) { options["can.B.see.it?"] = options["this.should.not.be.visible.in.B"] }
78
78
  success ->(options) { options["can.B.see.current_user?"] = options["current_user"] }
79
+ success ->(options) { options["can.B.see.params?"] = options["params"] }
79
80
  success ->(options) { options["can.B.see.A.class.data?"] = options["A.class.data"] }
80
81
  end
81
82
 
@@ -91,6 +92,7 @@ class DocsNestedOperationTest < Minitest::Spec
91
92
  it { A.()["this.should.not.be.visible.in.B"].must_equal true }
92
93
  # runtime dependencies are visible in B.
93
94
  it { A.({}, "current_user" => Module)["can.B.see.current_user?"].must_equal Module }
95
+ it { A.({ a: 1 })["can.B.see.params?"].must_equal({ a: 1 }) }
94
96
  # class data from A doesn't bleed into B.
95
97
  it { A.()["can.B.see.A.class.data?"].must_equal nil }
96
98
 
@@ -315,3 +317,18 @@ class NestedWithCallableTest < Minitest::Spec
315
317
  end
316
318
 
317
319
  # builder: Nested + deviate to left if nil / skip_track if true
320
+
321
+ #---
322
+ # automatic :name
323
+ class NestedNameTest < Minitest::Spec
324
+ class Create < Trailblazer::Operation
325
+ class Present < Trailblazer::Operation
326
+ # ...
327
+ end
328
+
329
+ step Nested( Present )
330
+ # ...
331
+ end
332
+
333
+ it { Create["pipetree"].inspect.must_equal %{[>operation.new,>Nested(NestedNameTest::Create::Present)]} }
334
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trailblazer
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.3
4
+ version: 2.0.4
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-01-23 00:00:00.000000000 Z
11
+ date: 2017-04-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: trailblazer-operation
@@ -184,6 +184,7 @@ files:
184
184
  - lib/trailblazer/operation/pundit.rb
185
185
  - lib/trailblazer/operation/representer.rb
186
186
  - lib/trailblazer/operation/rescue.rb
187
+ - lib/trailblazer/operation/test.rb
187
188
  - lib/trailblazer/operation/validate.rb
188
189
  - lib/trailblazer/operation/wrap.rb
189
190
  - lib/trailblazer/version.rb
@@ -242,7 +243,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
242
243
  version: '0'
243
244
  requirements: []
244
245
  rubyforge_project:
245
- rubygems_version: 2.6.3
246
+ rubygems_version: 2.5.2
246
247
  signing_key:
247
248
  specification_version: 4
248
249
  summary: A high-level architecture for Ruby and Rails.