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
checksums.yaml CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- OWFlMWJkMGQ3ODVkOTdhZGVmNDM3MDE3OTJiYTIxMThjNDZkZDVhYw==
4
+ NWYxMjI2MTQ0YjdhOTYyNDA1YTkwZjU4MTNhMDFjZDQ1OTM0OTczMQ==
5
5
  data.tar.gz: !binary |-
6
- ODljYTk3MjhiNjhmYWM1MjQ1NDczZmJmNjIxYmMxNDA0NDk0ZDU0MQ==
6
+ ZDk0YzAxYjUzYTlmMGU4Y2FkMGQ0NGQ2MDM0YjM2MjBlZmRmMGVhZg==
7
7
  !binary "U0hBNTEy":
8
8
  metadata.gz: !binary |-
9
- NjlmZmY0MzUxZmZlZjY0MzRkODg3YmM0MzQ1YzI4MDdjOTE5NTM1YTc0NTcw
10
- OGZiYjgyMzA3YTlmMGRmMzAyNjRiMzQwZjQ3YjM1ODFmYTQzMDNkZmRmMzBk
11
- ZTRkNWUxZWM2Mzk4NmJlNTQ2YmU1YWQwZmRmNzIxZDFkYjk0NTM=
9
+ ZDE1MWExN2JkZDY5OGYwNWFkMGZhYTVhZDE1MzEzYjMxYjc3YTU3NDc0MDQ4
10
+ OWMyOTEwMzY3ZTE4OGIxMTNiODlhZDExZGNjMzVlMjYzMWY1ZWNmZGVlM2Qz
11
+ Yjk2ZWRkZDkxMGU0MmJlMmU2ZjU0ZGI3ODA3ZWU2NDUzNTcxZWQ=
12
12
  data.tar.gz: !binary |-
13
- ZmExYTE0MzIyODFjN2JiYzAxOGUxM2ZhMzIzNjRiYjc4MjVlYjQxMTBlMWU2
14
- ZmE4ZjE2ZDU2YzI0YmIyNjIxZGQ5M2I1MzJlMDU1NzkwNWFiMDk0NmRlN2Vh
15
- NDZkMWYxOTNiZDRkNmE0NThjOWFlZjNhZDc4OGMxZjE5NjY2NmI=
13
+ OTcxYzViZjM1MDVkMDJjODhlZTlkN2M3MTliYzRmZDE1NzQ4NDMzMDgzYzhk
14
+ NjNhMGIwMjUxNzFiMzA4Mjg2NmE3OTQzNWRhNWNiMDIyM2Q4MzVlMDk3OWM3
15
+ OTAwNTBlNWYxMmY1MWUwMTlkOWFlYTZkY2E1NDA3NGFkNDdjZjk=
data/.gitignore CHANGED
@@ -1,6 +1,6 @@
1
1
  *.gem
2
2
  .bundle
3
- Gemfile.lock
3
+ /Gemfile.lock
4
4
  pkg/*
5
5
  rake
6
6
  tmp
data/README.md CHANGED
@@ -1,4 +1,14 @@
1
- # Her [![Build Status](https://secure.travis-ci.org/remiprev/her.png?branch=master)](http://travis-ci.org/remiprev/her) [![Gem dependency status](https://gemnasium.com/remiprev/her.png?travis)](https://gemnasium.com/remiprev/her)
1
+ # Her
2
+
3
+ [![Gem Version](https://badge.fury.io/rb/her.png)][gem]
4
+ [![Build Status](https://secure.travis-ci.org/remiprev/her.png?branch=master)][travis]
5
+ [![Dependency Status](https://gemnasium.com/remiprev/her.png?travis)][gemnasium]
6
+ [![Code Climate](https://codeclimate.com/github/remiprev/her.png)][codeclimate]
7
+
8
+ [gem]: https://rubygems.org/gems/her
9
+ [travis]: http://travis-ci.org/remiprev/her
10
+ [gemnasium]: https://gemnasium.com/remiprev/her
11
+ [codeclimate]: https://codeclimate.com/github/remiprev/her
2
12
 
3
13
  Her is an ORM (Object Relational Mapper) that maps REST resources to Ruby objects. It is designed to build applications that are powered by a RESTful API instead of a database.
4
14
 
@@ -18,7 +28,7 @@ First, you have to define which API your models will be bound to. For example, w
18
28
 
19
29
  ```ruby
20
30
  # config/initializers/her.rb
21
- Her::API.setup :url => "https://api.example.com" do |connection|
31
+ Her::API.setup url: "https://api.example.com" do |connection|
22
32
  connection.use Faraday::Request::UrlEncoded
23
33
  connection.use Her::Middleware::DefaultParseJSON
24
34
  connection.use Faraday::Adapter::NetHttp
@@ -42,10 +52,10 @@ User.all
42
52
  User.find(1)
43
53
  # GET https://api.example.com/users/1 and return a User object
44
54
 
45
- @user = User.create(:fullname => "Tobias Fünke")
55
+ @user = User.create(fullname: "Tobias Fünke")
46
56
  # POST "https://api.example.com/users" with the data and return a User object
47
57
 
48
- @user = User.new(:fullname => "Tobias Fünke")
58
+ @user = User.new(fullname: "Tobias Fünke")
49
59
  @user.occupation = "actor"
50
60
  @user.save
51
61
  # POST https://api.example.com/users with the data and return a User object
@@ -68,11 +78,11 @@ end
68
78
  # Update a fetched resource
69
79
  user = User.find(1)
70
80
  user.fullname = "Lindsay Fünke"
71
- # OR user.assign_attributes :fullname => "Lindsay Fünke"
81
+ # OR user.assign_attributes(fullname: "Lindsay Fünke")
72
82
  user.save
73
83
 
74
84
  # Update a resource without fetching it
75
- User.save_existing(1, :fullname => "Lindsay Fünke")
85
+ User.save_existing(1, fullname: "Lindsay Fünke")
76
86
 
77
87
  # Destroy a fetched resource
78
88
  user = User.find(1)
@@ -83,20 +93,21 @@ User.destroy_existing(1)
83
93
 
84
94
  # Fetching a collection of resources
85
95
  User.all
96
+ User.where(moderator: 1).all
86
97
 
87
98
  # Create a new resource
88
- User.create(:fullname => "Maeby Fünke")
99
+ User.create(fullname: "Maeby Fünke")
89
100
 
90
101
  # Save a new resource
91
- user = User.new(:fullname => "Maeby Fünke")
102
+ user = User.new(fullname: "Maeby Fünke")
92
103
  user.save
93
104
  ```
94
105
 
95
- You can look into the `examples` directory for a sample application using Her. For a complete reference of all the methods you can use, check out [the documentation](http://rdoc.info/github/remiprev/her).
106
+ You can look into the [`her-example`](https://github.com/remiprev/her-example) repository for a sample application using Her. For a complete reference of all the methods you can use, check out [the documentation](http://rdoc.info/github/remiprev/her).
96
107
 
97
108
  ## Middleware
98
109
 
99
- Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can choose the middleware used to handle requests and responses. Using the block in the `setup` call, you have access to Faraday’s `connection` object and are able to customize the middleware stack used on each request and response.
110
+ Since Her relies on [Faraday](https://github.com/lostisland/faraday) to send HTTP requests, you can choose the middleware used to handle requests and responses. Using the block in the `setup` call, you have access to Faraday’s `connection` object and are able to customize the middleware stack used on each request and response.
100
111
 
101
112
  ### Authentication
102
113
 
@@ -126,7 +137,7 @@ end
126
137
  # config/initializers/her.rb
127
138
  require "lib/my_token_authentication"
128
139
 
129
- Her::API.setup :url => "https://api.example.com" do |connection|
140
+ Her::API.setup url: "https://api.example.com" do |connection|
130
141
  connection.use MyTokenAuthentication
131
142
  connection.use Faraday::Request::UrlEncoded
132
143
  connection.use Her::Middleware::DefaultParseJSON
@@ -153,13 +164,13 @@ In your Ruby code:
153
164
  ```ruby
154
165
  # Create an application on `https://dev.twitter.com/apps` to set these values
155
166
  TWITTER_CREDENTIALS = {
156
- :consumer_key => "",
157
- :consumer_secret => "",
158
- :token => "",
159
- :token_secret => ""
167
+ consumer_key: "",
168
+ consumer_secret: "",
169
+ token: "",
170
+ token_secret: ""
160
171
  }
161
172
 
162
- Her::API.setup :url => "https://api.twitter.com/1/" do |connection|
173
+ Her::API.setup url: "https://api.twitter.com/1/" do |connection|
163
174
  connection.use FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
164
175
  connection.use Her::Middleware::DefaultParseJSON
165
176
  connection.use Faraday::Adapter::NetHttp
@@ -188,7 +199,7 @@ By default, Her handles JSON data. It expects the resource/collection data to be
188
199
 
189
200
  However, if you want Her to be able to parse the data from a single root element (usually based on the model name), you’ll have to use the `parse_root_in_json` method (See the **JSON attributes-wrapping** section).
190
201
 
191
- Also, you can define your own parsing method using a response middleware. The middleware should set `env[:body]` to a hash with three keys: `data`, `errors` and `metadata`. The following code uses a custom middleware to parse the JSON data:
202
+ Also, you can define your own parsing method using a response middleware. The middleware should set `env[:body]` to a hash with three symbol keys: `:data`, `:errors` and `:metadata`. The following code uses a custom middleware to parse the JSON data:
192
203
 
193
204
  ```ruby
194
205
  # Expects responses like:
@@ -198,21 +209,21 @@ Also, you can define your own parsing method using a response middleware. The mi
198
209
  # "id": 1,
199
210
  # "name": "Tobias Fünke"
200
211
  # },
201
- # "errors" => []
212
+ # "errors": []
202
213
  # }
203
214
  #
204
215
  class MyCustomParser < Faraday::Response::Middleware
205
216
  def on_complete(env)
206
- json = MultiJson.load(env[:body], :symbolize_keys => true)
217
+ json = MultiJson.load(env[:body], symbolize_keys: true)
207
218
  env[:body] = {
208
- :data => json[:result],
209
- :errors => json[:errors],
210
- :metadata => json[:metadata]
219
+ data: json[:result],
220
+ errors: json[:errors],
221
+ metadata: json[:metadata]
211
222
  }
212
223
  end
213
224
  end
214
225
 
215
- Her::API.setup :url => "https://api.example.com" do |connection|
226
+ Her::API.setup url: "https://api.example.com" do |connection|
216
227
  connection.use MyCustomParser
217
228
  connection.use Faraday::Adapter::NetHttp
218
229
  end
@@ -233,7 +244,7 @@ gem "memcached"
233
244
  In your Ruby code:
234
245
 
235
246
  ```ruby
236
- Her::API.setup :url => "https://api.example.com" do |connection|
247
+ Her::API.setup url: "https://api.example.com" do |connection|
237
248
  connection.use FaradayMiddleware::Caching, Memcached::Rails.new('127.0.0.1:11211')
238
249
  connection.use Her::Middleware::DefaultParseJSON
239
250
  connection.use Faraday::Adapter::NetHttp
@@ -289,14 +300,14 @@ If there’s association data in the resource, no extra HTTP request is made whe
289
300
  ```ruby
290
301
  @user = User.find(1)
291
302
  # {
292
- # :id => 1,
293
- # :name => "George Michael Bluth",
294
- # :comments => [
295
- # { :id => 1, :text => "Foo" },
296
- # { :id => 2, :text => "Bar" }
303
+ # "id": 1,
304
+ # "name": "George Michael Bluth",
305
+ # "comments": [
306
+ # { "id": 1, "text": "Foo" },
307
+ # { "id": 2, "text": "Bar" }
297
308
  # ],
298
- # :role => { :id => 1, :name => "Admin" },
299
- # :organization => { :id => 2, :name => "Bluth Company" }
309
+ # "role": { "id": 1, "name": "Admin" },
310
+ # "organization": { "id": 2, "name": "Bluth Company" }
300
311
  # }
301
312
  @user.comments
302
313
  # [#<Comment id=1 text="Foo">, #<Comment id=2 text="Bar">]
@@ -310,13 +321,17 @@ If there’s no association data in the resource, Her makes a HTTP request to re
310
321
 
311
322
  ```ruby
312
323
  @user = User.find(1)
313
- # { :id => 1, :name => "George Michael Bluth", :organization_id => 2 }
324
+ # { "id": 1, "name": "George Michael Bluth", "organization_id": 2 }
314
325
 
315
326
  # has_many association:
316
327
  @user.comments
317
328
  # GET /users/1/comments
318
329
  # [#<Comment id=1>, #<Comment id=2>]
319
330
 
331
+ @user.comments.where(approved: 1)
332
+ # GET /users/1/comments?approved=1
333
+ # [#<Comment id=1>]
334
+
320
335
  # has_one association:
321
336
  @user.role
322
337
  # GET /users/1/role
@@ -364,11 +379,11 @@ class User
364
379
  include Her::Model
365
380
 
366
381
  attributes :fullname, :email
367
- validates :fullname, :presence => true
368
- validates :email, :presence => true
382
+ validates :fullname, presence: true
383
+ validates :email, presence: true
369
384
  end
370
385
 
371
- @user = User.new(:fullname => "Tobias Fünke")
386
+ @user = User.new(fullname: "Tobias Fünke")
372
387
  @user.valid? # => false
373
388
 
374
389
  @user.save
@@ -386,7 +401,7 @@ class User
386
401
  attributes :fullname, :email
387
402
  end
388
403
 
389
- @user = User.new(:fullname => "Tobias Fünke")
404
+ @user = User.new(fullname: "Tobias Fünke")
390
405
  @user.fullname_changed? # => true
391
406
  @user.changes # => { :fullname => [nil, "Tobias Fünke"] }
392
407
 
@@ -412,7 +427,7 @@ class User
412
427
  end
413
428
  end
414
429
 
415
- @user = User.create(:fullname => "Tobias Funke")
430
+ @user = User.create(fullname: "Tobias Funke")
416
431
  # POST /users&fullname=Tobias+Fünke&internal_id=42
417
432
 
418
433
  @user = User.find(1)
@@ -450,10 +465,10 @@ class Article
450
465
  include_root_in_json :post
451
466
  end
452
467
 
453
- User.create(:fullname => "Tobias Fünke")
468
+ User.create(fullname: "Tobias Fünke")
454
469
  # POST { "user": { "fullname": "Tobias Fünke" } } to /users
455
470
 
456
- Article.create(:title => "Hello world.")
471
+ Article.create(title: "Hello world.")
457
472
  # POST { "post": { "title": "Hello world." } } to /articles
458
473
  ```
459
474
 
@@ -473,11 +488,11 @@ class Article
473
488
  end
474
489
 
475
490
  # POST /users returns { "user": { "fullname": "Tobias Fünke" } }
476
- user = User.create(:fullname => "Tobias Fünke")
491
+ user = User.create(fullname: "Tobias Fünke")
477
492
  user.fullname # => "Tobias Fünke"
478
493
 
479
494
  # POST /articles returns { "post": { "title": "Hello world." } }
480
- article = Article.create(:title => "Hello world.")
495
+ article = Article.create(title: "Hello world.")
481
496
  article.title # => "Hello world."
482
497
  ```
483
498
 
@@ -502,7 +517,7 @@ User.unpopular
502
517
  # GET /users/unpopular
503
518
  # [#<User id=3>, #<User id=4>]
504
519
 
505
- User.from_default(:name => "Maeby Fünke")
520
+ User.from_default(name: "Maeby Fünke")
506
521
  # POST /users/from_default?name=Maeby+Fünke
507
522
  # #<User id=5 name="Maeby Fünke">
508
523
  ```
@@ -582,13 +597,13 @@ class User
582
597
  collection_path "/organizations/:organization_id/users"
583
598
  end
584
599
 
585
- @user = User.find(1, :_organization_id => 2)
600
+ @user = User.find(1, _organization_id: 2)
586
601
  # GET /organizations/2/users/1
587
602
 
588
- @user = User.all(:_organization_id => 2)
603
+ @user = User.all(_organization_id: 2)
589
604
  # GET /organizations/2/users
590
605
 
591
- @user = User.new(:fullname => "Tobias Fünke", :organization_id => 2)
606
+ @user = User.new(fullname: "Tobias Fünke", organization_id: 2)
592
607
  @user.save
593
608
  # POST /organizations/2/users
594
609
  ```
@@ -603,8 +618,8 @@ class User
603
618
  primary_key :_id
604
619
  end
605
620
 
606
- user = User.find(1) # GET /users/1 returns { "_id": 1, "name": "Tobias" }
607
- user.save # PUT /users/1
621
+ user = User.find("4fd89a42ff204b03a905c535") # GET /users/1 returns { "_id": "4fd89a42ff204b03a905c535", "name": "Tobias" }
622
+ user.save # PUT /users/4fd89a42ff204b03a905c535
608
623
  ```
609
624
 
610
625
  ### Inheritance
@@ -634,14 +649,14 @@ It is possible to use different APIs for different models. Instead of calling `H
634
649
 
635
650
  ```ruby
636
651
  # config/initializers/her.rb
637
- $my_api = Her::API.new
638
- $my_api.setup :url => "https://my_api.example.com" do |connection|
652
+ MY_API = Her::API.new
653
+ MY_API.setup url: "https://my-api.example.com" do |connection|
639
654
  connection.use Her::Middleware::DefaultParseJSON
640
655
  connection.use Faraday::Adapter::NetHttp
641
656
  end
642
657
 
643
- $other_api = Her::API.new
644
- $other_api.setup :url => "https://other_api.example.com" do |connection|
658
+ OTHER_API = Her::API.new
659
+ OTHER_API.setup url: "https://other-api.example.com" do |connection|
645
660
  connection.use Her::Middleware::DefaultParseJSON
646
661
  connection.use Faraday::Adapter::NetHttp
647
662
  end
@@ -652,28 +667,28 @@ You can then define which API a model will use:
652
667
  ```ruby
653
668
  class User
654
669
  include Her::Model
655
- uses_api $my_api
670
+ use_api MY_API
656
671
  end
657
672
 
658
673
  class Category
659
674
  include Her::Model
660
- uses_api $other_api
675
+ use_api OTHER_API
661
676
  end
662
677
 
663
678
  User.all
664
- # GET https://my_api.example.com/users
679
+ # GET https://my-api.example.com/users
665
680
 
666
681
  Category.all
667
- # GET https://other_api.example.com/categories
682
+ # GET https://other-api.example.com/categories
668
683
  ```
669
684
 
670
685
  ### SSL
671
686
 
672
- When initializing `Her::API`, you can pass any parameter supported by `Faraday.new`. So [to use HTTPS](https://github.com/technoweenie/faraday/wiki/Setting-up-SSL-certificates), you can use Faraday’s `:ssl` option.
687
+ When initializing `Her::API`, you can pass any parameter supported by `Faraday.new`. So [to use HTTPS](https://github.com/lostisland/faraday/wiki/Setting-up-SSL-certificates), you can use Faraday’s `:ssl` option.
673
688
 
674
689
  ```ruby
675
- ssl_options = { :ca_path => "/usr/lib/ssl/certs" }
676
- Her::API.setup :url => "https://api.example.com", :ssl => ssl_options do |connection|
690
+ ssl_options = { ca_path: "/usr/lib/ssl/certs" }
691
+ Her::API.setup url: "https://api.example.com", ssl: ssl_options do |connection|
677
692
  connection.use Her::Middleware::DefaultParseJSON
678
693
  connection.use Faraday::Adapter::NetHttp
679
694
  end
@@ -704,11 +719,11 @@ In order to test them, we’ll have to stub the remote API requests. With [RSpec
704
719
  RSpec.configure do |config|
705
720
  config.include(Module.new do
706
721
  def stub_api_for(klass)
707
- klass.uses_api (api = Her::API.new)
722
+ klass.use_api (api = Her::API.new)
708
723
 
709
724
  # Here, you would customize this for your own API (URL, middleware, etc)
710
725
  # like you have done in your application’s initializer
711
- api.setup :url => "http://api.example.com" do |connection|
726
+ api.setup url: "http://api.example.com" do |connection|
712
727
  connection.use Her::Middleware::FirstLevelParseJSON
713
728
  connection.adapter(:test) { |s| yield(s) }
714
729
  end
@@ -724,7 +739,7 @@ Then, in your tests, we can specify what (fake) HTTP requests will return:
724
739
  describe User do
725
740
  before do
726
741
  stub_api_for(User) do |stub|
727
- stub.get("/users/popular") { |env| [200, {}, [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }].to_json] }
742
+ stub.get("/users/popular") { |env| [200, {}, [{ id: 1, name: "Tobias Fünke" }, { id: 2, name: "Lindsay Fünke" }].to_json] }
728
743
  end
729
744
  end
730
745
 
@@ -744,7 +759,7 @@ describe Post do
744
759
  describe :recent do
745
760
  before do
746
761
  stub_api_for(Post) do |stub|
747
- stub.get("/posts/recent") { |env| [200, {}, [{ :id => 1 }, { :id => 2 }].to_json] }
762
+ stub.get("/posts/recent") { |env| [200, {}, [{ id: 1 }, { id: 2 }].to_json] }
748
763
  end
749
764
  end
750
765
 
@@ -756,7 +771,7 @@ describe Post do
756
771
  describe :archived do
757
772
  before do
758
773
  stub_api_for(Post) do |stub|
759
- stub.get("/posts/archived") { |env| [200, {}, [{ :id => 1 }, { :id => 2 }].to_json] }
774
+ stub.get("/posts/archived") { |env| [200, {}, [{ id: 1 }, { id: 2 }].to_json] }
760
775
  end
761
776
  end
762
777
 
data/UPGRADE.md CHANGED
@@ -2,6 +2,27 @@
2
2
 
3
3
  Here is a list of backward-incompatible changes that were introduced while Her is pre-1.0. After reaching 1.0, it will follow the [Semantic Versioning](http://semver.org/) system.
4
4
 
5
+ ## 0.6
6
+
7
+ * Associations have been refactored so that calling the association name method doesn’t immediately load or fetch the data.
8
+
9
+ class User
10
+ include Her::Model
11
+ has_many :comments
12
+ end
13
+
14
+ # This doesn’t fetch the data yet
15
+ comments = User.find(1).comments
16
+
17
+ # This actually fetches the data
18
+ puts comments.inspect
19
+
20
+ # This is no longer possible
21
+ comments = User.find(1).comments(:approved => 1)
22
+
23
+ # To pass additional parameters to the HTTP request, we now have to do this
24
+ comments = User.find(1).comments.where(:approved => 1)
25
+
5
26
  ## 0.5.4
6
27
 
7
28
  * Her does not support Ruby 1.8.7 anymore. You should upgrade to 1.9.2, 1.9.3 or 2.0.0.
data/lib/her/model.rb CHANGED
@@ -1,6 +1,7 @@
1
1
  require "her/model/base"
2
2
  require "her/model/http"
3
3
  require "her/model/attributes"
4
+ require "her/model/relation"
4
5
  require "her/model/orm"
5
6
  require "her/model/parse"
6
7
  require "her/model/associations"
@@ -44,7 +45,7 @@ module Her
44
45
  # Class methods
45
46
  included do
46
47
  # Assign the default API
47
- uses_api Her::API.default_api
48
+ use_api Her::API.default_api
48
49
 
49
50
  # Define the default primary key
50
51
  primary_key :id