trailblazer 0.1.2 → 0.2.0

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: 02c7b4eafd8dfcbb9eb29aafd91a9213aa34d0e9
4
- data.tar.gz: 8720dec06b3af4b127f77ca140c25e71f7a68799
3
+ metadata.gz: 994926094dd0136c1436127773dd4c8786cd3cb3
4
+ data.tar.gz: ce869dcf9f8c01e2fe10847e3d4b54e460537960
5
5
  SHA512:
6
- metadata.gz: 20bd8a8b6b296bea95bd73a27269855af238c03b5617885c6a51015dc40b2ef7d1c5ea7ff394961e8871d0724fd614d1868227afb3112b74685f55f42eb6a9b1
7
- data.tar.gz: 79c3548b02e02789dc8a1ea55141d1786b710d53dd3213aae0cc0e28a1373c247debae6c1e845522e95235d7befd9fd30968f1ba92fbd7d4fdaaedc5641f9ae1
6
+ metadata.gz: 26367bea09297a1bbcf29506d589826f3e83fca5dc45e4bb6d7146a57f2984c60d324cda43f55a52cd08f3523ed5e76d5b0c56bbddd531a2509ccd4e81117861
7
+ data.tar.gz: ff56573c794feb3afbbc7bac40026f65f418153e9aaef9cbdb6967a01d37412ba1faa95fb4127bab82efd6ad0f5ef10a2ea359a8f94bd8749dbebd480b64d8a2
data/CHANGES.md CHANGED
@@ -1,3 +1,20 @@
1
+ # 0.2.0
2
+
3
+ ## API Changes
4
+
5
+ * `Controller#present` no longer calls `respond_to`, but lets you do the rendering. This will soon be re-introduced using `respond(present: true)`.
6
+ * `Controller#form` did not respect builders, this is fixed now.
7
+ * Use `request.body.read` in Unicorn/etc. environments in `Controller#respond`.
8
+
9
+ ## Stuff
10
+
11
+ * Autoloading changed, again. We now `require_dependency` in every request in dev.
12
+
13
+ # 0.1.3
14
+
15
+ * `crud_autoloading` now simply `require_dependency`s model files, then does the same for the CRUD operation file. This should fix random undefined constant problems in development.
16
+ * `Controller#form` did not use builders. This is fixed now.
17
+
1
18
  # 0.1.2
2
19
 
3
20
  * Add `crud_autoloading`.
data/README.md CHANGED
@@ -6,7 +6,7 @@ In a nutshell: Trailblazer makes you write **logicless models** that purely act
6
6
 
7
7
  ![](https://raw.githubusercontent.com/apotonick/trailblazer/master/doc/trb.jpg)
8
8
 
9
- Please sign up for my upcoming book [Trailblazer - A new architecture for Rails](https://leanpub.com/trailblazer), check out the free sample chapter and [let me know](http://twitter.com/apotonick) what you think!
9
+ Please buy my book [Trailblazer - A new architecture for Rails](https://leanpub.com/trailblazer) and [let me know](http://twitter.com/apotonick) what you think! I am still working on the book but keep adding new chapters every other week. It will be about 300 pages and we're developing a real, full-blown Rails/Trb application.
10
10
 
11
11
  The [demo application](https://github.com/apotonick/gemgem-trbrb) implements what we discuss in the book.
12
12
 
@@ -173,7 +173,7 @@ Again, this will only run the operation's setup and provide the model in `@model
173
173
 
174
174
  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.
175
175
 
176
- Note that `#present` will also work instead of `#form` (allowing it to be used in `#new` and `#edit`, too) as the responder will _not_ trigger any rendering in those actions.
176
+ Note that `#present` will leave rendering up to you - `respond_to` is _not_ called.
177
177
 
178
178
  ### Controller API
179
179
 
@@ -415,18 +415,22 @@ Use our autoloading if you dislike explicit requires.
415
415
  You can just add
416
416
 
417
417
  ```ruby
418
- require 'trailblazer/autoloading'
418
+ require "trailblazer/autoloading"
419
419
  ```
420
420
 
421
- to `config/initializers/trailblazer.rb` and implementation files like `Operation` will be automatically loaded.
421
+ to `config/initializers/trailblazer.rb` and implementation classes like `Operation` will be automatically loaded.
422
422
 
423
- In case you structure your CRUD operations in the `app/concepts/thing/crud.rb` file layout we use in the book, you're gonna run into `Missing constant` trouble. As the `crud.rb` files are not found by Rails it is a good idea to enable CRUD autoloading.
423
+ ## Operation Autoloading
424
+
425
+ If you structure your CRUD operations using the `app/concepts/*/crud.rb` file layout we use in the book, the `crud.rb` files are not gonna be found by Rails automatically. It is a good idea to enable CRUD autoloading.
426
+
427
+ At the end of your `config/application.rb` file, add the following.
424
428
 
425
429
  ```ruby
426
- require trailblazer/crud_autoloading
430
+ require "trailblazer/rails/railtie"
427
431
  ```
428
432
 
429
- This will go through `app/concepts/`, find all the `crud.rb` files, autload their corresponding namespace (e.g. `Thing`, which is a model) and then load the `crud` file.
433
+ This will go through `app/concepts/`, find all the `crud.rb` files, autoload their corresponding namespace (e.g. `Thing`, which is a model) and then load the `crud.rb` file.
430
434
 
431
435
 
432
436
  ## Why?
@@ -5,7 +5,7 @@ private
5
5
  def form(operation_class, params=self.params) # consider private.
6
6
  process_params!(params)
7
7
 
8
- @operation = operation_class.new.present(params)
8
+ @operation = operation_class.present(params)
9
9
  @form = @operation.contract
10
10
  @model = @operation.model
11
11
 
@@ -19,7 +19,8 @@ private
19
19
  res, op = operation!(operation_class, params) { [true, operation_class.present(params)] }
20
20
 
21
21
  yield op if block_given?
22
- respond_with op
22
+ # respond_with op
23
+ # TODO: implement respond(present: true)
23
24
  end
24
25
 
25
26
  # full-on Op[]
@@ -64,8 +65,9 @@ private
64
65
  # this is what happens:
65
66
  # respond_with Comment::Update::JSON.run(params.merge(comment: request.body.string))
66
67
  concept_name = operation_class.model_class.to_s.underscore # this could be renamed to ::concept_class soon.
68
+ request_body = request.body.respond_to?(:string) ? request.body.string : request.body.read
67
69
 
68
- params.merge!(concept_name => request.body.string)
70
+ params.merge!(concept_name => request_body)
69
71
  end
70
72
 
71
73
  res, @operation = yield # Create.run(params)
@@ -0,0 +1,24 @@
1
+ module Trailblazer
2
+ class Railtie < Rails::Railtie
3
+ def self.autoload_crud_operations(app)
4
+ Dir.glob("app/concepts/**/crud.rb") do |f|
5
+ path = f.sub("app/concepts/", "")
6
+ model = path.sub("/crud.rb", "")
7
+
8
+ require_dependency "#{app.root}/app/models/#{model}" # load the model file, first (thing.rb).
9
+ require_dependency "#{app.root}/#{f}" # load app/concepts/{concept}/crud.rb (Thing::Create, Thing::Update, and so on).
10
+ end
11
+ end
12
+
13
+ # thank you, http://stackoverflow.com/a/17573888/465070
14
+ initializer 'trailblazer.install' do |app|
15
+ if Rails.configuration.cache_classes
16
+ Trailblazer::Railtie.autoload_crud_operations(app)
17
+ else
18
+ ActionDispatch::Reloader.to_prepare do
19
+ Trailblazer::Railtie.autoload_crud_operations(app)
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -1,3 +1,3 @@
1
1
  module Trailblazer
2
- VERSION = "0.1.2"
2
+ VERSION = "0.2.0"
3
3
  end
@@ -40,6 +40,8 @@ class OperationRunTest < MiniTest::Spec
40
40
 
41
41
  # return operation when ::call
42
42
  it { Operation.call(true).must_equal operation }
43
+ it { Operation.(true).must_equal operation }
44
+ # #[] is alias for .()
43
45
  it { Operation[true].must_equal operation }
44
46
 
45
47
  # ::[] raises exception when invalid.
@@ -88,7 +90,7 @@ class OperationRunTest < MiniTest::Spec
88
90
 
89
91
  # Operation#contract returns @contract
90
92
  let (:contract) { Operation::Contract.new }
91
- it { Operation[true].contract.must_equal contract }
93
+ it { Operation.(true).contract.must_equal contract }
92
94
  end
93
95
 
94
96
 
@@ -119,7 +121,7 @@ class OperationTest < MiniTest::Spec
119
121
  # ::run
120
122
  it { OperationWithoutValidateCall.run(Object).must_equal [true, Object] }
121
123
  # ::[]
122
- it { OperationWithoutValidateCall[Object].must_equal(Object) }
124
+ it { OperationWithoutValidateCall.(Object).must_equal(Object) }
123
125
  # ::run with invalid!
124
126
  it { OperationWithoutValidateCall.run(nil).must_equal [false, nil] }
125
127
  # ::run with block, invalid
@@ -155,7 +157,7 @@ class OperationTest < MiniTest::Spec
155
157
  end
156
158
 
157
159
  it { OperationWithValidateBlock.run(false).last.secret_contract.must_equal nil }
158
- it('zzz') { OperationWithValidateBlock[true].secret_contract.must_equal OperationWithValidateBlock.contract_class.new.extend(Comparable) }
160
+ it('zzz') { OperationWithValidateBlock.(true).secret_contract.must_equal OperationWithValidateBlock.contract_class.new.extend(Comparable) }
159
161
 
160
162
  # manually setting @valid
161
163
  class OperationWithManualValid < Trailblazer::Operation
@@ -168,7 +170,7 @@ class OperationTest < MiniTest::Spec
168
170
  # ::run
169
171
  it { OperationWithManualValid.run(Object).must_equal [false, Object] }
170
172
  # ::[]
171
- it { OperationWithManualValid[Object].must_equal(Object) }
173
+ it { OperationWithManualValid.(Object).must_equal(Object) }
172
174
 
173
175
 
174
176
  # re-assign params
@@ -281,8 +283,8 @@ class OperationBuilderTest < MiniTest::Spec
281
283
  it { Operation.run({}).last.must_equal "operation" }
282
284
  it { Operation.run({sub: true}).last.must_equal "sub:operation" }
283
285
 
284
- it { Operation[{}].must_equal "operation" }
285
- it { Operation[{sub: true}].must_equal "sub:operation" }
286
+ it { Operation.({}).must_equal "operation" }
287
+ it { Operation.({sub: true}).must_equal "sub:operation" }
286
288
  end
287
289
 
288
290
  # ::contract builds Reform::Form class
@@ -113,13 +113,29 @@ class ResponderRespondWithJSONTest < ActionController::TestCase
113
113
  end
114
114
  end
115
115
 
116
+ # TODO: merge with above tests on SongsController.
117
+ class ControllerRespondTest < ActionController::TestCase
118
+ tests BandsController
119
+
120
+ test "#respond with builds" do
121
+ post :create, band: {name: "SNFU"}, admin: true
122
+ assert_response 302
123
+ assert_equal "SNFU [ADMIN]", Band.last.name
124
+ end
125
+ end
126
+
116
127
 
117
128
  class ResponderRunTest < ActionController::TestCase
118
129
  tests BandsController
119
130
 
120
131
  test "[html/valid]" do
121
132
  put :update, {id: 1, band: {name: "Nofx"}}
122
- assert_equal "no block: Nofx, Essen", response.body
133
+ assert_equal "no block: Nofx, Essen, Band::Create", response.body
134
+ end
135
+
136
+ test "[html/valid] with builds" do
137
+ put :update, {id: 1, band: {name: "Nofx"}, admin: true}
138
+ assert_equal "no block: Nofx [ADMIN], Essen, Band::Create::Admin", response.body
123
139
  end
124
140
 
125
141
  test "with block [html/valid]" do
@@ -146,6 +162,7 @@ class ControllerPresentTest < ActionController::TestCase
146
162
  assert_equal "bands/show.html: Band,Band,true,Band::Update,Essen\n", response.body
147
163
  end
148
164
 
165
+ # TODO: this implicitely tests builds. maybe have separate test for that?
149
166
  test "#present [JSON]" do
150
167
  band = Band::Create[band: {name: "Nofx"}].model
151
168
 
@@ -171,4 +188,10 @@ class ControllerFormTest < ActionController::TestCase
171
188
 
172
189
  assert_select "b", "Band,Band,true,Band::Create,Essen"
173
190
  end
191
+
192
+ test "#form with builder" do
193
+ get :new, admin: true
194
+
195
+ assert_select "b", ",Band,true,Band::Create::Admin"
196
+ end
174
197
  end
@@ -49,7 +49,9 @@ class BandsController < ApplicationController
49
49
  present Band::Update do |op|
50
50
  @klass = op.model.class
51
51
  @locality = params[:band][:locality] unless params[:format] == "json"
52
- end # respond_to
52
+
53
+ render json: op.to_json if params[:format] == "json"
54
+ end # render :show
53
55
  end
54
56
 
55
57
  def new
@@ -82,7 +84,7 @@ ERB
82
84
  def update
83
85
  run Band::Create
84
86
 
85
- render text: "no block: #{@operation.model.name}, #{params[:band][:locality]}"
87
+ render text: "no block: #{@operation.model.name}, #{params[:band][:locality]}, #{@operation.class}"
86
88
  end
87
89
 
88
90
  def update_with_block
@@ -66,8 +66,25 @@ class Band < ActiveRecord::Base
66
66
  end
67
67
  end
68
68
 
69
+ class Admin < self
70
+ def process(params)
71
+ res = super
72
+ model.update_attribute :name, "#{model.name} [ADMIN]"
73
+ res
74
+ end
75
+ end
76
+
77
+ # TODO: wait for uber 0.0.10 and @dutow.
78
+ # builds -> (params)
79
+ # return JSON if params[:format] == "json"
80
+ # return Admin if params[:admin]
81
+ # end
69
82
  builds do |params|
70
- JSON if params[:format] == "json"
83
+ if params[:format] == "json"
84
+ JSON
85
+ elsif params[:admin]
86
+ Admin
87
+ end
71
88
  end
72
89
  end
73
90
 
data/trailblazer.gemspec CHANGED
@@ -28,4 +28,6 @@ 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 "rails"
32
+ spec.add_development_dependency "sqlite3"
31
33
  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: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nick Sutterer
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2014-12-16 00:00:00.000000000 Z
11
+ date: 2015-01-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: actionpack
@@ -128,6 +128,34 @@ dependencies:
128
128
  - - "~>"
129
129
  - !ruby/object:Gem::Version
130
130
  version: 3.1.0
131
+ - !ruby/object:Gem::Dependency
132
+ name: rails
133
+ requirement: !ruby/object:Gem::Requirement
134
+ requirements:
135
+ - - ">="
136
+ - !ruby/object:Gem::Version
137
+ version: '0'
138
+ type: :development
139
+ prerelease: false
140
+ version_requirements: !ruby/object:Gem::Requirement
141
+ requirements:
142
+ - - ">="
143
+ - !ruby/object:Gem::Version
144
+ version: '0'
145
+ - !ruby/object:Gem::Dependency
146
+ name: sqlite3
147
+ requirement: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ type: :development
153
+ prerelease: false
154
+ version_requirements: !ruby/object:Gem::Requirement
155
+ requirements:
156
+ - - ">="
157
+ - !ruby/object:Gem::Version
158
+ version: '0'
131
159
  description: Trailblazer is a thin layer on top of Rails. It gently enforces encapsulation,
132
160
  an intuitive code structure and gives you an object-oriented architecture.
133
161
  email:
@@ -151,7 +179,6 @@ files:
151
179
  - gemfiles/Gemfile.rails.lock
152
180
  - lib/trailblazer.rb
153
181
  - lib/trailblazer/autoloading.rb
154
- - lib/trailblazer/crud_autoloading.rb
155
182
  - lib/trailblazer/operation.rb
156
183
  - lib/trailblazer/operation/controller.rb
157
184
  - lib/trailblazer/operation/crud.rb
@@ -159,6 +186,7 @@ files:
159
186
  - lib/trailblazer/operation/responder.rb
160
187
  - lib/trailblazer/operation/uploaded_file.rb
161
188
  - lib/trailblazer/operation/worker.rb
189
+ - lib/trailblazer/rails/railtie.rb
162
190
  - lib/trailblazer/version.rb
163
191
  - test/crud_test.rb
164
192
  - test/fixtures/apotomo.png
@@ -174,7 +202,6 @@ files:
174
202
  - test/rails/fake_app/song/operations.rb
175
203
  - test/rails/fake_app/views/bands/show.html.erb
176
204
  - test/rails/fake_app/views/songs/new.html.erb
177
- - test/rails/integration_test.rb
178
205
  - test/rails/test_helper.rb
179
206
  - test/responder_test.rb
180
207
  - test/test_helper.rb
@@ -220,7 +247,6 @@ test_files:
220
247
  - test/rails/fake_app/song/operations.rb
221
248
  - test/rails/fake_app/views/bands/show.html.erb
222
249
  - test/rails/fake_app/views/songs/new.html.erb
223
- - test/rails/integration_test.rb
224
250
  - test/rails/test_helper.rb
225
251
  - test/responder_test.rb
226
252
  - test/test_helper.rb
@@ -1,8 +0,0 @@
1
- # FIXME: this will only work for operations embedded in a MODEL namespace.
2
- # this is really hacky and assumes a lot about your structure, but it works for now. don't include it if you don't like it.
3
- Dir.glob("app/concepts/**/crud.rb") do |f|
4
- path = f.sub("app/concepts/", "")
5
-
6
- path.sub("/crud.rb", "").camelize.constantize # load the model first (Thing).
7
- require_dependency path # load model/crud.rb (Thing::Create, Thing::Update, and so on).
8
- end
@@ -1,23 +0,0 @@
1
- require 'test_helper'
2
-
3
- class IntegrationTest < ActionController::TestCase
4
- tests BandsController
5
-
6
- # test rendering JSON of populated band.
7
- test "#present [JSON]" do
8
- band = Band::Create[band: {name: "Nofx", songs: [{title: "Murder The Government"}, {title: "Eat The Meek"}]}].model
9
-
10
- get :show, id: band.id, format: :json
11
- assert_equal "{\"name\":\"Nofx\",\"songs\":[{\"title\":\"Murder The Government\"},{\"title\":\"Eat The Meek\"}]}", response.body
12
- end
13
-
14
- # parsing incoming complex document.
15
- test "create [JSON]" do
16
- post :create, "{\"name\":\"Nofx\",\"songs\":[{\"title\":\"Murder The Government\"},{\"title\":\"Eat The Meek\"}]}", format: :json
17
- assert_response 201
18
-
19
- band = Band.last
20
- assert_equal "Nofx", band.name
21
- assert_equal "Murder The Government", band.songs[0].title
22
- end
23
- end