trailblazer 0.3.0 → 0.3.1

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