trailblazer 2.0.3 → 2.0.4

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
  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.