her 0.5.5 → 0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (63) hide show
  1. checksums.yaml +8 -8
  2. data/.gitignore +1 -1
  3. data/README.md +78 -63
  4. data/UPGRADE.md +21 -0
  5. data/lib/her/model.rb +2 -1
  6. data/lib/her/model/associations.rb +17 -54
  7. data/lib/her/model/associations/association.rb +46 -0
  8. data/lib/her/model/associations/belongs_to_association.rb +34 -0
  9. data/lib/her/model/associations/has_many_association.rb +43 -0
  10. data/lib/her/model/associations/has_one_association.rb +33 -0
  11. data/lib/her/model/attributes.rb +19 -19
  12. data/lib/her/model/base.rb +5 -0
  13. data/lib/her/model/http.rb +17 -21
  14. data/lib/her/model/orm.rb +11 -35
  15. data/lib/her/model/parse.rb +4 -12
  16. data/lib/her/model/paths.rb +3 -2
  17. data/lib/her/model/relation.rb +113 -0
  18. data/lib/her/version.rb +1 -1
  19. data/spec/model/associations_spec.rb +48 -4
  20. data/spec/model/introspection_spec.rb +1 -1
  21. data/spec/model/orm_spec.rb +21 -102
  22. data/spec/model/parse_spec.rb +36 -7
  23. data/spec/model/paths_spec.rb +3 -3
  24. data/spec/model/relation_spec.rb +89 -0
  25. data/spec/spec_helper.rb +1 -0
  26. data/spec/support/macros/her_macros.rb +17 -0
  27. data/spec/support/macros/request_macros.rb +19 -0
  28. metadata +13 -37
  29. data/examples/grape-and-her/.env.default +0 -3
  30. data/examples/grape-and-her/Procfile +0 -2
  31. data/examples/grape-and-her/README.md +0 -27
  32. data/examples/grape-and-her/api/Gemfile +0 -11
  33. data/examples/grape-and-her/api/Rakefile +0 -14
  34. data/examples/grape-and-her/api/app/api.rb +0 -49
  35. data/examples/grape-and-her/api/app/models/organization.rb +0 -7
  36. data/examples/grape-and-her/api/app/models/user.rb +0 -9
  37. data/examples/grape-and-her/api/app/views/organizations/_base.rabl +0 -2
  38. data/examples/grape-and-her/api/app/views/organizations/index.rabl +0 -3
  39. data/examples/grape-and-her/api/app/views/organizations/show.rabl +0 -3
  40. data/examples/grape-and-her/api/app/views/users/_base.rabl +0 -8
  41. data/examples/grape-and-her/api/app/views/users/index.rabl +0 -3
  42. data/examples/grape-and-her/api/app/views/users/show.rabl +0 -3
  43. data/examples/grape-and-her/api/config.ru +0 -5
  44. data/examples/grape-and-her/api/config/boot.rb +0 -17
  45. data/examples/grape-and-her/api/config/unicorn.rb +0 -7
  46. data/examples/grape-and-her/api/db/migrations/001_create_users.rb +0 -11
  47. data/examples/grape-and-her/api/db/migrations/002_create_organizations.rb +0 -8
  48. data/examples/grape-and-her/consumer/Gemfile +0 -23
  49. data/examples/grape-and-her/consumer/app/assets/stylesheets/application.scss +0 -190
  50. data/examples/grape-and-her/consumer/app/assets/stylesheets/reset.scss +0 -53
  51. data/examples/grape-and-her/consumer/app/consumer.rb +0 -74
  52. data/examples/grape-and-her/consumer/app/models/organization.rb +0 -13
  53. data/examples/grape-and-her/consumer/app/models/user.rb +0 -13
  54. data/examples/grape-and-her/consumer/app/views/index.haml +0 -9
  55. data/examples/grape-and-her/consumer/app/views/layout.haml +0 -20
  56. data/examples/grape-and-her/consumer/app/views/organizations/index.haml +0 -25
  57. data/examples/grape-and-her/consumer/app/views/organizations/show.haml +0 -11
  58. data/examples/grape-and-her/consumer/app/views/users/index.haml +0 -33
  59. data/examples/grape-and-her/consumer/app/views/users/show.haml +0 -9
  60. data/examples/grape-and-her/consumer/config.ru +0 -20
  61. data/examples/grape-and-her/consumer/config/boot.rb +0 -30
  62. data/examples/grape-and-her/consumer/config/unicorn.rb +0 -7
  63. data/examples/grape-and-her/consumer/lib/response_logger.rb +0 -18
@@ -36,6 +36,7 @@ module Her
36
36
  return @_her_include_root_in_json unless value
37
37
  @_her_include_root_in_json = value
38
38
  end
39
+ alias :include_root_in_json? :include_root_in_json
39
40
 
40
41
  # Return or change the value of `parse_root_in`
41
42
  #
@@ -52,6 +53,7 @@ module Her
52
53
  return @_her_parse_root_in_json unless value
53
54
  @_her_parse_root_in_json = value
54
55
  end
56
+ alias :parse_root_in_json? :parse_root_in_json
55
57
 
56
58
  # Return or change the value of `root_element`. Always defaults to the base name of the class.
57
59
  #
@@ -72,24 +74,14 @@ module Her
72
74
  end
73
75
  end
74
76
 
75
- # @private
76
- def parse_root_in_json?
77
- parse_root_in_json
78
- end
79
-
80
- # @private
81
- def include_root_in_json?
82
- include_root_in_json
83
- end
84
-
85
77
  # @private
86
78
  def included_root_element
87
- include_root_in_json == true ? root_element.to_sym : include_root_in_json
79
+ include_root_in_json == true ? root_element : include_root_in_json
88
80
  end
89
81
 
90
82
  # @private
91
83
  def parsed_root_element
92
- parse_root_in_json == true ? root_element.to_sym : parse_root_in_json
84
+ parse_root_in_json == true ? root_element : parse_root_in_json
93
85
  end
94
86
  end
95
87
  end
@@ -31,7 +31,7 @@ module Her
31
31
  # @param [Symbol] value
32
32
  def primary_key(value = nil)
33
33
  @_her_primary_key ||= begin
34
- superclass.primary_key.to_sym if superclass.respond_to?(:primary_key)
34
+ superclass.primary_key if superclass.respond_to?(:primary_key)
35
35
  end
36
36
 
37
37
  return @_her_primary_key unless value
@@ -110,7 +110,8 @@ module Her
110
110
 
111
111
  path.gsub(/:([\w_]+)/) do
112
112
  # Look for :key or :_key, otherwise raise an exception
113
- parameters.delete($1.to_sym) || parameters.delete("_#{$1}".to_sym) || raise(Her::Errors::PathError.new("Missing :_#{$1} parameter to build the request path. Path is `#{path}`. Parameters are `#{parameters.inspect}`.", $1))
113
+ value = $1.to_sym
114
+ parameters.delete(value) || parameters.delete(:"_#{value}") || raise(Her::Errors::PathError.new("Missing :_#{$1} parameter to build the request path. Path is `#{path}`. Parameters are `#{parameters.inspect}`.", $1))
114
115
  end
115
116
  end
116
117
 
@@ -0,0 +1,113 @@
1
+ module Her
2
+ module Model
3
+ class Relation
4
+ attr_accessor :query_attrs
5
+
6
+ # @private
7
+ def initialize(parent)
8
+ @parent = parent
9
+ @query_attrs = {}
10
+ end
11
+
12
+ # Build a new resource
13
+ def build(attrs = {})
14
+ @parent.new(@query_attrs.merge(attrs))
15
+ end
16
+
17
+ # Add a query string parameter
18
+ def where(attrs = {})
19
+ return self if attrs.blank?
20
+ self.clone.tap { |a| a.query_attrs = a.query_attrs.merge(attrs) }
21
+ end
22
+ alias :all :where
23
+
24
+ def page(page)
25
+ where(:page => page)
26
+ end
27
+
28
+ def per_page(per_page)
29
+ where(:per_page => per_page)
30
+ end
31
+ alias :per :per_page
32
+
33
+ # Bubble all methods to the fetched collection
34
+ def method_missing(method, *args, &blk)
35
+ fetch.send(method, *args, &blk)
36
+ end
37
+
38
+ # @private
39
+ def nil?
40
+ fetch.nil?
41
+ end
42
+
43
+ # @private
44
+ def kind_of?(thing)
45
+ fetch.kind_of?(thing)
46
+ end
47
+
48
+ # Fetch a collection of resources
49
+ #
50
+ # @example
51
+ # @users = User.all
52
+ # # Fetched via GET "/users"
53
+ #
54
+ # @example
55
+ # @users = User.where(:approved => 1).all
56
+ # # Fetched via GET "/users?approved=1"
57
+ def fetch
58
+ @_fetch ||= begin
59
+ path = @parent.build_request_path(@query_attrs)
60
+ @parent.request(@query_attrs.merge(:_method => :get, :_path => path)) do |parsed_data, response|
61
+ @parent.new_collection(parsed_data)
62
+ end
63
+ end
64
+ end
65
+
66
+ # Create a resource and return it
67
+ #
68
+ # @example
69
+ # @user = User.create(:fullname => "Tobias Fünke")
70
+ # # Called via POST "/users/1" with `&fullname=Tobias+Fünke`
71
+ #
72
+ # @example
73
+ # @user = User.where(:email => "tobias@bluth.com").create(:fullname => "Tobias Fünke")
74
+ # # Called via POST "/users/1" with `&email=tobias@bluth.com&fullname=Tobias+Fünke`
75
+ def create(attrs = {})
76
+ attrs ||= {}
77
+ resource = @parent.new(@query_attrs.merge(attrs))
78
+ resource.save
79
+
80
+ resource
81
+ end
82
+
83
+ # Fetch a resource and create it if it's not found
84
+ #
85
+ # @example
86
+ # @user = User.where(:email => "remi@example.com").find_or_create
87
+ #
88
+ # # Returns the first item of the collection if present:
89
+ # # GET "/users?email=remi@example.com"
90
+ #
91
+ # # If collection is empty:
92
+ # # POST /users with `email=remi@example.com`
93
+ def first_or_create(attrs = {})
94
+ fetch.first || create(attrs)
95
+ end
96
+
97
+ # Fetch a resource and build it if it's not found
98
+ #
99
+ # @example
100
+ # @user = User.where(:email => "remi@example.com").find_or_initialize
101
+ #
102
+ # # Returns the first item of the collection if present:
103
+ # # GET "/users?email=remi@example.com"
104
+ #
105
+ # # If collection is empty:
106
+ # @user.email # => "remi@example.com"
107
+ # @user.new? # => true
108
+ def first_or_initialize(attrs = {})
109
+ fetch.first || build(attrs)
110
+ end
111
+ end
112
+ end
113
+ end
data/lib/her/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.5.5"
2
+ VERSION = "0.6"
3
3
  end
@@ -151,11 +151,12 @@ describe Her::Model::Associations do
151
151
  end
152
152
 
153
153
  it "fetches has_many data even if it was included, only if called with parameters" do
154
- @user_with_included_data.comments(:foo_id => 1).length.should == 1
154
+ @user_with_included_data.comments.where(:foo_id => 1).length.should == 1
155
155
  end
156
156
 
157
157
  it "maps an array of included data through has_one" do
158
158
  @user_with_included_data.role.should be_a(Foo::Role)
159
+ @user_with_included_data.role.object_id.should == @user_with_included_data.role.object_id
159
160
  @user_with_included_data.role.id.should == 1
160
161
  @user_with_included_data.role.body.should == "Admin"
161
162
  end
@@ -167,7 +168,7 @@ describe Her::Model::Associations do
167
168
  end
168
169
 
169
170
  it "fetches has_one data even if it was included, only if called with parameters" do
170
- @user_with_included_data.role(:foo_id => 2).id.should == 3
171
+ @user_with_included_data.role.where(:foo_id => 2).id.should == 3
171
172
  end
172
173
 
173
174
  it "maps an array of included data through belongs_to" do
@@ -183,7 +184,7 @@ describe Her::Model::Associations do
183
184
  end
184
185
 
185
186
  it "fetches belongs_to data even if it was included, only if called with parameters" do
186
- @user_with_included_data.organization(:foo_id => 1).name.should == "Bluth Company Foo"
187
+ @user_with_included_data.organization.where(:foo_id => 1).name.should == "Bluth Company Foo"
187
188
  end
188
189
 
189
190
  it "can tell if it has a association" do
@@ -197,7 +198,8 @@ describe Her::Model::Associations do
197
198
  end
198
199
 
199
200
  it "pass query string parameters when additional arguments are passed" do
200
- @user_without_included_data.organization(:admin => true).name.should == "Bluth Company (admin)"
201
+ @user_without_included_data.organization.where(:admin => true).name.should == "Bluth Company (admin)"
202
+ @user_without_included_data.organization.name.should == "Bluth Company"
201
203
  end
202
204
 
203
205
  [:create, :save_existing, :destroy].each do |type|
@@ -260,4 +262,46 @@ describe Her::Model::Associations do
260
262
  @user_without_included_data.company.name.should == "Bluth Company"
261
263
  end
262
264
  end
265
+
266
+ context "building and creating association data" do
267
+ before do
268
+ spawn_model "Foo::Comment"
269
+ spawn_model "Foo::User" do
270
+ has_many :comments
271
+ end
272
+ end
273
+
274
+ context "with #build" do
275
+ it "takes the parent primary key" do
276
+ @comment = Foo::User.new(:id => 10).comments.build(:body => "Hello!")
277
+ @comment.body.should == "Hello!"
278
+ @comment.user_id.should == 10
279
+ end
280
+ end
281
+
282
+ context "with #create" do
283
+ before do
284
+ Her::API.setup :url => "https://api.example.com" do |builder|
285
+ builder.use Her::Middleware::FirstLevelParseJSON
286
+ builder.use Faraday::Request::UrlEncoded
287
+ builder.adapter :test do |stub|
288
+ stub.get("/users/10") { |env| [200, {}, { :id => 10 }.to_json] }
289
+ stub.post("/comments") { |env| [200, {}, { :id => 1, :body => Faraday::Utils.parse_query(env[:body])['body'], :user_id => Faraday::Utils.parse_query(env[:body])['user_id'].to_i }.to_json] }
290
+ end
291
+ end
292
+
293
+ Foo::User.use_api Her::API.default_api
294
+ Foo::Comment.use_api Her::API.default_api
295
+ end
296
+
297
+ it "takes the parent primary key and saves the resource" do
298
+ @user = Foo::User.find(10)
299
+ @comment = @user.comments.create(:body => "Hello!")
300
+ @comment.id.should == 1
301
+ @comment.body.should == "Hello!"
302
+ @comment.user_id.should == 10
303
+ @user.comments.should == [@comment]
304
+ end
305
+ end
306
+ end
263
307
  end
@@ -44,7 +44,7 @@ describe Her::Model::Introspection do
44
44
 
45
45
  describe "#inspect with errors in resource path" do
46
46
  it "prints the resource path as “unknown”" do
47
- @comment = Foo::Comment.all(:project_id => 1).first
47
+ @comment = Foo::Comment.where(:project_id => 1).first
48
48
  path = '<unknown path, missing `project_id`>'
49
49
  ["#<Foo::Comment(#{path}) body=\"Hello!\" id=1>", "#<Foo::Comment(#{path}) id=1 body=\"Hello!\">"].should include(@comment.inspect)
50
50
  end
@@ -157,6 +157,7 @@ describe Her::Model::ORM do
157
157
  stub.get("/users/1") { |env| [200, {}, { :id => 1, :age => 42 }.to_json] }
158
158
  stub.get("/users/2") { |env| [200, {}, { :id => 2, :age => 34 }.to_json] }
159
159
  stub.get("/users?age=42") { |env| [200, {}, [{ :id => 1, :age => 42 }].to_json] }
160
+ stub.get("/users?age=40") { |env| [200, {}, [{ :id => 1, :age => 40 }].to_json] }
160
161
  end
161
162
  end
162
163
 
@@ -194,10 +195,26 @@ describe Her::Model::ORM do
194
195
  end
195
196
 
196
197
  it "handles finding with other parameters" do
197
- @users = User.all(:age => 42)
198
+ @users = User.where(:age => 42).all
198
199
  @users.should be_kind_of(Array)
199
200
  @users.should be_all { |u| u.age == 42 }
200
201
  end
202
+
203
+ it "handles finding with other parameters and scoped" do
204
+ @users = User.scoped
205
+ @users.where(:age => 42).should be_all { |u| u.age == 42 }
206
+ @users.where(:age => 40).should be_all { |u| u.age == 40 }
207
+ end
208
+
209
+ it "handles finding with paging parameters" do
210
+ @users = User.page(2).per_page(20)
211
+ @users.query_attrs[:page].should == 2
212
+ @users.query_attrs[:per_page].should == 20
213
+
214
+ @users = User.all.page(2).per_page(20)
215
+ @users.query_attrs[:page].should == 2
216
+ @users.query_attrs[:per_page].should == 20
217
+ end
201
218
  end
202
219
 
203
220
  context "creating resources" do
@@ -206,7 +223,7 @@ describe Her::Model::ORM do
206
223
  builder.use Her::Middleware::FirstLevelParseJSON
207
224
  builder.use Faraday::Request::UrlEncoded
208
225
  builder.adapter :test do |stub|
209
- stub.post("/users") { |env| [200, {}, { :id => 1, :fullname => "Tobias Fünke" }.to_json] }
226
+ stub.post("/users") { |env| [200, {}, { :id => 1, :fullname => Faraday::Utils.parse_query(env[:body])['fullname'], :email => Faraday::Utils.parse_query(env[:body])['email'] }.to_json] }
210
227
  stub.post("/companies") { |env| [200, {}, { :errors => ["name is required"] }.to_json] }
211
228
  end
212
229
  end
@@ -216,9 +233,10 @@ describe Her::Model::ORM do
216
233
  end
217
234
 
218
235
  it "handle one-line resource creation" do
219
- @user = Foo::User.create(:fullname => "Tobias Fünke")
236
+ @user = Foo::User.create(:fullname => "Tobias Fünke", :email => "tobias@bluth.com")
220
237
  @user.id.should == 1
221
238
  @user.fullname.should == "Tobias Fünke"
239
+ @user.email.should == "tobias@bluth.com"
222
240
  end
223
241
 
224
242
  it "handle resource creation through Model.new + #save" do
@@ -300,103 +318,4 @@ describe Her::Model::ORM do
300
318
  @user.should be_destroyed
301
319
  end
302
320
  end
303
-
304
- context "saving resources with overridden to_params" do
305
- before do
306
- Her::API.setup :url => "https://api.example.com" do |builder|
307
- builder.use Her::Middleware::FirstLevelParseJSON
308
- builder.use Faraday::Request::UrlEncoded
309
- builder.adapter :test do |stub|
310
- stub.post("/users") do |env|
311
- body = {
312
- :id => 1,
313
- :fullname => Faraday::Utils.parse_query(env[:body])['fullname']
314
- }.to_json
315
- [200, {}, body]
316
- end
317
- end
318
- end
319
-
320
- spawn_model "Foo::User" do
321
- def to_params
322
- { :fullname => "Lindsay Fünke" }
323
- end
324
- end
325
- end
326
-
327
- it "changes the request parameters for one-line resource creation" do
328
- @user = Foo::User.create(:fullname => "Tobias Fünke")
329
- @user.fullname.should == "Lindsay Fünke"
330
- end
331
-
332
- it "changes the request parameters for Model.new + #save" do
333
- @user = Foo::User.new(:fullname => "Tobias Fünke")
334
- @user.save
335
- @user.fullname.should == "Lindsay Fünke"
336
- end
337
- end
338
-
339
- context "checking resource equality" do
340
- before do
341
- Her::API.setup :url => "https://api.example.com" do |builder|
342
- builder.use Her::Middleware::FirstLevelParseJSON
343
- builder.use Faraday::Request::UrlEncoded
344
- builder.adapter :test do |stub|
345
- stub.get("/users/1") { |env| [200, {}, { :id => 1, :fullname => "Lindsay Fünke" }.to_json] }
346
- stub.get("/users/2") { |env| [200, {}, { :id => 1, :fullname => "Tobias Fünke" }.to_json] }
347
- stub.get("/admins/1") { |env| [200, {}, { :id => 1, :fullname => "Lindsay Fünke" }.to_json] }
348
- end
349
- end
350
-
351
- spawn_model "Foo::User"
352
- spawn_model "Foo::Admin"
353
- end
354
-
355
- let(:user) { Foo::User.find(1) }
356
-
357
- it "returns true for the exact same object" do
358
- user.should == user
359
- end
360
-
361
- it "returns true for the same resource via find" do
362
- user.should == Foo::User.find(1)
363
- end
364
-
365
- it "returns true for the same class with identical data" do
366
- user.should == Foo::User.new(:id => 1, :fullname => "Lindsay Fünke")
367
- end
368
-
369
- it "returns true for a different resource with the same data" do
370
- user.should == Foo::Admin.find(1)
371
- end
372
-
373
- it "returns false for the same class with different data" do
374
- user.should_not == Foo::User.new(:id => 2, :fullname => "Tobias Fünke")
375
- end
376
-
377
- it "returns false for a non-resource with the same data" do
378
- fake_user = stub(:data => { :id => 1, :fullname => "Lindsay Fünke" })
379
- user.should_not == fake_user
380
- end
381
-
382
- it "delegates eql? to ==" do
383
- other = Object.new
384
- user.should_receive(:==).with(other).and_return(true)
385
- user.eql?(other).should be_true
386
- end
387
-
388
- it "treats equal resources as equal for Array#uniq" do
389
- user2 = Foo::User.find(1)
390
- [user, user2].uniq.should == [user]
391
- end
392
-
393
- it "treats equal resources as equal for hash keys" do
394
- Foo::User.find(1)
395
- hash = { user => true }
396
- hash[Foo::User.find(1)] = false
397
- hash.size.should == 1
398
- hash.should == { user => false }
399
- end
400
- end
401
-
402
321
  end
@@ -2,8 +2,8 @@
2
2
  require File.join(File.dirname(__FILE__), "../spec_helper.rb")
3
3
 
4
4
  describe Her::Model::Parse do
5
- context "when include_root_in_json is true" do
6
- context "when include_root_in_json is true" do
5
+ context "when include_root_in_json is set" do
6
+ context "to true" do
7
7
  before do
8
8
  spawn_model "Foo::User" do
9
9
  include_root_in_json true
@@ -16,7 +16,7 @@ describe Her::Model::Parse do
16
16
  end
17
17
  end
18
18
 
19
- context "when include_root_in_json is set to another value" do
19
+ context "to a symbol" do
20
20
  before do
21
21
  spawn_model "Foo::User" do
22
22
  include_root_in_json :person
@@ -29,7 +29,7 @@ describe Her::Model::Parse do
29
29
  end
30
30
  end
31
31
 
32
- context "when include_root_in_json is set in the parent class" do
32
+ context "in the parent class" do
33
33
  before do
34
34
  spawn_model("Foo::Model") { include_root_in_json true }
35
35
 
@@ -52,7 +52,7 @@ describe Her::Model::Parse do
52
52
  end
53
53
  end
54
54
 
55
- context "when parse_root_in_json is true" do
55
+ context "to true" do
56
56
  before do
57
57
  Her::API.default_api.connection.adapter :test do |stub|
58
58
  stub.post("/users") { |env| [200, {}, { :user => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
@@ -87,7 +87,7 @@ describe Her::Model::Parse do
87
87
  end
88
88
  end
89
89
 
90
- context "when parse_root_in_json is set to a symbol" do
90
+ context "to a symbol" do
91
91
  before do
92
92
  Her::API.default_api.connection.adapter :test do |stub|
93
93
  stub.post("/users") { |env| [200, {}, { :person => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
@@ -102,7 +102,7 @@ describe Her::Model::Parse do
102
102
  end
103
103
  end
104
104
 
105
- context "when parse_root_in_json is set from the parent class" do
105
+ context "in the parent class" do
106
106
  before do
107
107
  Her::API.default_api.connection.adapter :test do |stub|
108
108
  stub.post("/users") { |env| [200, {}, { :user => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
@@ -122,4 +122,33 @@ describe Her::Model::Parse do
122
122
  end
123
123
  end
124
124
  end
125
+
126
+ context "when to_params is set" do
127
+ before do
128
+ Her::API.setup :url => "https://api.example.com" do |builder|
129
+ builder.use Her::Middleware::FirstLevelParseJSON
130
+ builder.use Faraday::Request::UrlEncoded
131
+ builder.adapter :test do |stub|
132
+ stub.post("/users") { |env| ok! :id => 1, :fullname => params(env)['fullname'] }
133
+ end
134
+ end
135
+
136
+ spawn_model "Foo::User" do
137
+ def to_params
138
+ { :fullname => "Lindsay Fünke" }
139
+ end
140
+ end
141
+ end
142
+
143
+ it "changes the request parameters for one-line resource creation" do
144
+ @user = Foo::User.create(:fullname => "Tobias Fünke")
145
+ @user.fullname.should == "Lindsay Fünke"
146
+ end
147
+
148
+ it "changes the request parameters for Model.new + #save" do
149
+ @user = Foo::User.new(:fullname => "Tobias Fünke")
150
+ @user.save
151
+ @user.fullname.should == "Lindsay Fünke"
152
+ end
153
+ end
125
154
  end