trailblazer 0.3.0 → 0.3.1

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: 64d96dc88ee097d82859f27a353220b80c738e3e
4
- data.tar.gz: 2b94910cfaa58c8b8c1d6ade98d7d1c2d9280c61
3
+ metadata.gz: 06e8559ba04b20c80f460c00d2fe76e94a7dceae
4
+ data.tar.gz: d16ed4ac3f269404152c316e2abcad2053c9f29c
5
5
  SHA512:
6
- metadata.gz: 7ca6fc8e1715d0c98e07630c900daa3294bc6ac0387b32605efc2dc36d623cd61b43eed532c43255354ed210d564ef8ae58d2639d6bdfb8a826a6a4d9690cf3a
7
- data.tar.gz: becc502617a59760160be2b64d53e3025be033e4c404ee76d557cdd3c0e780da963ed6e1305cc54d06f14739ef47ce8a9450c4753bc6d97a12db97a4c115e96d
6
+ metadata.gz: 2818fb4a0c7cfdc66b700df7feed6ac8a60dca747922ac901c311c92dffaf44dd0b3881ddfb46bf3eceebbc122d558bbd5c1acfc463a4ff2246824f519e475ee
7
+ data.tar.gz: 39daeb303ccadc8dd261cfa44576bf046d94174568abecceed193de66c902cd3fc1a5ce27d99814644f26585b800d7f7568b094f5c5ff044eb8fbbaf29ea1fa6
data/CHANGES.md CHANGED
@@ -1,3 +1,7 @@
1
+ # 0.3.1
2
+
3
+ * Autoload `Dispatch`.
4
+
1
5
  # 0.3.0
2
6
 
3
7
  ## Changes
data/Gemfile CHANGED
@@ -7,5 +7,5 @@ gemspec
7
7
  # gem "reform", path: "../reform"
8
8
  # gem "disposable", path: "../disposable"
9
9
  gem "virtus"
10
- gem "reform", github: "apotonick/reform"
11
-
10
+ # gem "reform", github: "apotonick/reform"
11
+ gem "reform", ">= 2.0.0.rc1"
data/README.md CHANGED
@@ -141,11 +141,58 @@ class Create < Trailblazer::Operation
141
141
  self.contract_class = MyCommentForm
142
142
  ```
143
143
 
144
+ ## Callbacks
145
+
146
+ Post-processing logic (also known as _callbacks_) is configured in operations.
147
+
148
+ Following the schema of your contract, you can define callbacks for events tracked by the form's twin.
149
+
150
+ ```ruby
151
+ class Create < Trailblazer::Operation
152
+ callback(:after_save) do
153
+ on_change :upload_file, property: :file
154
+
155
+ property :user do
156
+ on_create :notify_user!
157
+ end
158
+ end
159
+ ```
160
+
161
+ The _Imperative Callback_ pattern then allows you to call this _callback group_ whereever you need it.
162
+
163
+ ```ruby
164
+ class Create < Trailblazer::Operation
165
+
166
+ def process(params)
167
+ validate(params) do
168
+ contract.save
169
+ dispatch!(:after_save)
170
+ end
171
+ end
172
+ end
173
+ ```
174
+
175
+ No magical triggering of unwanted logic anymore, but explicit invocations where you want it.
176
+
177
+
144
178
  ## Models
145
179
 
146
180
  Models for persistence can be implemented using any ORM you fancy, for instance [ActiveRecord](https://github.com/rails/rails/tree/master/activerecord#active-record--object-relational-mapping-in-rails) or [Datamapper](http://datamapper.org/).
147
181
 
148
- In Trailblazer, models are completely empty and solely configure database-relevant directives and associations. No business logic is allowed in models. Only operations, views and cells can access models directly.
182
+ In Trailblazer, models are completely empty. They solely contain associations and finders. No business logic is allowed in models.
183
+
184
+ ```ruby
185
+ class Thing < ActiveRecord::Base
186
+ has_many :comments, -> { order(created_at: :desc) }
187
+ has_many :users, through: :authorships
188
+ has_many :authorships
189
+
190
+ scope :latest, lambda { all.limit(9).order("id DESC") }
191
+ end
192
+ ```
193
+
194
+ Only operations and views/cells can access models directly.
195
+
149
196
 
150
197
  ## Views
151
198
 
@@ -153,9 +200,31 @@ View rendering can happen using the controller as known from Rails. This is abso
153
200
 
154
201
  More complex UI logic happens in _View Models_ as found in [Cells](https://github.com/apotonick/cells). View models also replace helpers.
155
202
 
156
- 8. **HTTP API** Consuming and rendering API documents (e.g. JSON or XML) is done via [roar](https://github.com/apotonick/roar) and [representable](https://github.com/apotonick/representable). They usually inherit the schema from <em>Contract</em>s .
157
203
 
158
- 10. **Tests** Subject to tests are mainly <em>Operation</em>s and <em>View Model</em>s, as they encapsulate endpoint behaviour of your app. As a nice side effect, factories are replaced by simple _Operation_ calls.
204
+ ## Representers
205
+
206
+ Operations can use representers from [Roar](https://github.com/apotonick/roar) to serialize and parse JSON and XML documents for APIs.
207
+
208
+ Representers can be inferred automatically from your contract, then may be refined, e.g. with hypermedia or a format like `JSON-API`.
209
+
210
+ ```ruby
211
+ class Create < Trailblazer::Operation
212
+
213
+ representer do
214
+ # inherited :body
215
+ include Roar::JSON::HAL
216
+
217
+ link(:self) { comment_path(represented.id) }
218
+ end
219
+ ```
220
+
221
+ The operation can then parse incoming JSON documents in `validate` and render a document via `to_json`. The full [documentation is here](http://trailblazerb.org/gems/operation/representer.html) or in the [Trailblazer book](https://leanpub.com/trailblazer), chapter _Hypermedia APIs_.
222
+
223
+ ## Tests
224
+
225
+ Subject to tests are mainly _Operation_s and _View Model_s, as they encapsulate endpoint behaviour of your app. As a nice side effect, factories are replaced by simple _Operation_ calls.
226
+
227
+
159
228
 
160
229
  ## Overview
161
230
 
@@ -165,6 +234,8 @@ Using the different layers is completely optional and up to you: Both Cells and
165
234
 
166
235
  ## Controller API
167
236
 
237
+ [Learn more](http://trailblazerb.org/gems/operation/controller.html)
238
+
168
239
  Trailblazer provides four methods to present and invoke operations. But before that, you need to include the `Controller` module.
169
240
 
170
241
  ```ruby
@@ -294,24 +365,6 @@ In all three cases the following instance variables are assigned: `@operation`,
294
365
  Named instance variables can be included, too. This is documented [here](#named-controller-instance-variables).
295
366
 
296
367
 
297
- ### Normalizing params
298
-
299
- Override `#process_params!` to add or remove values to `params` before the operation is run. This is called in `#run`, `#respond` and `#present`.
300
-
301
- ```ruby
302
- class CommentsController < ApplicationController
303
- # ..
304
-
305
- private
306
- def process_params!(params)
307
- params.merge!(current_user: current_user)
308
- end
309
- end
310
- ```
311
-
312
- This centralizes params normalization and doesn't require you to do that in every action manually.
313
-
314
-
315
368
  ### Different Request Formats
316
369
 
317
370
  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.
@@ -344,22 +397,22 @@ end
344
397
  The simplest way of running an operation is the _call style_.
345
398
 
346
399
  ```ruby
347
- op = Comment::Create[params]
400
+ op = Comment::Create.(params)
348
401
  ```
349
402
 
350
- Using `Operation#[]` will return the operation instance. In case of an invalid operation, this will raise an exception.
403
+ The call style runs the operation and return the operation instance, only.
351
404
 
352
- Note how this can easily be used for test factories.
405
+ In case of an invalid operation, this will raise an exception.
353
406
 
354
- ```ruby
355
- let(:comment) { Comment::Create[valid_comment_params].model }
356
- ```
407
+ ### Run style
357
408
 
358
- Using operations as test factories is a fundamental concept of Trailblazer to remove buggy redundancy in tests and manual factories.
409
+ The _run style_ will do the same as call, but won't raise an exception in case of an invalid result. Instead, it returns result _and_ the operation instance.
359
410
 
360
- ### Run style
411
+ ```ruby
412
+ result, op = Comment::Create.run(params)
413
+ ```
361
414
 
362
- You can run an operation manually and use the same block semantics as found in the controller.
415
+ Additionally, it accepts a block that's only run for a valid state.
363
416
 
364
417
  ```ruby
365
418
  Comment::Create.run(params) do |op|
@@ -367,7 +420,27 @@ Comment::Create.run(params) do |op|
367
420
  end
368
421
  ```
369
422
 
370
- Of course, this does _not_ throw an exception but simply skips the block when the operation is invalid.
423
+ ## Form API
424
+
425
+ Usually, an operation has a form object.
426
+
427
+ ```ruby
428
+ class Create < Trailblazer::Operation
429
+ contract do
430
+ property :body
431
+ validates :body: presence: true, length: {max: 160}
432
+ end
433
+ ```
434
+
435
+ A `::contract` block simply opens a new Reform class for you.
436
+
437
+ ```ruby
438
+ contract do #=> Class.new(Reform::Form) do
439
+ ```
440
+
441
+ This allows using Reform's API in the block.
442
+
443
+ When inheriting, the block is `class_eval`ed in the inherited class' context and allows adding, removing and customizing the sub contract.
371
444
 
372
445
  ### CRUD Semantics
373
446
 
@@ -3,4 +3,5 @@ Trailblazer::Operation.class_eval do
3
3
  autoload :Responder, "trailblazer/operation/responder"
4
4
  autoload :CRUD, "trailblazer/operation/crud"
5
5
  autoload :Collection, "trailblazer/operation/collection"
6
+ autoload :Dispatch, "trailblazer/operation/dispatch"
6
7
  end
@@ -143,7 +143,6 @@ module Trailblazer
143
143
  end
144
144
 
145
145
  require 'trailblazer/operation/crud'
146
- require "trailblazer/operation/dispatch"
147
146
 
148
147
  # run
149
148
  # setup
@@ -1,3 +1,3 @@
1
1
  module Trailblazer
2
- VERSION = "0.3.0"
2
+ VERSION = "0.3.1"
3
3
  end
@@ -1,11 +1,12 @@
1
1
  require 'test_helper'
2
+ require "trailblazer/operation/dispatch"
2
3
 
3
4
  # callbacks are tested in Disposable::Callback::Group.
4
5
  class OperationCallbackTest < MiniTest::Spec
5
6
  Song = Struct.new(:name)
6
7
 
7
8
  class Create < Trailblazer::Operation
8
- include Dispatch
9
+ include Trailblazer::Operation::Dispatch
9
10
 
10
11
  contract do
11
12
  property :name
data/trailblazer.gemspec CHANGED
@@ -18,7 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
19
  spec.require_paths = ["lib"]
20
20
 
21
- spec.add_dependency "actionpack", '>= 3.0.0' # this framework works on Rails.
21
+
22
22
  spec.add_dependency "uber", ">= 0.0.10" # no builder inheritance.
23
23
  # spec.add_dependency "representable", ">= 2.1.1", "<2.3.0" # Representable::apply.
24
24
  spec.add_dependency "reform", ">= 1.2.0"
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
28
28
  spec.add_development_dependency "minitest"
29
29
  # spec.add_development_dependency "minitest-spec-rails" # TODO: can anyone make this work (test/rails).
30
30
  spec.add_development_dependency "sidekiq", "~> 3.1.0"
31
+ spec.add_development_dependency "actionpack", '>= 3.0.0' # Rails is optional.
31
32
  spec.add_development_dependency "rails"
32
33
  spec.add_development_dependency "sqlite3"
33
34
  spec.add_development_dependency "responders"
metadata CHANGED
@@ -1,29 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: trailblazer
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.0
4
+ version: 0.3.1
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-06-30 00:00:00.000000000 Z
11
+ date: 2015-07-03 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: actionpack
15
- requirement: !ruby/object:Gem::Requirement
16
- requirements:
17
- - - ">="
18
- - !ruby/object:Gem::Version
19
- version: 3.0.0
20
- type: :runtime
21
- prerelease: false
22
- version_requirements: !ruby/object:Gem::Requirement
23
- requirements:
24
- - - ">="
25
- - !ruby/object:Gem::Version
26
- version: 3.0.0
27
13
  - !ruby/object:Gem::Dependency
28
14
  name: uber
29
15
  requirement: !ruby/object:Gem::Requirement
@@ -108,6 +94,20 @@ dependencies:
108
94
  - - "~>"
109
95
  - !ruby/object:Gem::Version
110
96
  version: 3.1.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: actionpack
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - ">="
102
+ - !ruby/object:Gem::Version
103
+ version: 3.0.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - ">="
109
+ - !ruby/object:Gem::Version
110
+ version: 3.0.0
111
111
  - !ruby/object:Gem::Dependency
112
112
  name: rails
113
113
  requirement: !ruby/object:Gem::Requirement