her 0.3.8 → 0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -372,6 +372,58 @@ The available hooks are:
372
372
  * `after_destroy`
373
373
  * `after_find`
374
374
 
375
+ ### JSON attributes-wrapping
376
+
377
+ Her supports *sending* and *parsing* JSON data wrapped in a root element (to be compatible with Rails’ `include_root_in_json` setting), like so:
378
+
379
+ #### Sending
380
+
381
+ If you want to send all data to your API wrapped in a *root* element based on the model name.
382
+
383
+ ```ruby
384
+ class User
385
+ include Her::Model
386
+ include_root_in_json true
387
+ end
388
+
389
+ class Article
390
+ include Her::Model
391
+ include_root_in_json :post
392
+ end
393
+
394
+ User.create(:fullname => "Tobias Fünke")
395
+ # POST { "user": { "fullname": "Tobias Fünke" } } to /users
396
+
397
+ Article.create(:title => "Hello world.")
398
+ # POST { "post": { "title": "Hello world." } } to /articles
399
+ ```
400
+
401
+ #### Parsing
402
+
403
+ If the API returns data wrapped in a *root* element based on the model name.
404
+
405
+ ```ruby
406
+ class User
407
+ include Her::Model
408
+ parse_root_in_json true
409
+ end
410
+
411
+ class Article
412
+ include Her::Model
413
+ parse_root_in_json :post
414
+ end
415
+
416
+ # POST /users returns { "user": { "fullname": "Tobias Fünke" } }
417
+ user = User.create(:fullname => "Tobias Fünke")
418
+ user.fullname # => "Tobias Fünke"
419
+
420
+ # POST /articles returns { "post": { "title": "Hello world." } }
421
+ article = Article.create(:title => "Hello world.")
422
+ article.title # => "Hello world."
423
+ ```
424
+
425
+ Of course, you can use both `include_root_in_json` and `parse_root_in_json` at the same time.
426
+
375
427
  ### Custom requests
376
428
 
377
429
  You can easily define custom requests for your models using `custom_get`, `custom_post`, etc.
@@ -662,6 +714,7 @@ These fine folks helped with Her:
662
714
  * [@pencil](https://github.com/pencil)
663
715
  * [@joanniclaborde](https://github.com/joanniclaborde)
664
716
  * [@seanreads](https://github.com/seanreads)
717
+ * [@jonkarna](https://github.com/jonkarna)
665
718
 
666
719
  ## License
667
720
 
@@ -33,7 +33,8 @@ module Her
33
33
  extend Her::Model::Hooks
34
34
 
35
35
  # Define default settings
36
- base_path = self.name.split("::").last.underscore.pluralize
36
+ root_element self.name.split("::").last.underscore
37
+ base_path = root_element.pluralize
37
38
  collection_path "#{base_path}"
38
39
  resource_path "#{base_path}/:id"
39
40
  uses_api Her::API.default_api
@@ -24,7 +24,7 @@ module Her
24
24
  # @private
25
25
  def self.initialize_collection(klass, parsed_data={})
26
26
  collection_data = parsed_data[:data].map do |item_data|
27
- resource = klass.new(item_data)
27
+ resource = klass.new(klass.parse(item_data))
28
28
  klass.wrap_in_hooks(resource, :find)
29
29
  resource
30
30
  end
@@ -150,7 +150,7 @@ module Her
150
150
 
151
151
  self.class.wrap_in_hooks(resource, *hooks) do |resource, klass|
152
152
  klass.request(params.merge(:_method => method, :_path => "#{request_path}")) do |parsed_data|
153
- self.data = parsed_data[:data] if parsed_data[:data].any?
153
+ self.data = self.class.parse(parsed_data[:data]) if parsed_data[:data].any?
154
154
  self.metadata = parsed_data[:metadata]
155
155
  self.errors = parsed_data[:errors]
156
156
 
@@ -171,7 +171,7 @@ module Her
171
171
  resource = self
172
172
  self.class.wrap_in_hooks(resource, :destroy) do |resource, klass|
173
173
  klass.request(:_method => :delete, :_path => "#{request_path}") do |parsed_data|
174
- self.data = parsed_data[:data]
174
+ self.data = self.class.parse(parsed_data[:data])
175
175
  self.metadata = parsed_data[:metadata]
176
176
  self.errors = parsed_data[:errors]
177
177
  end
@@ -185,7 +185,11 @@ module Her
185
185
  # @user.to_params
186
186
  # # => { :id => 1, :name => 'John Smith' }
187
187
  def to_params
188
- @data.dup
188
+ if self.class.include_root_in_json
189
+ { (self.class.include_root_in_json == true ? self.class.root_element : self.class.include_root_in_json) => @data.dup }
190
+ else
191
+ @data.dup
192
+ end
189
193
  end
190
194
 
191
195
  module ClassMethods
@@ -196,6 +200,17 @@ module Her
196
200
  Her::Model::ORM.initialize_collection(self, parsed_data)
197
201
  end
198
202
 
203
+ # Parse data before assigning it to a resource
204
+ #
205
+ # @param [Hash] data
206
+ def parse(data)
207
+ if parse_root_in_json
208
+ parse_root_in_json == true ? data[root_element.to_sym] : data[parse_root_in_json]
209
+ else
210
+ data
211
+ end
212
+ end
213
+
199
214
  # Fetch specific resource(s) by their ID
200
215
  #
201
216
  # @example
@@ -210,7 +225,7 @@ module Her
210
225
  results = ids.flatten.compact.uniq.map do |id|
211
226
  resource = nil
212
227
  request(params.merge(:_method => :get, :_path => "#{build_request_path(params.merge(:id => id))}")) do |parsed_data|
213
- resource = new(parsed_data[:data].merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
228
+ resource = new(parse(parsed_data[:data]).merge :_metadata => parsed_data[:data], :_errors => parsed_data[:errors])
214
229
  wrap_in_hooks(resource, :find)
215
230
  end
216
231
  resource
@@ -243,8 +258,9 @@ module Her
243
258
  wrap_in_hooks(resource, :create, :save) do |resource, klass|
244
259
  params = resource.to_params
245
260
  request(params.merge(:_method => :post, :_path => "#{build_request_path(params)}")) do |parsed_data|
261
+ data = parse(parsed_data[:data])
246
262
  resource.instance_eval do
247
- @data = parsed_data[:data]
263
+ @data = data
248
264
  @metadata = parsed_data[:metadata]
249
265
  @errors = parsed_data[:errors]
250
266
  end
@@ -271,7 +287,7 @@ module Her
271
287
  # # Called via DELETE "/users/1"
272
288
  def destroy_existing(id, params={})
273
289
  request(params.merge(:_method => :delete, :_path => "#{build_request_path(params.merge(:id => id))}")) do |parsed_data|
274
- new(parsed_data[:data])
290
+ new(parse(parsed_data[:data]))
275
291
  end
276
292
  end
277
293
 
@@ -282,6 +298,18 @@ module Her
282
298
  memo
283
299
  end
284
300
  end
301
+
302
+ # Return or change the value of `include_root_in_json`
303
+ def include_root_in_json(value=nil)
304
+ return @include_root_in_json if value.nil?
305
+ @include_root_in_json = value
306
+ end
307
+
308
+ # Return or change the value of `parse_root_in`
309
+ def parse_root_in_json(value=nil)
310
+ return @parse_root_in_json if value.nil?
311
+ @parse_root_in_json = value
312
+ end
285
313
  end
286
314
  end
287
315
  end
@@ -16,6 +16,7 @@ module Her
16
16
  end
17
17
 
18
18
  module ClassMethods
19
+
19
20
  # Defines a custom collection path for the resource
20
21
  #
21
22
  # @example
@@ -69,6 +70,12 @@ module Her
69
70
  parameters.delete($1.to_sym) || parameters.delete("_#{$1}".to_sym) || raise(Her::Errors::PathError.new("Missing :_#{$1} parameter to build the request path (#{path})."))
70
71
  end
71
72
  end
73
+
74
+ # Return or change the value of `root_element`
75
+ def root_element(value=nil)
76
+ return @root_element if value.nil?
77
+ @root_element = value
78
+ end
72
79
  end
73
80
  end
74
81
  end
@@ -1,3 +1,3 @@
1
1
  module Her
2
- VERSION = "0.3.8"
2
+ VERSION = "0.4"
3
3
  end
@@ -462,4 +462,91 @@ describe Her::Model::ORM do
462
462
  hash.should == { user => false }
463
463
  end
464
464
  end
465
+
466
+ context "when include_root_in_json is true" do
467
+ context "when include_root_in_json is true" do
468
+ before do
469
+ spawn_model "Foo::User" do
470
+ include_root_in_json true
471
+ end
472
+ end
473
+
474
+ it "wraps params in the element name" do
475
+ @new_user = Foo::User.new(:fullname => "Tobias Fünke")
476
+ @new_user.to_params.should == { 'user' => { :fullname => "Tobias Fünke" } }
477
+ end
478
+ end
479
+
480
+ context "when include_root_in_json is set to another value" do
481
+ before do
482
+ spawn_model "Foo::User" do
483
+ include_root_in_json :person
484
+ end
485
+ end
486
+
487
+ it "wraps params in the specified value" do
488
+ @new_user = Foo::User.new(:fullname => "Tobias Fünke")
489
+ @new_user.to_params.should == { :person => { :fullname => "Tobias Fünke" } }
490
+ end
491
+ end
492
+ end
493
+
494
+ context "when parse_root_in_json is set" do
495
+ before do
496
+ Her::API.setup :url => "https://api.example.com" do |builder|
497
+ builder.use Her::Middleware::FirstLevelParseJSON
498
+ builder.use Faraday::Request::UrlEncoded
499
+ end
500
+ end
501
+
502
+ context "when parse_root_in_json is true" do
503
+ before do
504
+ Her::API.default_api.connection.adapter :test do |stub|
505
+ stub.post("/users") { |env| [200, {}, { :user => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
506
+ stub.get("/users") { |env| [200, {}, [{ :user => { :id => 1, :fullname => "Lindsay Fünke" } }].to_json] }
507
+ stub.get("/users/1") { |env| [200, {}, { :user => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
508
+ stub.put("/users/1") { |env| [200, {}, { :user => { :id => 1, :fullname => "Tobias Fünke Jr." } }.to_json] }
509
+ end
510
+
511
+ spawn_model("Foo::User") { parse_root_in_json true }
512
+ end
513
+
514
+ it "parse the data from the JSON root element after .create" do
515
+ @new_user = Foo::User.create(:fullname => "Lindsay Fünke")
516
+ @new_user.fullname.should == "Lindsay Fünke"
517
+ end
518
+
519
+ it "parse the data from the JSON root element after .all" do
520
+ @users = Foo::User.all
521
+ @users.first.fullname.should == "Lindsay Fünke"
522
+ end
523
+
524
+ it "parse the data from the JSON root element after .find" do
525
+ @user = Foo::User.find(1)
526
+ @user.fullname.should == "Lindsay Fünke"
527
+ end
528
+
529
+ it "parse the data from the JSON root element after .save" do
530
+ @user = Foo::User.find(1)
531
+ @user.fullname = "Tobias Fünke"
532
+ @user.save
533
+ @user.fullname.should == "Tobias Fünke Jr."
534
+ end
535
+ end
536
+
537
+ context "when parse_root_in_json is set to a symbol" do
538
+ before do
539
+ Her::API.default_api.connection.adapter :test do |stub|
540
+ stub.post("/users") { |env| [200, {}, { :person => { :id => 1, :fullname => "Lindsay Fünke" } }.to_json] }
541
+ end
542
+
543
+ spawn_model("Foo::User") { parse_root_in_json :person }
544
+ end
545
+
546
+ it "parse the data with the symbol" do
547
+ @new_user = Foo::User.create(:fullname => "Lindsay Fünke")
548
+ @new_user.fullname.should == "Lindsay Fünke"
549
+ end
550
+ end
551
+ end
465
552
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: her
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.8
4
+ version: '0.4'
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-01-14 00:00:00.000000000 Z
12
+ date: 2013-01-19 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rake
@@ -177,7 +177,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
177
177
  version: '0'
178
178
  segments:
179
179
  - 0
180
- hash: -2988245247515927159
180
+ hash: -2845158545991818661
181
181
  required_rubygems_version: !ruby/object:Gem::Requirement
182
182
  none: false
183
183
  requirements:
@@ -186,10 +186,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  version: '0'
187
187
  segments:
188
188
  - 0
189
- hash: -2988245247515927159
189
+ hash: -2845158545991818661
190
190
  requirements: []
191
191
  rubyforge_project:
192
- rubygems_version: 1.8.24
192
+ rubygems_version: 1.8.23
193
193
  signing_key:
194
194
  specification_version: 3
195
195
  summary: A simple Representational State Transfer-based Hypertext Transfer Protocol-powered