her 0.2.1 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +50 -24
- data/examples/twitter-oauth/app.rb +10 -3
- data/examples/twitter-search/Gemfile +1 -0
- data/examples/twitter-search/app.rb +25 -1
- data/lib/her/api.rb +7 -16
- data/lib/her/model.rb +3 -2
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +35 -4
- data/spec/model/paths_spec.rb +42 -27
- data/spec/spec_helper.rb +6 -1
- metadata +4 -4
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Her
|
2
2
|
|
3
|
-
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
|
3
|
+
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
4
|
|
5
5
|
[](http://travis-ci.org/remiprev/her)
|
6
6
|
|
@@ -56,7 +56,7 @@ User.find(1)
|
|
56
56
|
|
57
57
|
## Middleware
|
58
58
|
|
59
|
-
Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can add additional middleware to handle requests and responses.
|
59
|
+
Since Her relies on [Faraday](https://github.com/technoweenie/faraday) to send HTTP requests, you can add additional middleware to handle requests and responses. Using a block in the `setup` call, you have access to Faraday’s `builder` object and are able to customize the middleware stack used on each request and response.
|
60
60
|
|
61
61
|
### Authentication
|
62
62
|
|
@@ -64,14 +64,19 @@ Her doesn’t support any kind of authentication. However, it’s very easy to i
|
|
64
64
|
|
65
65
|
```ruby
|
66
66
|
class MyAuthentication < Faraday::Middleware
|
67
|
+
def initialize(app, options={})
|
68
|
+
@options = options
|
69
|
+
end
|
70
|
+
|
67
71
|
def call(env)
|
68
|
-
env[:request_headers]["X-API-Token"] =
|
72
|
+
env[:request_headers]["X-API-Token"] = @options[:token] if @options.include?(:token)
|
69
73
|
@app.call(env)
|
70
74
|
end
|
71
75
|
end
|
72
76
|
|
73
77
|
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
74
|
-
|
78
|
+
# This token could be stored in the client session
|
79
|
+
builder.use MyAuthentication, :token => "bb2b2dd75413d32c1ac421d39e95b978d1819ff611f68fc2fdd5c8b9c7331192"
|
75
80
|
end
|
76
81
|
```
|
77
82
|
|
@@ -91,14 +96,14 @@ By default, Her handles JSON data. It expects the resource/collection data to be
|
|
91
96
|
[{ "id" : 1, "name" : "Tobias Fünke" }]
|
92
97
|
```
|
93
98
|
|
94
|
-
However, you can define your own parsing method, using a response middleware. The middleware is expected to set `env[:body]` to a hash with three keys: `data`, `errors` and `metadata`. The following code enables parsing JSON data and treating the result as first-level properties. Using the builder block, we then replace the default parser.
|
99
|
+
However, you can define your own parsing method, using a response middleware. The middleware is expected to set `env[:body]` to a hash with three keys: `data`, `errors` and `metadata`. The following code enables parsing JSON data and treating the result as first-level properties. Using the builder block, we then replace the default parser with our custom parser.
|
95
100
|
|
96
101
|
```ruby
|
97
102
|
class MyCustomParser < Faraday::Response::Middleware
|
98
103
|
def on_complete(env)
|
99
104
|
json = MultiJson.load(env[:body], :symbolize_keys => true)
|
100
105
|
env[:body] = {
|
101
|
-
:data => json[:
|
106
|
+
:data => json[:result],
|
102
107
|
:errors => json[:errors],
|
103
108
|
:metadata => json[:metadata]
|
104
109
|
}
|
@@ -106,10 +111,10 @@ class MyCustomParser < Faraday::Response::Middleware
|
|
106
111
|
end
|
107
112
|
|
108
113
|
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
109
|
-
|
110
|
-
builder.
|
114
|
+
# We use the `swap` method to replace Her’s default parser middleware
|
115
|
+
builder.swap Her::Middleware::DefaultParseJSON, MyCustomParser
|
111
116
|
end
|
112
|
-
# User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "
|
117
|
+
# User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "result" => { "id": 1, "name": "Tobias Fünke" }, "errors" => [] }'
|
113
118
|
```
|
114
119
|
|
115
120
|
### OAuth
|
@@ -136,7 +141,8 @@ TWITTER_CREDENTIALS = {
|
|
136
141
|
}
|
137
142
|
|
138
143
|
Her::API.setup :base_uri => "https://api.twitter.com/1/" do |builder|
|
139
|
-
|
144
|
+
# We need to insert the middleware at the beginning of the stack (hence the `insert 0`)
|
145
|
+
builder.insert 0, FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
|
140
146
|
end
|
141
147
|
|
142
148
|
class Tweet
|
@@ -161,12 +167,26 @@ In your Ruby code:
|
|
161
167
|
|
162
168
|
```ruby
|
163
169
|
class MyCache
|
164
|
-
def
|
165
|
-
|
166
|
-
|
170
|
+
def initialize
|
171
|
+
@cache = {}
|
172
|
+
end
|
173
|
+
|
174
|
+
def write(key, value)
|
175
|
+
@cache[key] = value
|
176
|
+
end
|
177
|
+
|
178
|
+
def read(key)
|
179
|
+
@cache[key]
|
180
|
+
end
|
181
|
+
|
182
|
+
def fetch(key, &block)
|
183
|
+
return value = read(key) if value.nil?
|
184
|
+
write key, yield
|
185
|
+
end
|
167
186
|
end
|
168
187
|
|
169
188
|
# A cache system must respond to `#write`, `#read` and `#fetch`.
|
189
|
+
# We should be probably using something like Memcached here, not a global object
|
170
190
|
$cache = MyCache.new
|
171
191
|
|
172
192
|
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
@@ -178,12 +198,15 @@ class User
|
|
178
198
|
end
|
179
199
|
|
180
200
|
@user = User.find(1)
|
181
|
-
|
201
|
+
# GET /users/1
|
202
|
+
|
203
|
+
@user = User.find(1)
|
204
|
+
# This request will be fetched from the cache
|
182
205
|
```
|
183
206
|
|
184
207
|
## Relationships
|
185
208
|
|
186
|
-
You can define `has_many`, `has_one` and `belongs_to` relationships in your models. The relationship data is handled in two different ways.
|
209
|
+
You can define `has_many`, `has_one` and `belongs_to` relationships in your models. The relationship data is handled in two different ways. If there’s relationship data when parsing a resource, it will be used to create new Ruby objects.
|
187
210
|
|
188
211
|
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).
|
189
212
|
|
@@ -210,7 +233,7 @@ class Organization
|
|
210
233
|
end
|
211
234
|
```
|
212
235
|
|
213
|
-
If there’s relationship data in the resource, no extra HTTP request is made when calling the `#comments` method and an array of resources
|
236
|
+
If there’s relationship data in the resource, no extra HTTP request is made when calling the `#comments` method and an array of resources is returned:
|
214
237
|
|
215
238
|
```ruby
|
216
239
|
@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" } }}
|
@@ -226,21 +249,21 @@ If there’s no relationship data in the resource, an extra HTTP request (to `GE
|
|
226
249
|
@user.comments # => [#<Comment id=1>, #<Comment id=2>] fetched from /users/1/comments
|
227
250
|
```
|
228
251
|
|
229
|
-
For `has_one`
|
252
|
+
For `has_one` relationships, an extra HTTP request (to `GET /users/1/role`) is made when calling the `#role` method:
|
230
253
|
|
231
254
|
```ruby
|
232
255
|
@user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth" }}
|
233
256
|
@user.role # => #<Role id=1> fetched from /users/1/role
|
234
257
|
```
|
235
258
|
|
236
|
-
For `belongs_to`
|
259
|
+
For `belongs_to` relationships, an extra HTTP request (to `GET /organizations/2`) is made when calling the `#organization` method:
|
237
260
|
|
238
261
|
```ruby
|
239
262
|
@user = User.find(1) # { :data => { :id => 1, :name => "George Michael Bluth", :organization_id => 2 }}
|
240
263
|
@user.organization # => #<Organization id=2> fetched from /organizations/2
|
241
264
|
```
|
242
265
|
|
243
|
-
However, subsequent calls to `#comments`
|
266
|
+
However, subsequent calls to `#comments`, `#role` and `#organization` will not trigger extra HTTP requests as the data has already been fetched.
|
244
267
|
|
245
268
|
## Hooks
|
246
269
|
|
@@ -260,8 +283,6 @@ end
|
|
260
283
|
# POST /users&fullname=Tobias+Fünke&internal_id=42
|
261
284
|
```
|
262
285
|
|
263
|
-
In the future, adding hooks to all models will be possible, as well as defining and triggering your own hooks (eg. for your custom requests).
|
264
|
-
|
265
286
|
## Custom requests
|
266
287
|
|
267
288
|
You can easily define custom requests for your models using `custom_get`, `custom_post`, etc.
|
@@ -343,12 +364,12 @@ end
|
|
343
364
|
# GET /hello_users/1
|
344
365
|
```
|
345
366
|
|
346
|
-
You can include custom variables in your paths:
|
367
|
+
You can also include custom variables in your paths:
|
347
368
|
|
348
369
|
```ruby
|
349
370
|
class User
|
350
371
|
include Her::Model
|
351
|
-
collection_path "/organizations/:organization_id/users
|
372
|
+
collection_path "/organizations/:organization_id/users"
|
352
373
|
end
|
353
374
|
|
354
375
|
@user = User.find(1, :_organization_id => 2)
|
@@ -356,6 +377,10 @@ end
|
|
356
377
|
|
357
378
|
@user = User.all(:_organization_id => 2)
|
358
379
|
# GET /organizations/2/users
|
380
|
+
|
381
|
+
@user = User.new(:fullname => "Tobias Fünke", :organization_id => 2)
|
382
|
+
@user.save
|
383
|
+
# POST /organizations/2/users
|
359
384
|
```
|
360
385
|
|
361
386
|
## Multiple APIs
|
@@ -394,7 +419,7 @@ Category.all
|
|
394
419
|
## Things to be done
|
395
420
|
|
396
421
|
* Better error handling
|
397
|
-
* Better documentation
|
422
|
+
* Better API documentation (using YARD)
|
398
423
|
|
399
424
|
## Contributors
|
400
425
|
|
@@ -403,6 +428,7 @@ Feel free to contribute and submit issues/pull requests [on GitHub](https://gith
|
|
403
428
|
* [@jfcixmedia](https://github.com/jfcixmedia)
|
404
429
|
* [@EtienneLem](https://github.com/EtienneLem)
|
405
430
|
* [@rafaelss](https://github.com/rafaelss)
|
431
|
+
* [@tysontate](https://github.com/tysontate)
|
406
432
|
|
407
433
|
Take a look at the `spec` folder before you do, and make sure `bundle exec rake spec` passes after your modifications :)
|
408
434
|
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# Create custom parser
|
2
|
-
class
|
2
|
+
class TwitterParser < Faraday::Response::Middleware
|
3
3
|
METADATA_KEYS = [:completed_in, :max_id, :max_id_str, :next_page, :page, :query, :refresh_url, :results_per_page, :since_id, :since_id_str]
|
4
4
|
|
5
5
|
def on_complete(env)
|
@@ -21,7 +21,10 @@ TWITTER_CREDENTIALS = {
|
|
21
21
|
}
|
22
22
|
|
23
23
|
# Initialize API
|
24
|
-
Her::API.setup :base_uri => "https://api.twitter.com/1/"
|
24
|
+
Her::API.setup :base_uri => "https://api.twitter.com/1/" do |builder|
|
25
|
+
builder.insert 0, FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
|
26
|
+
builder.swap Her::Middleware::DefaultParseJSON, TwitterParser
|
27
|
+
end
|
25
28
|
|
26
29
|
# Define classes
|
27
30
|
class Tweet
|
@@ -31,12 +34,16 @@ class Tweet
|
|
31
34
|
get "/statuses/home_timeline.json"
|
32
35
|
end
|
33
36
|
|
37
|
+
def self.mentions
|
38
|
+
get "/statuses/mentions.json"
|
39
|
+
end
|
40
|
+
|
34
41
|
def username
|
35
42
|
user[:screen_name]
|
36
43
|
end
|
37
44
|
end
|
38
45
|
|
39
46
|
get "/" do
|
40
|
-
@tweets = Tweet.
|
47
|
+
@tweets = Tweet.mentions
|
41
48
|
haml :index
|
42
49
|
end
|
@@ -12,8 +12,32 @@ class TwitterSearchParser < Faraday::Response::Middleware
|
|
12
12
|
end
|
13
13
|
end
|
14
14
|
|
15
|
+
class MyCache
|
16
|
+
def initialize
|
17
|
+
@cache = {}
|
18
|
+
end
|
19
|
+
|
20
|
+
def write(key, value)
|
21
|
+
@cache[key] = value
|
22
|
+
end
|
23
|
+
|
24
|
+
def read(key)
|
25
|
+
@cache[key]
|
26
|
+
end
|
27
|
+
|
28
|
+
def fetch(key, &block)
|
29
|
+
return value = read(key) if value.nil?
|
30
|
+
write key, yield
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
$cache = MyCache.new
|
35
|
+
|
15
36
|
# Initialize API
|
16
|
-
Her::API.setup :base_uri => "http://search.twitter.com"
|
37
|
+
Her::API.setup :base_uri => "http://search.twitter.com" do |builder|
|
38
|
+
builder.swap Her::Middleware::FirstLevelParseJSON, TwitterSearchParser
|
39
|
+
builder.use FaradayMiddleware::Caching, $cache
|
40
|
+
end
|
17
41
|
|
18
42
|
# Define classes
|
19
43
|
class Tweet
|
data/lib/her/api.rb
CHANGED
@@ -3,14 +3,12 @@ module Her
|
|
3
3
|
# so it knows where to make those requests. In Rails, this is usually done in `config/initializers/her.rb`:
|
4
4
|
class API
|
5
5
|
# @private
|
6
|
-
attr_reader :base_uri, :middleware
|
6
|
+
attr_reader :base_uri, :middleware, :connection
|
7
7
|
|
8
8
|
# Setup a default API connection. Accepted arguments and options are the same as {API#setup}.
|
9
|
-
def self.setup(attrs={}) # {{{
|
9
|
+
def self.setup(attrs={}, &block) # {{{
|
10
10
|
@@default_api = new
|
11
|
-
|
12
|
-
yield connection.builder if block_given?
|
13
|
-
connection
|
11
|
+
@@default_api.setup(attrs, &block)
|
14
12
|
end # }}}
|
15
13
|
|
16
14
|
# Setup the API connection.
|
@@ -60,19 +58,12 @@ module Her
|
|
60
58
|
|
61
59
|
@middleware.flatten!
|
62
60
|
middleware = @middleware
|
63
|
-
@connection = Faraday.new(:url => @base_uri) do |
|
64
|
-
middleware.each do |
|
65
|
-
|
66
|
-
args = item.is_a?(Hash) ? item.values.first : nil
|
67
|
-
if args
|
68
|
-
builder.use klass, args
|
69
|
-
else
|
70
|
-
builder.use klass
|
71
|
-
end
|
61
|
+
@connection = Faraday.new(:url => @base_uri) do |connection|
|
62
|
+
middleware.each do |klass|
|
63
|
+
connection.use klass
|
72
64
|
end
|
65
|
+
yield connection.builder if block_given?
|
73
66
|
end
|
74
|
-
yield @connection.builder if block_given?
|
75
|
-
@connection
|
76
67
|
end # }}}
|
77
68
|
|
78
69
|
# Define a custom parsing procedure. The procedure is passed the response object and is
|
data/lib/her/model.rb
CHANGED
@@ -35,8 +35,9 @@ module Her
|
|
35
35
|
extend Her::Model::Paths
|
36
36
|
|
37
37
|
# Define default settings
|
38
|
-
|
39
|
-
|
38
|
+
base_path = self.name.split("::").last.downcase.pluralize
|
39
|
+
collection_path "/#{base_path}"
|
40
|
+
resource_path "/#{base_path}/:id"
|
40
41
|
uses_api Her::API.default_api
|
41
42
|
end
|
42
43
|
end
|
data/lib/her/version.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -16,20 +16,52 @@ describe Her::API do
|
|
16
16
|
@api.setup :base_uri => "https://api.example.com"
|
17
17
|
@api.base_uri.should == "https://api.example.com"
|
18
18
|
end # }}}
|
19
|
+
|
20
|
+
it "sets custom middleware with #use" do # {{{
|
21
|
+
class Foo; end;
|
22
|
+
class Bar; end;
|
23
|
+
|
24
|
+
@api = Her::API.new
|
25
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
26
|
+
builder.use Foo
|
27
|
+
builder.use Bar
|
28
|
+
end
|
29
|
+
@api.connection.builder.handlers.should == [Her::Middleware::FirstLevelParseJSON, Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp, Foo, Bar]
|
30
|
+
end # }}}
|
31
|
+
|
32
|
+
it "sets custom middleware with #insert" do # {{{
|
33
|
+
class Foo; end;
|
34
|
+
class Bar; end;
|
35
|
+
|
36
|
+
@api = Her::API.new
|
37
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
38
|
+
builder.use Foo
|
39
|
+
builder.insert 0, Bar
|
40
|
+
end
|
41
|
+
@api.connection.builder.handlers.should == [Bar, Her::Middleware::FirstLevelParseJSON, Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp, Foo]
|
42
|
+
end # }}}
|
43
|
+
|
44
|
+
it "delete some default middleware" do # {{{
|
45
|
+
@api = Her::API.new
|
46
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
47
|
+
builder.delete Faraday::Request::UrlEncoded
|
48
|
+
end
|
49
|
+
@api.connection.builder.handlers.should == [Her::Middleware::FirstLevelParseJSON, Faraday::Adapter::NetHttp]
|
50
|
+
end # }}}
|
19
51
|
end
|
20
52
|
|
21
53
|
describe "#request" do
|
22
54
|
it "makes HTTP requests" do # {{{
|
23
55
|
FakeWeb.register_uri(:get, "https://api.example.com/foo", :body => "Foo, it is.")
|
24
56
|
|
25
|
-
class
|
57
|
+
class SimpleParser < Faraday::Response::Middleware
|
26
58
|
def on_complete(env)
|
27
59
|
env[:body] = { :data => env[:body] }
|
28
60
|
end
|
29
61
|
end
|
30
62
|
|
31
63
|
@api = Her::API.new
|
32
|
-
@api.setup :base_uri => "https://api.example.com", :parse_middleware =>
|
64
|
+
@api.setup :base_uri => "https://api.example.com", :parse_middleware => SimpleParser
|
33
65
|
parsed_data = @api.request(:_method => :get, :_path => "/foo")
|
34
66
|
parsed_data[:data] == "Foo, it is."
|
35
67
|
end # }}}
|
@@ -63,8 +95,7 @@ describe Her::API do
|
|
63
95
|
|
64
96
|
@api = Her::API.new
|
65
97
|
@api.setup :base_uri => "https://api.example.com" do |connection|
|
66
|
-
connection.
|
67
|
-
connection.use CustomParser
|
98
|
+
connection.swap Her::Middleware::DefaultParseJSON, CustomParser
|
68
99
|
end
|
69
100
|
parsed_data = @api.request(:_method => :get, :_path => "users/1")
|
70
101
|
parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
|
data/spec/model/paths_spec.rb
CHANGED
@@ -3,38 +3,53 @@ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
|
3
3
|
|
4
4
|
describe Her::Model::Paths do
|
5
5
|
context "building request paths" do
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
describe "#build_request_path" do
|
11
|
-
it "builds paths with defaults" do # {{{
|
12
|
-
User.build_request_path(id: "foo").should == "/users/foo"
|
13
|
-
User.build_request_path.should == "/users"
|
14
|
-
end # }}}
|
15
|
-
|
16
|
-
it "builds paths with custom collection path" do # {{{
|
17
|
-
User.collection_path "/utilisateurs"
|
18
|
-
User.build_request_path(id: "foo").should == "/utilisateurs/foo"
|
19
|
-
User.build_request_path.should == "/utilisateurs"
|
6
|
+
context "simple model" do
|
7
|
+
before do # {{{
|
8
|
+
spawn_model :User
|
20
9
|
end # }}}
|
21
10
|
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
11
|
+
describe "#build_request_path" do
|
12
|
+
it "builds paths with defaults" do # {{{
|
13
|
+
User.build_request_path(id: "foo").should == "/users/foo"
|
14
|
+
User.build_request_path.should == "/users"
|
15
|
+
end # }}}
|
16
|
+
|
17
|
+
it "builds paths with custom collection path" do # {{{
|
18
|
+
User.collection_path "/utilisateurs"
|
19
|
+
User.build_request_path(id: "foo").should == "/utilisateurs/foo"
|
20
|
+
User.build_request_path.should == "/utilisateurs"
|
21
|
+
end # }}}
|
22
|
+
|
23
|
+
it "builds paths with custom collection path with multiple variables" do # {{{
|
24
|
+
User.collection_path "/organizations/:organization_id/utilisateurs"
|
25
|
+
User.build_request_path(:id => "foo", :_organization_id => "acme").should == "/organizations/acme/utilisateurs/foo"
|
26
|
+
User.build_request_path(:_organization_id => "acme").should == "/organizations/acme/utilisateurs"
|
27
|
+
end # }}}
|
28
|
+
|
29
|
+
it "builds paths with custom item path" do # {{{
|
30
|
+
User.resource_path "/utilisateurs/:id"
|
31
|
+
User.build_request_path(id: "foo").should == "/utilisateurs/foo"
|
32
|
+
User.build_request_path.should == "/users"
|
33
|
+
end # }}}
|
34
|
+
|
35
|
+
it "raises exceptions when building a path without required custom variables" do # {{{
|
36
|
+
User.collection_path "/organizations/:organization_id/utilisateurs"
|
37
|
+
expect { User.build_request_path(:id => "foo") }.should raise_error(Her::Errors::PathError)
|
38
|
+
end # }}}
|
39
|
+
end
|
40
|
+
end
|
27
41
|
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
User.build_request_path.should == "/users"
|
42
|
+
context "nested model" do
|
43
|
+
before do # {{{
|
44
|
+
spawn_submodel :Base, :User
|
32
45
|
end # }}}
|
33
46
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
47
|
+
describe "#build_request_path" do
|
48
|
+
it "builds paths with defaults" do # {{{
|
49
|
+
Base::User.build_request_path(id: "foo").should == "/users/foo"
|
50
|
+
Base::User.build_request_path.should == "/users"
|
51
|
+
end # }}}
|
52
|
+
end
|
38
53
|
end
|
39
54
|
end
|
40
55
|
|
data/spec/spec_helper.rb
CHANGED
@@ -19,8 +19,13 @@ class Array
|
|
19
19
|
def to_json; MultiJson.dump(self); end
|
20
20
|
end
|
21
21
|
|
22
|
-
def spawn_model(klass,
|
22
|
+
def spawn_model(klass, &block)
|
23
23
|
Object.instance_eval { remove_const klass } if Object.const_defined?(klass)
|
24
24
|
Object.const_set(klass, Class.new).send(:include, Her::Model)
|
25
25
|
Object.const_get(klass).class_eval(&block) if block_given?
|
26
26
|
end
|
27
|
+
|
28
|
+
def spawn_submodel(mod, klass)
|
29
|
+
Object.instance_eval { remove_const mod } if Object.const_defined?(mod)
|
30
|
+
Object.const_set(mod, Module.new).const_set(klass, Class.new).send(:include, Her::Model)
|
31
|
+
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.2.
|
4
|
+
version: 0.2.2
|
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-
|
12
|
+
date: 2012-05-01 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
@@ -281,7 +281,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
281
281
|
version: '0'
|
282
282
|
segments:
|
283
283
|
- 0
|
284
|
-
hash:
|
284
|
+
hash: -2369072493348034064
|
285
285
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
286
286
|
none: false
|
287
287
|
requirements:
|
@@ -290,7 +290,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
290
290
|
version: '0'
|
291
291
|
segments:
|
292
292
|
- 0
|
293
|
-
hash:
|
293
|
+
hash: -2369072493348034064
|
294
294
|
requirements: []
|
295
295
|
rubyforge_project:
|
296
296
|
rubygems_version: 1.8.18
|