trailblazer 1.0.0.rc1 → 1.0.0.rc2

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: 4c67bd17df3cf4afa247418e31cf3747e07ae7f1
4
- data.tar.gz: ceb2f1a7f81c63d82152938607f4c46cb4b075fc
3
+ metadata.gz: 07471cd851403f80b0a26ef761be0ceb009dc745
4
+ data.tar.gz: cad5f9dfb9a3e6ecce4623d4d32bff7688ac62e0
5
5
  SHA512:
6
- metadata.gz: 633a5a70e6b0f362247be2509dd637e234d10135f0d6c1917c81d3646646e12ae5efdaa964468592203f5eabafc274b1620c2d48b6b5870c26551bc92e11f971
7
- data.tar.gz: 6276f20bc9d09a11d8dc313efd964383a04d1e05f77d87eded95e64953c8e854ecdaf0ec5be23f916fbafef0a867bffd6b89fc8b5b73ddd5e41cbddf1d3ef055
6
+ metadata.gz: 7896872cf410a207510668b7589f5e39b45c7d5ae3180682ecd5036745646742ccf1c487a26b7df5407f57ef8c12c94832948d22746472a463ce0a42c7be1594
7
+ data.tar.gz: 35a858f63b046ff83c7f456e043ccefa1f10e52a0e84c5ac967dfeed36987c03fb8c0a909552060363335779080536a59e7d6c82669a07636fd86012ea532762
data/CHANGES.md CHANGED
@@ -3,7 +3,8 @@
3
3
  * `Operation[{..}]` is deprecated in favor of `Operation.({..})`.
4
4
  setup in initialize: when Op.run() with Worker, the policy will be run "delayed" and not with the actual permission set. this will result in many crashing sidekiq workers.
5
5
  * `Operation::CRUD` is now `Operation::Model`.
6
- * `Controller#form` now invokes `#prepopulate!` before rendering the view. Use `#present` if you don't want that.
6
+ * `Controller#form` now invokes `#prepopulate!` before rendering the view.
7
+ * `Controller#present` does not instantiate and assign `@form` anymore.
7
8
 
8
9
  # 0.3.4
9
10
 
data/README.md CHANGED
@@ -317,107 +317,11 @@ end
317
317
 
318
318
  This will simply run `Comment::Create[params]`.
319
319
 
320
- You can pass your own params, too.
321
320
 
322
- ```ruby
323
- def create
324
- run Comment::Create, params.merge({current_user: current_user})
325
- end
326
- ```
327
-
328
- An additional block will be executed _only if_ the operation result is valid.
329
-
330
- ```ruby
331
- def create
332
- run Comment::Create do |op|
333
- return redirect_to(comments_path, notice: op.message)
334
- end
335
- end
336
- ```
337
-
338
- Note that the operation instance is yielded to the block.
339
-
340
- The case of an invalid response can be handled after the block.
341
-
342
- ```ruby
343
- def create
344
- run Comment::Create do |op|
345
- # valid code..
346
- return
347
- end
348
-
349
- render action: :new
350
- end
351
- ```
352
-
353
- Don't forget to `return` from the valid block, otherwise both the valid block _and_ the invalid calls after it will be invoked.
354
-
355
- ### Responding
356
-
357
- Alternatively, you can use Rails' excellent `#respond_with` to let a responder take care of what to render. Operations can be passed into `respond_with`. This happens automatically in `#respond`, the third way to let Trailblazer invoke an operation.
358
-
359
- ```ruby
360
- def create
361
- respond Comment::Create
362
- end
363
- ```
364
-
365
- This will simply run the operation and chuck the instance into the responder letting the latter sort out what to render or where to redirect. The operation delegates respective calls to its internal `model`.
366
-
367
- `#respond` will accept options to be passed on to `respond_with`, too
368
321
 
369
- ```ruby
370
- respond Comment::Create, params, location: brandnew_comments_path
371
- ```
372
-
373
- You can also handle different formats in that block. It is totally fine to do that in the controller as this is _endpoint_ logic that is HTTP-specific and not business.
374
-
375
- ```ruby
376
- def create
377
- respond Comment::Create do |op, formats|
378
- formats.html { redirect_to(op.model, :notice => op.valid? ? "All good!" : "Fail!") }
379
- formats.json { render nothing: true }
380
- end
381
- end
382
- ```
383
-
384
- The block passed to `#respond` is _always_ executed, regardless of the operation's validity result. Goal is to let the responder handle the validity of the operation.
385
-
386
- The `formats` object is simply passed on to `#respond_with`.
387
-
388
- ### Presenting
389
-
390
- For `#show` actions that simply present the model using a HTML page or a JSON or XML document the `#present` method comes in handy.
391
-
392
- ```ruby
393
- def show
394
- present Comment::Update
395
- end
396
- ```
397
-
398
- Again, this will only run the operation's setup and provide the model in `@model`. You can then use a cell or controller view for HTML to present the model.
399
-
400
- For document-based APIs and request types that are not HTTP the operation will be advised to render the JSON or XML document using the operation's representer.
401
-
402
- Note that `#present` will leave rendering up to you - `respond_to` is _not_ called.
403
-
404
-
405
- In all three cases the following instance variables are assigned: `@operation`, `@form`, `@model`.
406
-
407
- Named instance variables can be included, too. This is documented [here](#named-controller-instance-variables).
408
322
 
409
323
 
410
- ### Different Request Formats
411
-
412
- In case you have document-API operations that use representers to deserialize the incoming JSON or XML: You can configure the controller to pass the original request body into the operation via `params["comment"]` - instead of the pre-parsed hash from Rails.
413
-
414
- You need to configure this in the controller.
415
-
416
- ```ruby
417
- class CommentsController < ApplicationController
418
- operation document_formats: :json
419
- ```
420
-
324
+ ----
421
325
 
422
326
  It's up to the operation's builder to decide which class to instantiate.
423
327
 
@@ -44,9 +44,9 @@ module Trailblazer
44
44
  call(*args)
45
45
  end
46
46
 
47
- # Runs #setup! and returns the form object.
47
+ # Runs #setup! but doesn't process the operation.
48
48
  def present(params)
49
- build_operation(params).present
49
+ build_operation(params)
50
50
  end
51
51
 
52
52
  # This is a DSL method. Use ::contract_class and ::contract_class= for the explicit version.
@@ -78,11 +78,6 @@ module Trailblazer
78
78
  [valid?, self]
79
79
  end
80
80
 
81
- def present
82
- contract!
83
- self
84
- end
85
-
86
81
  attr_reader :model
87
82
 
88
83
  def errors
@@ -3,7 +3,7 @@ require "trailblazer/endpoint"
3
3
  module Trailblazer::Operation::Controller
4
4
  private
5
5
  def form(*args)
6
- present(*args).tap do |op|
6
+ operation!(*args).tap do |op|
7
7
  op.contract.prepopulate! # equals to @form.prepopulate!
8
8
  end
9
9
  end
@@ -11,18 +11,17 @@ private
11
11
  # Provides the operation instance, model and contract without running #process.
12
12
  # Returns the operation.
13
13
  def present(operation_class, params=self.params)
14
- res, op = operation!(operation_class, params) { [true, operation_class.present(params)] }
15
- op
14
+ operation!(operation_class, params, skip_form: true)
16
15
  end
17
16
 
18
17
  def collection(*args)
19
- present(*args).tap do |op|
18
+ operation!(*args).tap do |op|
20
19
  @collection = op.model
21
20
  end
22
21
  end
23
22
 
24
23
  def run(operation_class, params=self.params, &block)
25
- res, op = operation!(operation_class, params) { operation_class.run(params) }
24
+ res, op = operation_for!(operation_class, params) { operation_class.run(params) }
26
25
 
27
26
  yield op if res and block_given?
28
27
 
@@ -31,7 +30,7 @@ private
31
30
 
32
31
  # The block passed to #respond is always run, regardless of the validity result.
33
32
  def respond(operation_class, options={}, params=self.params, &block)
34
- res, op = operation!(operation_class, params, options) { operation_class.run(params) }
33
+ res, op = operation_for!(operation_class, params, options) { operation_class.run(params) }
35
34
  namespace = options.delete(:namespace) || []
36
35
 
37
36
  return respond_with *namespace, op, options if not block_given?
@@ -39,26 +38,30 @@ private
39
38
  end
40
39
 
41
40
  private
41
+ def operation!(operation_class, params=self.params, options={}) # or #model or #setup.
42
+ res, op = operation_for!(operation_class, params, options) { [true, operation_class.present(params)] }
43
+ op
44
+ end
42
45
 
43
46
  def process_params!(params)
44
47
  end
45
48
 
46
49
  # Normalizes parameters and invokes the operation (including its builders).
47
- def operation!(operation_class, params, options={}, &block)
50
+ def operation_for!(operation_class, params, options={}, &block)
48
51
  # Per default, only treat :html as non-document.
49
52
  options[:is_document] ||= request.format == :html ? false : true
50
53
 
51
54
  process_params!(params)
52
55
  res, op = Trailblazer::Endpoint.new(operation_class, params, request, options).(&block)
53
- setup_operation_instance_variables!(op)
56
+ setup_operation_instance_variables!(op, options)
54
57
 
55
58
  [res, op]
56
59
  end
57
60
 
58
- def setup_operation_instance_variables!(operation)
61
+ def setup_operation_instance_variables!(operation, options)
59
62
  @operation = operation
60
- @form = operation.contract
61
63
  @model = operation.model
64
+ @form = operation.contract unless options[:skip_form]
62
65
  end
63
66
 
64
67
 
@@ -1,7 +1,7 @@
1
1
  # Assigns an additional instance variable for +@model+ named after the model's table name (e.g. @comment).
2
2
  module Trailblazer::Operation::Controller::ActiveRecord
3
3
  private
4
- def setup_operation_instance_variables!(operation)
4
+ def setup_operation_instance_variables!(operation, options)
5
5
  super
6
6
  instance_variable_set(:"@#{operation_model_name}", @model)
7
7
  end
@@ -1,3 +1,3 @@
1
1
  module Trailblazer
2
- VERSION = "1.0.0.rc1"
2
+ VERSION = "1.0.0.rc2"
3
3
  end
@@ -118,19 +118,29 @@ class OperationRunTest < MiniTest::Spec
118
118
 
119
119
  # # Operation#contract returns @contract
120
120
  it { Operation.("yes, true").contract.class.to_s.must_equal "OperationRunTest::Operation::Contract" }
121
- end
122
121
 
123
122
 
124
- class OperationTest < MiniTest::Spec
125
- class Operation < Trailblazer::Operation
126
- def process(params)
127
- validate(Object, params)
123
+
124
+
125
+ describe "::present" do
126
+ class NoContractOp < Trailblazer::Operation
127
+ self.contract_class = nil
128
+
129
+ def model!(*)
130
+ Object
131
+ end
128
132
  end
133
+
134
+ # the operation and model are available, but no contract.
135
+ it { NoContractOp.present({}).model.must_equal Object }
136
+ # no contract is built.
137
+ it { assert_raises(NoMethodError) { NoContractOp.present({}).contract } }
138
+ it { assert_raises(NoMethodError) { NoContractOp.run({}) } }
129
139
  end
140
+ end
130
141
 
131
- # contract is retrieved from ::contract_class.
132
- it { assert_raises(NoMethodError) { Operation.run({}) } } # TODO: if you call #validate without defining a contract, the error is quite cryptic.
133
142
 
143
+ class OperationTest < MiniTest::Spec
134
144
  # test #invalid!
135
145
  class OperationWithoutValidateCall < Trailblazer::Operation
136
146
  def process(params)
@@ -199,17 +209,6 @@ class OperationTest < MiniTest::Spec
199
209
 
200
210
 
201
211
 
202
-
203
- # unlimited arguments for ::run and friends.
204
- # class OperationReceivingLottaArguments < Trailblazer::Operation
205
- # def process(model, params)
206
- # @model = [model, params]
207
- # end
208
- # include Inspect
209
- # end
210
-
211
- # it { OperationReceivingLottaArguments.run(Object, {}).to_s.must_equal %{[true, <OperationReceivingLottaArguments @model=[Object, {}]>]} }
212
-
213
212
  # ::present only runs #setup! which runs #model!.
214
213
  class ContractOnlyOperation < Trailblazer::Operation
215
214
  self.contract_class = class Contract
@@ -78,7 +78,7 @@ class ControllerPresentTest < ActionController::TestCase
78
78
 
79
79
  get :show, id: band.id
80
80
 
81
- assert_equal "bands/show: Band,Band,true,Band::Update,Essen,nil", response.body
81
+ assert_equal "bands/show: Band,Band,Band::Update,Essen,nil", response.body
82
82
  end
83
83
 
84
84
  # TODO: this implicitely tests builds. maybe have separate test for that?
@@ -130,10 +130,10 @@ class ActiveRecordPresentTest < ActionController::TestCase
130
130
  tests ActiveRecordBandsController
131
131
 
132
132
  test "#present" do
133
- band = Band::Create[band: {name: "Nofx"}].model
133
+ band = Band::Create.(band: {name: "Nofx"}).model
134
134
  get :show, id: band.id
135
135
 
136
- assert_equal "active_record_bands/show.html: Band, Band, true, Band::Update", response.body
136
+ assert_equal "active_record_bands/show.html: Band, Band, nil, Band::Update", response.body
137
137
  end
138
138
 
139
139
  test "#collection" do
@@ -63,7 +63,7 @@ class BandsController < ApplicationController
63
63
  @locality = params[:band][:locality] unless params[:format] == "json"
64
64
 
65
65
  return render json: op.to_json if params[:format] == "json"
66
- render text: "bands/show: #{[@klass, @model.class, @form.is_a?(Reform::Form), @operation.class, @locality, @form.locality.inspect].join(',')}"
66
+ render text: "bands/show: #{[@klass, @model.class, @operation.class, @locality, @form.inspect].join(',')}"
67
67
  end
68
68
 
69
69
  def new
@@ -122,7 +122,7 @@ class ActiveRecordBandsController < ApplicationController
122
122
  def show
123
123
  present Band::Update
124
124
 
125
- render text: "active_record_bands/show.html: #{@model.class}, #{@band.class}, #{@form.is_a?(Reform::Form)}, #{@operation.class}"
125
+ render text: "active_record_bands/show.html: #{@model.class}, #{@band.class}, #{@form.inspect}, #{@operation.class}"
126
126
  end
127
127
  end
128
128
 
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: 1.0.0.rc1
4
+ version: 1.0.0.rc2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-09-24 00:00:00.000000000 Z
11
+ date: 2015-09-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: uber