her 0.1.1 → 0.1.5
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +3 -0
- data/README.md +156 -10
- data/lib/her/model.rb +1 -0
- data/lib/her/model/http.rb +12 -0
- data/lib/her/model/orm.rb +7 -10
- data/lib/her/model/relationships.rb +37 -9
- data/lib/her/version.rb +1 -1
- data/spec/model_spec.rb +41 -4
- metadata +5 -4
data/LICENSE
ADDED
data/README.md
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
[![Build Status](https://secure.travis-ci.org/remiprev/her.png)](http://travis-ci.org/remiprev/her)
|
4
4
|
|
5
|
-
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.
|
5
|
+
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 and no database.
|
6
6
|
|
7
7
|
## Installation
|
8
8
|
|
@@ -19,6 +19,7 @@ That’s it!
|
|
19
19
|
First, you have to define which API your models will be bound to. For example, with Rails, you would create a new `config/initializers/her.rb` file with this line:
|
20
20
|
|
21
21
|
```ruby
|
22
|
+
# config/initializers/her.rb
|
22
23
|
Her::API.setup :base_uri => "https://api.example.com"
|
23
24
|
```
|
24
25
|
|
@@ -33,15 +34,82 @@ end
|
|
33
34
|
After that, using Her is very similar to many ActiveModel-like ORMs:
|
34
35
|
|
35
36
|
```ruby
|
36
|
-
User.all
|
37
|
-
|
37
|
+
User.all
|
38
|
+
# GET https://api.example.com/users and return an array of User objects
|
39
|
+
|
40
|
+
User.find(1)
|
41
|
+
# GET https://api.example.com/users/1 and return a User object
|
42
|
+
|
43
|
+
@user = User.create(:fullname => "Tobias Fünke")
|
44
|
+
# POST "https://api.example.com/users" with the data and return a User object
|
45
|
+
|
46
|
+
@user = User.new(:fullname => "Tobias Fünke")
|
47
|
+
@user.occupation = "actor"
|
48
|
+
@user.save
|
49
|
+
# POST https://api.example.com/users with the data and return a User object
|
50
|
+
|
51
|
+
@user = User.find(1)
|
52
|
+
@user.fullname = "Lindsay Fünke"
|
53
|
+
@user.save
|
54
|
+
# PUT https://api.example.com/users/1 with the data and return+update the User object
|
55
|
+
```
|
56
|
+
|
57
|
+
## Parsing data
|
58
|
+
|
59
|
+
By default, Her handles JSON data. It expects the data to be formatted in a certain structure. The default is this:
|
60
|
+
|
61
|
+
```javascript
|
62
|
+
// The response of GET /users/1
|
63
|
+
{
|
64
|
+
"data" : {
|
65
|
+
"id" : 1,
|
66
|
+
"name" : "Tobias Fünke"
|
67
|
+
}
|
68
|
+
}
|
69
|
+
|
70
|
+
// The response of GET /users
|
71
|
+
{
|
72
|
+
"data" : [
|
73
|
+
{
|
74
|
+
"id" : 1,
|
75
|
+
"name" : "Tobias Fünke"
|
76
|
+
},
|
77
|
+
{
|
78
|
+
"id" : 2,
|
79
|
+
"name" : "Lindsay Fünke"
|
80
|
+
}
|
81
|
+
],
|
82
|
+
"metadata" : {
|
83
|
+
"page" : 1,
|
84
|
+
"per_page" : 10
|
85
|
+
}
|
86
|
+
}
|
87
|
+
```
|
88
|
+
|
89
|
+
However, you can define your own parsing method, with `Her::API.parse_with`. The `parse_with` method takes a block which will be executed each time data from an HTTP response needs to be parsed. The block is expected to return a hash with three keys: `data`, `errors` and `metadata`. The following code enables parsing JSON data and treating this data as first-level properties:
|
90
|
+
|
91
|
+
```ruby
|
92
|
+
Her::API.setup :base_uri => "https://api.example.com"
|
93
|
+
Her::API.parse_with |response|
|
94
|
+
json = JSON.parse(response.body, :symbolize_names => true)
|
95
|
+
errors = json.delete(:errors)
|
96
|
+
{
|
97
|
+
:data => json,
|
98
|
+
:errors => errors || [],
|
99
|
+
:metadata => {}
|
100
|
+
}
|
101
|
+
end
|
102
|
+
|
103
|
+
# User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "id": 1, "name": "Tobias Fünke" }'
|
38
104
|
```
|
39
105
|
|
106
|
+
This feature is not stable and might change in the future, probably by using a middleware through [Faraday](https://github.com/technoweenie/faraday).
|
107
|
+
|
40
108
|
## Relationships
|
41
109
|
|
42
|
-
You can define `has_many` relationships in your models. The relationship data is handled in two different ways. When parsing a resource from JSON data, if there’s a relationship data included, it will be used to create new Ruby objects.
|
110
|
+
You can define `has_many`, `has_one` and `belongs_to` relationships in your models. The relationship data is handled in two different ways. When parsing a resource from JSON data, if there’s a relationship data included, it will be used to create new Ruby objects.
|
43
111
|
|
44
|
-
If no relationship data was included when parsing a resource, calling a method with the same name as the relationship will fetch the data (providing there’s an HTTP request available for it).
|
112
|
+
If no relationship data was included when parsing a resource, calling a method with the same name as the relationship will fetch the data (providing there’s an HTTP request available for it in the API).
|
45
113
|
|
46
114
|
For example, with this setup:
|
47
115
|
|
@@ -49,32 +117,58 @@ For example, with this setup:
|
|
49
117
|
class User
|
50
118
|
include Her::Model
|
51
119
|
has_many :comments
|
120
|
+
has_one :role
|
121
|
+
belongs_to :organization
|
52
122
|
end
|
53
123
|
|
54
124
|
class Comment
|
55
125
|
include Her::Model
|
56
126
|
end
|
127
|
+
|
128
|
+
class Role
|
129
|
+
include Her::Model
|
130
|
+
end
|
131
|
+
|
132
|
+
class Organization
|
133
|
+
include Her::Model
|
134
|
+
end
|
57
135
|
```
|
58
136
|
|
59
|
-
|
137
|
+
If there’s relationship data in the resource, no extra HTTP request is made when calling the `#comments` method and an array of resources are returned:
|
60
138
|
|
61
139
|
```ruby
|
62
|
-
@user = User.find(1) # { :data => { :id => 1, :name => "
|
140
|
+
@user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth", :comments => [{ :id => 1, :text => "Foo" }, { :id => 2, :text => "Bar" }], :role => { :id => 1, :name => "Admin" }, :organization => { :id => 2, :name => "Bluth Company" } }}
|
63
141
|
@user.comments # => [#<Comment id=1>, #<Comment id=2>] fetched directly from @user
|
142
|
+
@user.role # => #<Role id=1> fetched directly from @user
|
143
|
+
@user.organization # => #<Organization id=2> fetched directly from @user
|
64
144
|
```
|
65
145
|
|
66
146
|
If there’s no relationship data in the resource, an extra HTTP request (to `GET /users/1/comments`) is made when calling the `#comments` method:
|
67
147
|
|
68
148
|
```ruby
|
69
|
-
@user = User.find(1) # { :data => { :id => 1, :name => "
|
149
|
+
@user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth" }}
|
70
150
|
@user.comments # => [#<Comment id=1>, #<Comment id=2>] fetched from /users/1/comments
|
71
151
|
```
|
72
152
|
|
73
|
-
|
153
|
+
For `has_one` relationship, an extra HTTP request (to `GET /users/1/role`) is made when calling the `#role` method:
|
154
|
+
|
155
|
+
```ruby
|
156
|
+
@user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth" }}
|
157
|
+
@user.role # => #<Role id=1> fetched from /users/1/role
|
158
|
+
```
|
159
|
+
|
160
|
+
For `belongs_to` relationship, an extra HTTP request (to `GET /organizations/2`) is made when calling the `#organization` method:
|
161
|
+
|
162
|
+
```ruby
|
163
|
+
@user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth", :organization_id => 2 }}
|
164
|
+
@user.organization # => #<Organization id=2> fetched from /organizations/2
|
165
|
+
```
|
166
|
+
|
167
|
+
However, subsequent calls to `#comments` or `#role` will not trigger the extra HTTP request.
|
74
168
|
|
75
169
|
## Custom requests
|
76
170
|
|
77
|
-
You can easily add custom methods for your models. You can either use `get_collection` (which maps the returned data to a collection of resources), `get_resource` (which maps the returned data to a single resource) or `get_raw` (which yields the parsed data return from the HTTP request).
|
171
|
+
You can easily add custom methods for your models. You can either use `get_collection` (which maps the returned data to a collection of resources), `get_resource` (which maps the returned data to a single resource) or `get_raw` (which yields the parsed data return from the HTTP request). Other HTTP methods are supported (`post_raw`, `put_resource`, etc.)
|
78
172
|
|
79
173
|
```ruby
|
80
174
|
class User
|
@@ -94,3 +188,55 @@ end
|
|
94
188
|
User.popular # => [#<User id=1>, #<User id=2>]
|
95
189
|
User.total # => 42
|
96
190
|
```
|
191
|
+
|
192
|
+
## Multiple APIs
|
193
|
+
|
194
|
+
It is possible to use different APIs for different models. Instead of calling `Her::API.setup`, you can create instances of `Her::API`:
|
195
|
+
|
196
|
+
```ruby
|
197
|
+
# config/initializers/her.rb
|
198
|
+
$my_api = Her::API.new
|
199
|
+
$my_api.setup :base_uri => "https://my_api.example.com"
|
200
|
+
|
201
|
+
$other_api = Her::API.new
|
202
|
+
$other_api.setup :base_uri => "https://other_api.example.com"
|
203
|
+
```
|
204
|
+
|
205
|
+
You can then define which API a model will use:
|
206
|
+
|
207
|
+
```ruby
|
208
|
+
class User
|
209
|
+
include Her::Model
|
210
|
+
uses_api $my_api
|
211
|
+
end
|
212
|
+
|
213
|
+
class Category
|
214
|
+
include Her::Model
|
215
|
+
uses_api $other_api
|
216
|
+
end
|
217
|
+
|
218
|
+
User.all
|
219
|
+
# GET https://my_api.example.com/users
|
220
|
+
|
221
|
+
Category.all
|
222
|
+
# GET https://other_api.example.com/categories
|
223
|
+
```
|
224
|
+
|
225
|
+
## Things to be done
|
226
|
+
|
227
|
+
* Deleting resources
|
228
|
+
* Support for Faraday middleware to handle caching, alternative formats, etc.
|
229
|
+
* Hooks before save, update, create, destroy, etc.
|
230
|
+
* Better error handling
|
231
|
+
* Better introspection for debug
|
232
|
+
* Better documentation
|
233
|
+
|
234
|
+
## Contributors
|
235
|
+
|
236
|
+
Feel free to contribute and submit issues/pull requests [on GitHub](https://github.com/remiprev/her/issues).
|
237
|
+
|
238
|
+
Take a look at the `spec` folder before you do, and make sure `bundle exec rake spec` passes after your modifications :)
|
239
|
+
|
240
|
+
## License
|
241
|
+
|
242
|
+
Her is © 2012 [Rémi Prévost](http://exomel.com) and may be freely distributed under the [LITL license](https://github.com/remiprev/her/blob/master/LICENSE). See the `LICENSE` file.
|
data/lib/her/model.rb
CHANGED
data/lib/her/model/http.rb
CHANGED
@@ -19,6 +19,18 @@ module Her
|
|
19
19
|
@her_collection_path = path
|
20
20
|
end # }}}
|
21
21
|
|
22
|
+
# Defines a custom item path for the resource
|
23
|
+
#
|
24
|
+
# @example
|
25
|
+
# class User
|
26
|
+
# include Her::Model
|
27
|
+
# item_path "user"
|
28
|
+
# end
|
29
|
+
def item_path(path=nil) # {{{
|
30
|
+
return @her_item_path unless path
|
31
|
+
@her_item_path = path
|
32
|
+
end # }}}
|
33
|
+
|
22
34
|
# Main request wrapper around Her::API. Used to make custom request to the API.
|
23
35
|
# @private
|
24
36
|
def request(attrs={}, &block) # {{{
|
data/lib/her/model/orm.rb
CHANGED
@@ -9,15 +9,6 @@ module Her
|
|
9
9
|
@data = self.class.parse_relationships(@data)
|
10
10
|
end # }}}
|
11
11
|
|
12
|
-
# Initialize a collection of resources with raw data from an HTTP request
|
13
|
-
#
|
14
|
-
# @example
|
15
|
-
# User.get("/users/popular") { |data| User.new_collection(data) }
|
16
|
-
def new_collection(parsed_data) # {{{
|
17
|
-
collection_data = parsed_data[:data]
|
18
|
-
Her::Model::ORM.initialize_collection(self.to_s.downcase.to_sym, collection_data)
|
19
|
-
end # }}}
|
20
|
-
|
21
12
|
# Initialize a collection of resources
|
22
13
|
# @private
|
23
14
|
def self.initialize_collection(name, collection_data) # {{{
|
@@ -40,6 +31,12 @@ module Her
|
|
40
31
|
end
|
41
32
|
end # }}}
|
42
33
|
|
34
|
+
# Initialize a collection of resources with raw data from an HTTP request
|
35
|
+
def new_collection(parsed_data) # {{{
|
36
|
+
collection_data = parsed_data[:data]
|
37
|
+
Her::Model::ORM.initialize_collection(self.to_s.downcase.to_sym, collection_data)
|
38
|
+
end # }}}
|
39
|
+
|
43
40
|
# Fetch a specific resource based on an ID
|
44
41
|
def find(id, params={}) # {{{
|
45
42
|
request(params.merge(:_method => :get, :_path => "#{@her_collection_path}/#{id}")) do |parsed_data|
|
@@ -50,7 +47,7 @@ module Her
|
|
50
47
|
# Fetch a collection of resources
|
51
48
|
def all(params={}) # {{{
|
52
49
|
request(params.merge(:_method => :get, :_path => "#{@her_collection_path}")) do |parsed_data|
|
53
|
-
|
50
|
+
new_collection(parsed_data)
|
54
51
|
end
|
55
52
|
end # }}}
|
56
53
|
|
@@ -14,7 +14,15 @@ module Her
|
|
14
14
|
@her_relationships ||= {}
|
15
15
|
@her_relationships.each_pair do |type, relationships|
|
16
16
|
relationships.each do |relationship|
|
17
|
-
|
17
|
+
if data.include?(relationship[:name])
|
18
|
+
if type == :has_many
|
19
|
+
data[relationship[:name]] = Her::Model::ORM.initialize_collection(relationship[:name], data[relationship[:name]])
|
20
|
+
elsif type == :has_one
|
21
|
+
data[relationship[:name]] = Object.const_get(relationship[:name].to_s.classify).new(data[relationship[:name]])
|
22
|
+
elsif type == :belongs_to
|
23
|
+
data[relationship[:name]] = Object.const_get(relationship[:name].to_s.classify).new(data[relationship[:name]])
|
24
|
+
end
|
25
|
+
end
|
18
26
|
end
|
19
27
|
end
|
20
28
|
data
|
@@ -24,9 +32,9 @@ module Her
|
|
24
32
|
#
|
25
33
|
# * `User.has_many :comments` is used to check if the "user" JSON
|
26
34
|
# resource we receive has a `comments` key and map it to an array
|
27
|
-
# of Comment
|
35
|
+
# of Comment objects
|
28
36
|
# * `User.has_many :comments` creates a User.comments method to would
|
29
|
-
# make an extra HTTP request if there was no "comments" key
|
37
|
+
# make an extra HTTP request (to `/users/:id/comments`) if there was no "comments" key
|
30
38
|
def has_many(name, attrs={}) # {{{
|
31
39
|
@her_relationships ||= {}
|
32
40
|
(@her_relationships[:has_many] ||= []) << attrs.merge(:name => name)
|
@@ -38,18 +46,38 @@ module Her
|
|
38
46
|
end
|
39
47
|
end # }}}
|
40
48
|
|
41
|
-
# Define
|
49
|
+
# Define an *has_one* relationship for the resource
|
42
50
|
#
|
43
|
-
# * `User.
|
44
|
-
# resource we receive has
|
45
|
-
#
|
51
|
+
# * `User.has_one :category` is used to check if the "category" JSON
|
52
|
+
# resource we receive has a `category` key and map it to a Category object
|
53
|
+
# * `User.has_one :category` creates a User.category method to would
|
54
|
+
# make an extra HTTP request (to `/users/category`) if there was no "category" key
|
55
|
+
def has_one(name, attrs={}) # {{{
|
56
|
+
@her_relationships ||= {}
|
57
|
+
(@her_relationships[:has_one] ||= []) << attrs.merge(:name => name)
|
58
|
+
collection_path = @her_collection_path
|
59
|
+
|
60
|
+
define_method(name) do
|
61
|
+
return @data[name] if @data.include?(name) # Do not fetch from API again if we have it in @data
|
62
|
+
self.class.get_resource("#{collection_path}/#{id}/#{Object.const_get(name.to_s.classify).item_path}")
|
63
|
+
end
|
64
|
+
end # }}}
|
65
|
+
|
66
|
+
# Define a *belongs_to* relationship for the resource
|
46
67
|
#
|
47
|
-
# * `User.belongs_to :
|
68
|
+
# * `User.belongs_to :organization` is used to check if the "organization" JSON
|
69
|
+
# resource we receive has a `organization` key and map it to an Organization object
|
70
|
+
# * `User.belongs_to :organization` creates a User.organization method to would
|
71
|
+
# make an extra HTTP request (to `/organizations/:organization_id`) if there was no "organization" key
|
48
72
|
def belongs_to(name, attrs={}) # {{{
|
49
73
|
@her_relationships ||= {}
|
50
74
|
(@her_relationships[:belongs_to] ||= []) << attrs.merge(:name => name)
|
75
|
+
collection_path = @her_collection_path
|
51
76
|
|
52
|
-
|
77
|
+
define_method(name) do
|
78
|
+
return @data[name] if @data.include?(name) # Do not fetch from API again if we have it in @data
|
79
|
+
self.class.get_resource("#{Object.const_get(name.to_s.classify).collection_path}/#{@data["#{name}_id".to_sym]}")
|
80
|
+
end
|
53
81
|
end # }}}
|
54
82
|
end
|
55
83
|
end
|
data/lib/her/version.rb
CHANGED
data/spec/model_spec.rb
CHANGED
@@ -214,12 +214,12 @@ describe Her::Model do
|
|
214
214
|
end
|
215
215
|
end # }}}
|
216
216
|
|
217
|
-
it "handle resource data update without saving it" do
|
217
|
+
it "handle resource data update without saving it" do # {{{
|
218
218
|
@user = User.find(1)
|
219
219
|
@user.fullname.should == "Tobias Fünke"
|
220
220
|
@user.fullname = "Kittie Sanchez"
|
221
221
|
@user.fullname.should == "Kittie Sanchez"
|
222
|
-
end
|
222
|
+
end # }}}
|
223
223
|
|
224
224
|
it "handle resource update through #save on an existing resource" do # {{{
|
225
225
|
@user = User.find(1)
|
@@ -250,6 +250,17 @@ describe Her::Model do
|
|
250
250
|
User.relationships[:has_many].should == [{ :name => :comments }, { :name => :posts }]
|
251
251
|
end # }}}
|
252
252
|
|
253
|
+
it "handles a single 'has_one' relationship" do # {{{
|
254
|
+
User.has_one :category
|
255
|
+
User.relationships[:has_one].should == [{ :name => :category }]
|
256
|
+
end # }}}
|
257
|
+
|
258
|
+
it "handles multiples 'has_one' relationship" do # {{{
|
259
|
+
User.has_one :category
|
260
|
+
User.has_one :role
|
261
|
+
User.relationships[:has_one].should == [{ :name => :category }, { :name => :role }]
|
262
|
+
end # }}}
|
263
|
+
|
253
264
|
it "handles a single belongs_to relationship" do # {{{
|
254
265
|
User.belongs_to :organization
|
255
266
|
User.relationships[:belongs_to].should == [{ :name => :organization }]
|
@@ -265,20 +276,34 @@ describe Her::Model do
|
|
265
276
|
context "handling relationships" do
|
266
277
|
before do # {{{
|
267
278
|
Her::API.setup :base_uri => "https://api.example.com"
|
268
|
-
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke", :comments => [{ :id => 2, :body => "Tobias, you blow hard!" }, { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak" }] } }.to_json)
|
269
|
-
FakeWeb.register_uri(:get, "https://api.example.com/users/2", :body => { :data => { :id => 2, :name => "Lindsay Fünke" } }.to_json)
|
279
|
+
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :data => { :id => 1, :name => "Tobias Fünke", :comments => [{ :id => 2, :body => "Tobias, you blow hard!" }, { :id => 3, :body => "I wouldn't mind kissing that man between the cheeks, so to speak" }], :role => { :id => 1, :body => "Admin" }, :organization => { :id => 1, :name => "Bluth Company" }, :organization_id => 1 } }.to_json)
|
280
|
+
FakeWeb.register_uri(:get, "https://api.example.com/users/2", :body => { :data => { :id => 2, :name => "Lindsay Fünke", :organization_id => 1 } }.to_json)
|
270
281
|
FakeWeb.register_uri(:get, "https://api.example.com/users/2/comments", :body => { :data => [{ :id => 4, :body => "They're having a FIRESALE?" }, { :id => 5, :body => "Is this the tiny town from Footloose?" }] }.to_json)
|
282
|
+
FakeWeb.register_uri(:get, "https://api.example.com/users/2/role", :body => { :data => { :id => 2, :body => "User" } }.to_json)
|
283
|
+
FakeWeb.register_uri(:get, "https://api.example.com/organizations/1", :body => { :data => { :id => 1, :name => "Bluth Company" } }.to_json)
|
271
284
|
|
272
285
|
Object.instance_eval { remove_const :User } if Object.const_defined?(:User)
|
273
286
|
class User
|
274
287
|
include Her::Model
|
275
288
|
has_many :comments
|
289
|
+
has_one :role
|
290
|
+
belongs_to :organization
|
291
|
+
end
|
292
|
+
|
293
|
+
Object.instance_eval { remove_const :Organization } if Object.const_defined?(:Organization)
|
294
|
+
class Organization
|
295
|
+
include Her::Model
|
276
296
|
end
|
277
297
|
|
278
298
|
Object.instance_eval { remove_const :Comment } if Object.const_defined?(:Comment)
|
279
299
|
class Comment
|
280
300
|
include Her::Model
|
281
301
|
end
|
302
|
+
|
303
|
+
Object.instance_eval { remove_const :Role } if Object.const_defined?(:Role)
|
304
|
+
class Role
|
305
|
+
include Her::Model
|
306
|
+
end
|
282
307
|
end # }}}
|
283
308
|
|
284
309
|
it "maps an array of included data" do # {{{
|
@@ -286,6 +311,12 @@ describe Her::Model do
|
|
286
311
|
@user.comments.length.should == 2
|
287
312
|
@user.comments.first.id.should == 2
|
288
313
|
@user.comments.first.body.should == "Tobias, you blow hard!"
|
314
|
+
|
315
|
+
@user.role.id.should == 1
|
316
|
+
@user.role.body.should == "Admin"
|
317
|
+
|
318
|
+
@user.organization.id.should == 1
|
319
|
+
@user.organization.name.should == "Bluth Company"
|
289
320
|
end # }}}
|
290
321
|
|
291
322
|
it "fetches data that was not included" do # {{{
|
@@ -293,6 +324,12 @@ describe Her::Model do
|
|
293
324
|
@user.comments.length.should == 2
|
294
325
|
@user.comments.first.id.should == 4
|
295
326
|
@user.comments.first.body.should == "They're having a FIRESALE?"
|
327
|
+
|
328
|
+
@user.role.id.should == 2
|
329
|
+
@user.role.body.should == "User"
|
330
|
+
|
331
|
+
@user.organization.id.should == 1
|
332
|
+
@user.organization.name.should == "Bluth Company"
|
296
333
|
end # }}}
|
297
334
|
end
|
298
335
|
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.1.
|
4
|
+
version: 0.1.5
|
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: 2012-04-
|
12
|
+
date: 2012-04-11 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -165,6 +165,7 @@ files:
|
|
165
165
|
- .gitignore
|
166
166
|
- .travis.yml
|
167
167
|
- Gemfile
|
168
|
+
- LICENSE
|
168
169
|
- README.md
|
169
170
|
- Rakefile
|
170
171
|
- her.gemspec
|
@@ -193,7 +194,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
193
194
|
version: '0'
|
194
195
|
segments:
|
195
196
|
- 0
|
196
|
-
hash: -
|
197
|
+
hash: -4167601811325738400
|
197
198
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
198
199
|
none: false
|
199
200
|
requirements:
|
@@ -202,7 +203,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
202
203
|
version: '0'
|
203
204
|
segments:
|
204
205
|
- 0
|
205
|
-
hash: -
|
206
|
+
hash: -4167601811325738400
|
206
207
|
requirements: []
|
207
208
|
rubyforge_project:
|
208
209
|
rubygems_version: 1.8.18
|