her 0.2.3 → 0.2.4
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +36 -11
- data/UPGRADE.md +30 -0
- data/lib/her/api.rb +1 -20
- data/lib/her/model.rb +1 -1
- data/lib/her/model/orm.rb +1 -1
- data/lib/her/version.rb +1 -1
- data/spec/api_spec.rb +16 -25
- data/spec/model/hooks_spec.rb +6 -1
- data/spec/model/http_spec.rb +33 -6
- data/spec/model/introspection_spec.rb +6 -1
- data/spec/model/orm_spec.rb +33 -4
- data/spec/model/paths_spec.rb +42 -1
- data/spec/model/relationships_spec.rb +6 -1
- metadata +110 -44
data/README.md
CHANGED
@@ -14,13 +14,21 @@ gem "her"
|
|
14
14
|
|
15
15
|
That’s it!
|
16
16
|
|
17
|
+
## Upgrade
|
18
|
+
|
19
|
+
Please see the [UPGRADE.md](https://github.com/remiprev/her/blob/master/UPGRADE.md) file for backward compability issues.
|
20
|
+
|
17
21
|
## Usage
|
18
22
|
|
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
|
23
|
+
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 these lines:
|
20
24
|
|
21
25
|
```ruby
|
22
26
|
# config/initializers/her.rb
|
23
|
-
Her::API.setup :base_uri => "https://api.example.com"
|
27
|
+
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
28
|
+
builder.use Faraday::Request::UrlEncoded
|
29
|
+
builder.use Her::Middleware::DefaultParseJSON
|
30
|
+
builder.use Faraday::Adapter::NetHttp
|
31
|
+
end
|
24
32
|
```
|
25
33
|
|
26
34
|
And then to add the ORM behavior to a class, you just have to include `Her::Model` in it:
|
@@ -56,7 +64,7 @@ User.find(1)
|
|
56
64
|
|
57
65
|
## Middleware
|
58
66
|
|
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
|
67
|
+
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 the 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
68
|
|
61
69
|
### Authentication
|
62
70
|
|
@@ -77,6 +85,10 @@ end
|
|
77
85
|
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
78
86
|
# This token could be stored in the client session
|
79
87
|
builder.use MyAuthentication, :token => "bb2b2dd75413d32c1ac421d39e95b978d1819ff611f68fc2fdd5c8b9c7331192"
|
88
|
+
|
89
|
+
builder.use Faraday::Request::UrlEncoded
|
90
|
+
builder.use Her::Middleware::DefaultParseJSON
|
91
|
+
builder.use Faraday::Adapter::NetHttp
|
80
92
|
end
|
81
93
|
```
|
82
94
|
|
@@ -86,8 +98,6 @@ Now, each HTTP request made by Her will have the `X-API-Token` header.
|
|
86
98
|
|
87
99
|
By default, Her handles JSON data. It expects the resource/collection data to be returned at the first level.
|
88
100
|
|
89
|
-
**Note**: *Before 0.2, Her expected the resource/collection data to be returned in a `data` key within the JSON object. If you want the old behavior, you can use the `Her::Middleware::SecondLevelParseJSON` middleware.*
|
90
|
-
|
91
101
|
```javascript
|
92
102
|
// The response of GET /users/1
|
93
103
|
{ "id" : 1, "name" : "Tobias Fünke" }
|
@@ -111,8 +121,9 @@ class MyCustomParser < Faraday::Response::Middleware
|
|
111
121
|
end
|
112
122
|
|
113
123
|
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
114
|
-
|
115
|
-
builder.
|
124
|
+
builder.use Faraday::Request::UrlEncoded
|
125
|
+
builder.use MyCustomParser
|
126
|
+
builder.use Faraday::Adapter::NetHttp
|
116
127
|
end
|
117
128
|
# User.find(1) will now expect "https://api.example.com/users/1" to return something like '{ "result" => { "id": 1, "name": "Tobias Fünke" }, "errors" => [] }'
|
118
129
|
```
|
@@ -141,8 +152,10 @@ TWITTER_CREDENTIALS = {
|
|
141
152
|
}
|
142
153
|
|
143
154
|
Her::API.setup :base_uri => "https://api.twitter.com/1/" do |builder|
|
144
|
-
|
145
|
-
builder.
|
155
|
+
builder.use FaradayMiddleware::OAuth, TWITTER_CREDENTIALS
|
156
|
+
builder.use Faraday::Request::UrlEncoded
|
157
|
+
builder.use Her::Middleware::DefaultParseJSON
|
158
|
+
builder.use Faraday::Adapter::NetHttp
|
146
159
|
end
|
147
160
|
|
148
161
|
class Tweet
|
@@ -190,7 +203,10 @@ end
|
|
190
203
|
$cache = MyCache.new
|
191
204
|
|
192
205
|
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
206
|
+
builder.use Faraday::Request::UrlEncoded
|
193
207
|
builder.use FaradayMiddleware::Caching, $cache
|
208
|
+
builder.use Her::Middleware::DefaultParseJSON
|
209
|
+
builder.use Faraday::Adapter::NetHttp
|
194
210
|
end
|
195
211
|
|
196
212
|
class User
|
@@ -390,10 +406,18 @@ It is possible to use different APIs for different models. Instead of calling `H
|
|
390
406
|
```ruby
|
391
407
|
# config/initializers/her.rb
|
392
408
|
$my_api = Her::API.new
|
393
|
-
$my_api.setup :base_uri => "https://my_api.example.com"
|
409
|
+
$my_api.setup :base_uri => "https://my_api.example.com" do |builder|
|
410
|
+
builder.use Faraday::Request::UrlEncoded
|
411
|
+
builder.use Her::Middleware::DefaultParseJSON
|
412
|
+
builder.use Faraday::Adapter::NetHttp
|
413
|
+
end
|
394
414
|
|
395
415
|
$other_api = Her::API.new
|
396
|
-
$other_api.setup :base_uri => "https://other_api.example.com"
|
416
|
+
$other_api.setup :base_uri => "https://other_api.example.com" do |builder|
|
417
|
+
builder.use Faraday::Request::UrlEncoded
|
418
|
+
builder.use Her::Middleware::DefaultParseJSON
|
419
|
+
builder.use Faraday::Adapter::NetHttp
|
420
|
+
end
|
397
421
|
```
|
398
422
|
|
399
423
|
You can then define which API a model will use:
|
@@ -429,6 +453,7 @@ Feel free to contribute and submit issues/pull requests [on GitHub](https://gith
|
|
429
453
|
* [@EtienneLem](https://github.com/EtienneLem)
|
430
454
|
* [@rafaelss](https://github.com/rafaelss)
|
431
455
|
* [@tysontate](https://github.com/tysontate)
|
456
|
+
* [@nfo](https://github.com/nfo)
|
432
457
|
|
433
458
|
Take a look at the `spec` folder before you do, and make sure `bundle exec rake spec` passes after your modifications :)
|
434
459
|
|
data/UPGRADE.md
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
Here is a list of backward-incompatible changes that were introduced while Her is still \<1.0. After reaching 1.0, it will follow the [Semantic Versioning](http://semver.org/) system.
|
2
|
+
|
3
|
+
## 0.2.4
|
4
|
+
|
5
|
+
* Her no longer includes default middleware when making HTTP requests. The user has now to define all the needed middleware. Before:
|
6
|
+
|
7
|
+
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
8
|
+
builder.insert(0, FaradayMiddle::OAuth)
|
9
|
+
end
|
10
|
+
|
11
|
+
Now:
|
12
|
+
|
13
|
+
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
14
|
+
builder.use FaradayMiddle::OAuth
|
15
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
16
|
+
builder.use Faraday::Request::UrlEncoded
|
17
|
+
builder.use Faraday::Adapter::NetHttp
|
18
|
+
end
|
19
|
+
|
20
|
+
## 0.2
|
21
|
+
|
22
|
+
* The default parser middleware has been replaced to treat first-level JSON data as the resource or collection data. Before it expected this:
|
23
|
+
|
24
|
+
{ "data": { "id": 1, "name": "Foo" }, "errors": [] }
|
25
|
+
|
26
|
+
Now it expects this (the `errors` key is not treated as resource data):
|
27
|
+
|
28
|
+
{ "id": 1, "name": "Foo", "errors": [] }
|
29
|
+
|
30
|
+
If you still want to get the old behavior, you can use `Her::Middleware::SecondLevelParseJSON` instead of `Her::Middleware::FirstLevelParseJSON` in your middleware stack.
|
data/lib/her/api.rb
CHANGED
@@ -3,7 +3,7 @@ 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, :
|
6
|
+
attr_reader :base_uri, :connection
|
7
7
|
|
8
8
|
# Setup a default API connection. Accepted arguments and options are the same as {API#setup}.
|
9
9
|
def self.setup(attrs={}, &block) # {{{
|
@@ -15,9 +15,6 @@ module Her
|
|
15
15
|
#
|
16
16
|
# @param [Hash] attrs the options to create a message with
|
17
17
|
# @option attrs [String] :base_uri The main HTTP API root (eg. `https://api.example.com`)
|
18
|
-
# @option attrs [Array, Class] :middleware **Deprecated** A list of the only middleware Her will use
|
19
|
-
# @option attrs [Array, Class] :add_middleware **Deprecated** A list of middleware to add to Her’s default middleware
|
20
|
-
# @option attrs [Class] :parse_middleware **Deprecated** A middleware that will replace {Her::Middleware::FirstLevelParseJSON} to parse the received JSON
|
21
18
|
#
|
22
19
|
# @return Faraday::Connection
|
23
20
|
#
|
@@ -50,18 +47,7 @@ module Her
|
|
50
47
|
# end
|
51
48
|
def setup(attrs={}) # {{{
|
52
49
|
@base_uri = attrs[:base_uri]
|
53
|
-
@middleware = Her::API.default_middleware
|
54
|
-
|
55
|
-
@middleware = [attrs[:middleware]] if attrs[:middleware]
|
56
|
-
@middleware = [attrs[:add_middleware]] + @middleware if attrs[:add_middleware]
|
57
|
-
@middleware = [attrs[:parse_middleware]] + @middleware.reject { |item| item == Her::Middleware::FirstLevelParseJSON } if attrs[:parse_middleware]
|
58
|
-
|
59
|
-
@middleware.flatten!
|
60
|
-
middleware = @middleware
|
61
50
|
@connection = Faraday.new(:url => @base_uri) do |connection|
|
62
|
-
middleware.each do |klass|
|
63
|
-
connection.use klass
|
64
|
-
end
|
65
51
|
yield connection.builder if block_given?
|
66
52
|
end
|
67
53
|
end # }}}
|
@@ -93,10 +79,5 @@ module Her
|
|
93
79
|
def self.default_api(attrs={}) # {{{
|
94
80
|
defined?(@@default_api) ? @@default_api : nil
|
95
81
|
end # }}}
|
96
|
-
|
97
|
-
# @private
|
98
|
-
def self.default_middleware # {{{
|
99
|
-
[Her::Middleware::FirstLevelParseJSON, Faraday::Request::UrlEncoded, Faraday::Adapter::NetHttp]
|
100
|
-
end # }}}
|
101
82
|
end
|
102
83
|
end
|
data/lib/her/model.rb
CHANGED
@@ -35,7 +35,7 @@ module Her
|
|
35
35
|
extend Her::Model::Paths
|
36
36
|
|
37
37
|
# Define default settings
|
38
|
-
base_path = self.name.split("::").last.
|
38
|
+
base_path = self.name.split("::").last.underscore.pluralize
|
39
39
|
collection_path "/#{base_path}"
|
40
40
|
resource_path "/#{base_path}/:id"
|
41
41
|
uses_api Her::API.default_api
|
data/lib/her/model/orm.rb
CHANGED
@@ -42,7 +42,7 @@ module Her
|
|
42
42
|
# @param [Hash] parsed_data The raw `parsed_data` parsed from the HTTP response
|
43
43
|
def new_collection(parsed_data) # {{{
|
44
44
|
collection_data = parsed_data[:data]
|
45
|
-
Her::Model::ORM.initialize_collection(self.to_s.
|
45
|
+
Her::Model::ORM.initialize_collection(self.to_s.underscore, collection_data)
|
46
46
|
end # }}}
|
47
47
|
|
48
48
|
# Return `true` if a resource was not saved yet
|
data/lib/her/version.rb
CHANGED
data/spec/api_spec.rb
CHANGED
@@ -26,27 +26,7 @@ describe Her::API do
|
|
26
26
|
builder.use Foo
|
27
27
|
builder.use Bar
|
28
28
|
end
|
29
|
-
@api.connection.builder.handlers.should == [
|
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]
|
29
|
+
@api.connection.builder.handlers.should == [Foo, Bar]
|
50
30
|
end # }}}
|
51
31
|
end
|
52
32
|
|
@@ -61,7 +41,12 @@ describe Her::API do
|
|
61
41
|
end
|
62
42
|
|
63
43
|
@api = Her::API.new
|
64
|
-
@api.setup :base_uri => "https://api.example.com"
|
44
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
45
|
+
builder.use SimpleParser
|
46
|
+
builder.use Faraday::Request::UrlEncoded
|
47
|
+
builder.use Faraday::Adapter::NetHttp
|
48
|
+
end
|
49
|
+
|
65
50
|
parsed_data = @api.request(:_method => :get, :_path => "/foo")
|
66
51
|
parsed_data[:data] == "Foo, it is."
|
67
52
|
end # }}}
|
@@ -70,7 +55,11 @@ describe Her::API do
|
|
70
55
|
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => MultiJson.dump({ :id => 1, :name => "George Michael Bluth", :errors => ["This is a single error"], :metadata => { :page => 1, :per_page => 10 } }))
|
71
56
|
|
72
57
|
@api = Her::API.new
|
73
|
-
@api.setup :base_uri => "https://api.example.com"
|
58
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
59
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
60
|
+
builder.use Faraday::Request::UrlEncoded
|
61
|
+
builder.use Faraday::Adapter::NetHttp
|
62
|
+
end
|
74
63
|
parsed_data = @api.request(:_method => :get, :_path => "users/1")
|
75
64
|
parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
|
76
65
|
parsed_data[:errors].should == ["This is a single error"]
|
@@ -94,8 +83,10 @@ describe Her::API do
|
|
94
83
|
end
|
95
84
|
|
96
85
|
@api = Her::API.new
|
97
|
-
@api.setup :base_uri => "https://api.example.com" do |
|
98
|
-
|
86
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
87
|
+
builder.use CustomParser
|
88
|
+
builder.use Faraday::Request::UrlEncoded
|
89
|
+
builder.use Faraday::Adapter::NetHttp
|
99
90
|
end
|
100
91
|
parsed_data = @api.request(:_method => :get, :_path => "users/1")
|
101
92
|
parsed_data[:data].should == { :id => 1, :name => "George Michael Bluth" }
|
data/spec/model/hooks_spec.rb
CHANGED
@@ -110,7 +110,12 @@ describe Her::Model::Hooks do
|
|
110
110
|
|
111
111
|
context "perform hooks on a model" do
|
112
112
|
before do # {{{
|
113
|
-
Her::API.setup :base_uri => "https://api.example.com"
|
113
|
+
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
114
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
115
|
+
builder.use Faraday::Request::UrlEncoded
|
116
|
+
builder.use Faraday::Adapter::NetHttp
|
117
|
+
end
|
118
|
+
|
114
119
|
FakeWeb.register_uri(:post, "https://api.example.com/users", :body => { :id => 1, :name => "Tobias Fünke" }.to_json)
|
115
120
|
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :id => 1, :name => "Tobias Fünke" }.to_json)
|
116
121
|
FakeWeb.register_uri(:put, "https://api.example.com/users/1", :body => { :id => 1, :name => "Tobias Fünke" }.to_json)
|
data/spec/model/http_spec.rb
CHANGED
@@ -29,7 +29,11 @@ describe Her::Model::HTTP do
|
|
29
29
|
|
30
30
|
it "binds two models to two different instances of Her::API" do # {{{
|
31
31
|
@api1 = Her::API.new
|
32
|
-
@api1.setup :base_uri => "https://api1.example.com"
|
32
|
+
@api1.setup :base_uri => "https://api1.example.com" do |builder|
|
33
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
34
|
+
builder.use Faraday::Request::UrlEncoded
|
35
|
+
builder.use Faraday::Adapter::NetHttp
|
36
|
+
end
|
33
37
|
|
34
38
|
spawn_model :User
|
35
39
|
User.uses_api @api1
|
@@ -39,7 +43,11 @@ describe Her::Model::HTTP do
|
|
39
43
|
end
|
40
44
|
|
41
45
|
@api2 = Her::API.new
|
42
|
-
@api2.setup :base_uri => "https://api2.example.com"
|
46
|
+
@api2.setup :base_uri => "https://api2.example.com" do |builder|
|
47
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
48
|
+
builder.use Faraday::Request::UrlEncoded
|
49
|
+
builder.use Faraday::Adapter::NetHttp
|
50
|
+
end
|
43
51
|
|
44
52
|
spawn_model :Comment
|
45
53
|
Comment.uses_api @api2
|
@@ -50,7 +58,12 @@ describe Her::Model::HTTP do
|
|
50
58
|
end # }}}
|
51
59
|
|
52
60
|
it "binds one model to Her::API and another one to an instance of Her::API" do # {{{
|
53
|
-
Her::API.setup :base_uri => "https://api1.example.com"
|
61
|
+
Her::API.setup :base_uri => "https://api1.example.com" do |builder|
|
62
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
63
|
+
builder.use Faraday::Request::UrlEncoded
|
64
|
+
builder.use Faraday::Adapter::NetHttp
|
65
|
+
end
|
66
|
+
|
54
67
|
spawn_model :User
|
55
68
|
|
56
69
|
User.class_eval do
|
@@ -58,7 +71,11 @@ describe Her::Model::HTTP do
|
|
58
71
|
end
|
59
72
|
|
60
73
|
@api = Her::API.new
|
61
|
-
@api.setup :base_uri => "https://api2.example.com"
|
74
|
+
@api.setup :base_uri => "https://api2.example.com" do |builder|
|
75
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
76
|
+
builder.use Faraday::Request::UrlEncoded
|
77
|
+
builder.use Faraday::Adapter::NetHttp
|
78
|
+
end
|
62
79
|
|
63
80
|
spawn_model :Comment
|
64
81
|
Comment.uses_api @api
|
@@ -72,7 +89,12 @@ describe Her::Model::HTTP do
|
|
72
89
|
context "making HTTP requests" do
|
73
90
|
before do # {{{
|
74
91
|
@api = Her::API.new
|
75
|
-
@api.setup :base_uri => "https://api.example.com"
|
92
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
93
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
94
|
+
builder.use Faraday::Request::UrlEncoded
|
95
|
+
builder.use Faraday::Adapter::NetHttp
|
96
|
+
end
|
97
|
+
|
76
98
|
FakeWeb.register_uri(:get, "https://api.example.com/users", :body => [{ :id => 1 }].to_json)
|
77
99
|
FakeWeb.register_uri(:get, "https://api.example.com/users?page=2", :body => [{ :id => 2 }].to_json)
|
78
100
|
FakeWeb.register_uri(:get, "https://api.example.com/users/popular", :body => [{ :id => 1 }, { :id => 2 }].to_json)
|
@@ -163,7 +185,12 @@ describe Her::Model::HTTP do
|
|
163
185
|
context "setting custom requests" do
|
164
186
|
before do # {{{
|
165
187
|
@api = Her::API.new
|
166
|
-
@api.setup :base_uri => "https://api.example.com"
|
188
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
189
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
190
|
+
builder.use Faraday::Request::UrlEncoded
|
191
|
+
builder.use Faraday::Adapter::NetHttp
|
192
|
+
end
|
193
|
+
|
167
194
|
FakeWeb.register_uri(:get, "https://api.example.com/users/popular", :body => [{ :id => 1 }, { :id => 2 }].to_json)
|
168
195
|
FakeWeb.register_uri(:post, "https://api.example.com/users/from_default", :body => { :id => 4 }.to_json)
|
169
196
|
|
@@ -4,7 +4,12 @@ require File.join(File.dirname(__FILE__), "../spec_helper.rb")
|
|
4
4
|
describe Her::Model::Introspection do
|
5
5
|
context "introspecting a resource" do
|
6
6
|
before do # {{{
|
7
|
-
Her::API.setup :base_uri => "https://api.example.com"
|
7
|
+
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
8
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
9
|
+
builder.use Faraday::Request::UrlEncoded
|
10
|
+
builder.use Faraday::Adapter::NetHttp
|
11
|
+
end
|
12
|
+
|
8
13
|
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :id => 1, :name => "Tobias Funke" }.to_json)
|
9
14
|
spawn_model :User
|
10
15
|
end # }}}
|
data/spec/model/orm_spec.rb
CHANGED
@@ -5,13 +5,23 @@ describe Her::Model::ORM do
|
|
5
5
|
context "mapping data to Ruby objects" do
|
6
6
|
before do # {{{
|
7
7
|
api = Her::API.new
|
8
|
-
api.setup :base_uri => "https://api.example.com"
|
8
|
+
api.setup :base_uri => "https://api.example.com" do |builder|
|
9
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
10
|
+
builder.use Faraday::Request::UrlEncoded
|
11
|
+
builder.use Faraday::Adapter::NetHttp
|
12
|
+
end
|
13
|
+
|
9
14
|
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :id => 1, :name => "Tobias Fünke" }.to_json)
|
10
15
|
FakeWeb.register_uri(:get, "https://api.example.com/users", :body => [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }].to_json)
|
16
|
+
FakeWeb.register_uri(:get, "https://api.example.com/admin_users", :body => [{ :id => 1, :name => "Tobias Fünke" }, { :id => 2, :name => "Lindsay Fünke" }].to_json)
|
11
17
|
|
12
18
|
spawn_model :User do
|
13
19
|
uses_api api
|
14
20
|
end
|
21
|
+
|
22
|
+
spawn_model :AdminUser do
|
23
|
+
uses_api api
|
24
|
+
end
|
15
25
|
end # }}}
|
16
26
|
|
17
27
|
it "maps a single resource to a Ruby object" do # {{{
|
@@ -24,6 +34,10 @@ describe Her::Model::ORM do
|
|
24
34
|
@users = User.all
|
25
35
|
@users.length.should == 2
|
26
36
|
@users.first.name.should == "Tobias Fünke"
|
37
|
+
|
38
|
+
@users = AdminUser.all
|
39
|
+
@users.length.should == 2
|
40
|
+
@users.first.name.should == "Tobias Fünke"
|
27
41
|
end # }}}
|
28
42
|
|
29
43
|
it "handles new resource" do # {{{
|
@@ -37,7 +51,12 @@ describe Her::Model::ORM do
|
|
37
51
|
|
38
52
|
context "creating resources" do
|
39
53
|
before do # {{{
|
40
|
-
Her::API.setup :base_uri => "https://api.example.com"
|
54
|
+
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
55
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
56
|
+
builder.use Faraday::Request::UrlEncoded
|
57
|
+
builder.use Faraday::Adapter::NetHttp
|
58
|
+
end
|
59
|
+
|
41
60
|
FakeWeb.register_uri(:post, "https://api.example.com/users", :body => { :id => 1, :fullname => "Tobias Fünke" }.to_json)
|
42
61
|
|
43
62
|
spawn_model :User
|
@@ -59,7 +78,12 @@ describe Her::Model::ORM do
|
|
59
78
|
context "updating resources" do
|
60
79
|
before do # {{{
|
61
80
|
@api = Her::API.new
|
62
|
-
@api.setup :base_uri => "https://api.example.com"
|
81
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
82
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
83
|
+
builder.use Faraday::Request::UrlEncoded
|
84
|
+
builder.use Faraday::Adapter::NetHttp
|
85
|
+
end
|
86
|
+
|
63
87
|
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :id => 1, :fullname => "Tobias Fünke" }.to_json)
|
64
88
|
FakeWeb.register_uri(:put, "https://api.example.com/users/1", :body => { :id => 1, :fullname => "Lindsay Fünke" }.to_json)
|
65
89
|
|
@@ -89,7 +113,12 @@ describe Her::Model::ORM do
|
|
89
113
|
context "deleting resources" do
|
90
114
|
before do # {{{
|
91
115
|
@api = Her::API.new
|
92
|
-
@api.setup :base_uri => "https://api.example.com"
|
116
|
+
@api.setup :base_uri => "https://api.example.com" do |builder|
|
117
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
118
|
+
builder.use Faraday::Request::UrlEncoded
|
119
|
+
builder.use Faraday::Adapter::NetHttp
|
120
|
+
end
|
121
|
+
|
93
122
|
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :id => 1, :fullname => "Tobias Fünke", :active => true }.to_json)
|
94
123
|
FakeWeb.register_uri(:delete, "https://api.example.com/users/1", :body => { :id => 1, :fullname => "Lindsay Fünke", :active => false }.to_json)
|
95
124
|
|
data/spec/model/paths_spec.rb
CHANGED
@@ -39,6 +39,42 @@ describe Her::Model::Paths do
|
|
39
39
|
end
|
40
40
|
end
|
41
41
|
|
42
|
+
context "simple model with multiple words" do
|
43
|
+
before do # {{{
|
44
|
+
spawn_model :AdminUser
|
45
|
+
end # }}}
|
46
|
+
|
47
|
+
describe "#build_request_path" do
|
48
|
+
it "builds paths with defaults" do # {{{
|
49
|
+
AdminUser.build_request_path(:id => "foo").should == "/admin_users/foo"
|
50
|
+
AdminUser.build_request_path.should == "/admin_users"
|
51
|
+
end # }}}
|
52
|
+
|
53
|
+
it "builds paths with custom collection path" do # {{{
|
54
|
+
AdminUser.collection_path "/users"
|
55
|
+
AdminUser.build_request_path(:id => "foo").should == "/users/foo"
|
56
|
+
AdminUser.build_request_path.should == "/users"
|
57
|
+
end # }}}
|
58
|
+
|
59
|
+
it "builds paths with custom collection path with multiple variables" do # {{{
|
60
|
+
AdminUser.collection_path "/organizations/:organization_id/users"
|
61
|
+
AdminUser.build_request_path(:id => "foo", :_organization_id => "acme").should == "/organizations/acme/users/foo"
|
62
|
+
AdminUser.build_request_path(:_organization_id => "acme").should == "/organizations/acme/users"
|
63
|
+
end # }}}
|
64
|
+
|
65
|
+
it "builds paths with custom item path" do # {{{
|
66
|
+
AdminUser.resource_path "/users/:id"
|
67
|
+
AdminUser.build_request_path(:id => "foo").should == "/users/foo"
|
68
|
+
AdminUser.build_request_path.should == "/admin_users"
|
69
|
+
end # }}}
|
70
|
+
|
71
|
+
it "raises exceptions when building a path without required custom variables" do # {{{
|
72
|
+
AdminUser.collection_path "/organizations/:organization_id/users"
|
73
|
+
expect { AdminUser.build_request_path(:id => "foo") }.should raise_error(Her::Errors::PathError)
|
74
|
+
end # }}}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
42
78
|
context "nested model" do
|
43
79
|
before do # {{{
|
44
80
|
spawn_submodel :Base, :User
|
@@ -56,7 +92,12 @@ describe Her::Model::Paths do
|
|
56
92
|
context "making HTTP requests" do
|
57
93
|
before do # {{{
|
58
94
|
api = Her::API.new
|
59
|
-
api.setup :base_uri => "https://api.example.com"
|
95
|
+
api.setup :base_uri => "https://api.example.com" do |builder|
|
96
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
97
|
+
builder.use Faraday::Request::UrlEncoded
|
98
|
+
builder.use Faraday::Adapter::NetHttp
|
99
|
+
end
|
100
|
+
|
60
101
|
FakeWeb.register_uri(:get, "https://api.example.com/organizations/2/users", :body => [{ :id => 1, :fullname => "Tobias Fünke", :organization_id => 2 }, { :id => 2, :fullname => "Lindsay Fünke", :organization_id => 2 }].to_json)
|
61
102
|
FakeWeb.register_uri(:post, "https://api.example.com/organizations/2/users", :body => { :id => 1, :fullname => "Tobias Fünke", :organization_id => 2 }.to_json)
|
62
103
|
FakeWeb.register_uri(:put, "https://api.example.com/organizations/2/users/1", :body => { :id => 1, :fullname => "Lindsay Fünke", :organization_id => 2 }.to_json)
|
@@ -43,7 +43,12 @@ describe Her::Model::Relationships do
|
|
43
43
|
|
44
44
|
context "handling relationships" do
|
45
45
|
before do # {{{
|
46
|
-
Her::API.setup :base_uri => "https://api.example.com"
|
46
|
+
Her::API.setup :base_uri => "https://api.example.com" do |builder|
|
47
|
+
builder.use Her::Middleware::FirstLevelParseJSON
|
48
|
+
builder.use Faraday::Request::UrlEncoded
|
49
|
+
builder.use Faraday::Adapter::NetHttp
|
50
|
+
end
|
51
|
+
|
47
52
|
FakeWeb.register_uri(:get, "https://api.example.com/users/1", :body => { :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)
|
48
53
|
FakeWeb.register_uri(:get, "https://api.example.com/users/2", :body => { :id => 2, :name => "Lindsay Fünke", :organization_id => 1 }.to_json)
|
49
54
|
FakeWeb.register_uri(:get, "https://api.example.com/users/2/comments", :body => [{ :id => 4, :body => "They're having a FIRESALE?" }, { :id => 5, :body => "Is this the tiny town from Footloose?" }].to_json)
|
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.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,151 +9,216 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-05-
|
12
|
+
date: 2012-05-03 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rake
|
16
|
-
requirement:
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
|
-
- - =
|
19
|
+
- - '='
|
20
20
|
- !ruby/object:Gem::Version
|
21
21
|
version: 0.9.2.2
|
22
22
|
type: :development
|
23
23
|
prerelease: false
|
24
|
-
version_requirements:
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - '='
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: 0.9.2.2
|
25
30
|
- !ruby/object:Gem::Dependency
|
26
31
|
name: rspec
|
27
|
-
requirement:
|
32
|
+
requirement: !ruby/object:Gem::Requirement
|
28
33
|
none: false
|
29
34
|
requirements:
|
30
|
-
- - =
|
35
|
+
- - '='
|
31
36
|
- !ruby/object:Gem::Version
|
32
37
|
version: 2.9.0
|
33
38
|
type: :development
|
34
39
|
prerelease: false
|
35
|
-
version_requirements:
|
40
|
+
version_requirements: !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - '='
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
version: 2.9.0
|
36
46
|
- !ruby/object:Gem::Dependency
|
37
47
|
name: yard
|
38
|
-
requirement:
|
48
|
+
requirement: !ruby/object:Gem::Requirement
|
39
49
|
none: false
|
40
50
|
requirements:
|
41
|
-
- - =
|
51
|
+
- - '='
|
42
52
|
- !ruby/object:Gem::Version
|
43
53
|
version: 0.7.5
|
44
54
|
type: :development
|
45
55
|
prerelease: false
|
46
|
-
version_requirements:
|
56
|
+
version_requirements: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - '='
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 0.7.5
|
47
62
|
- !ruby/object:Gem::Dependency
|
48
63
|
name: redcarpet
|
49
|
-
requirement:
|
64
|
+
requirement: !ruby/object:Gem::Requirement
|
50
65
|
none: false
|
51
66
|
requirements:
|
52
|
-
- - =
|
67
|
+
- - '='
|
53
68
|
- !ruby/object:Gem::Version
|
54
69
|
version: 1.17.2
|
55
70
|
type: :development
|
56
71
|
prerelease: false
|
57
|
-
version_requirements:
|
72
|
+
version_requirements: !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - '='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: 1.17.2
|
58
78
|
- !ruby/object:Gem::Dependency
|
59
79
|
name: mocha
|
60
|
-
requirement:
|
80
|
+
requirement: !ruby/object:Gem::Requirement
|
61
81
|
none: false
|
62
82
|
requirements:
|
63
|
-
- - =
|
83
|
+
- - '='
|
64
84
|
- !ruby/object:Gem::Version
|
65
85
|
version: 0.11.3
|
66
86
|
type: :development
|
67
87
|
prerelease: false
|
68
|
-
version_requirements:
|
88
|
+
version_requirements: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - '='
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
version: 0.11.3
|
69
94
|
- !ruby/object:Gem::Dependency
|
70
95
|
name: fakeweb
|
71
|
-
requirement:
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
72
97
|
none: false
|
73
98
|
requirements:
|
74
|
-
- - =
|
99
|
+
- - '='
|
75
100
|
- !ruby/object:Gem::Version
|
76
101
|
version: 1.3.0
|
77
102
|
type: :development
|
78
103
|
prerelease: false
|
79
|
-
version_requirements:
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - '='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: 1.3.0
|
80
110
|
- !ruby/object:Gem::Dependency
|
81
111
|
name: guard
|
82
|
-
requirement:
|
112
|
+
requirement: !ruby/object:Gem::Requirement
|
83
113
|
none: false
|
84
114
|
requirements:
|
85
|
-
- - =
|
115
|
+
- - '='
|
86
116
|
- !ruby/object:Gem::Version
|
87
117
|
version: 1.0.1
|
88
118
|
type: :development
|
89
119
|
prerelease: false
|
90
|
-
version_requirements:
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
none: false
|
122
|
+
requirements:
|
123
|
+
- - '='
|
124
|
+
- !ruby/object:Gem::Version
|
125
|
+
version: 1.0.1
|
91
126
|
- !ruby/object:Gem::Dependency
|
92
127
|
name: guard-rspec
|
93
|
-
requirement:
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
94
129
|
none: false
|
95
130
|
requirements:
|
96
|
-
- - =
|
131
|
+
- - '='
|
97
132
|
- !ruby/object:Gem::Version
|
98
133
|
version: 0.7.0
|
99
134
|
type: :development
|
100
135
|
prerelease: false
|
101
|
-
version_requirements:
|
136
|
+
version_requirements: !ruby/object:Gem::Requirement
|
137
|
+
none: false
|
138
|
+
requirements:
|
139
|
+
- - '='
|
140
|
+
- !ruby/object:Gem::Version
|
141
|
+
version: 0.7.0
|
102
142
|
- !ruby/object:Gem::Dependency
|
103
143
|
name: rb-fsevent
|
104
|
-
requirement:
|
144
|
+
requirement: !ruby/object:Gem::Requirement
|
105
145
|
none: false
|
106
146
|
requirements:
|
107
|
-
- - =
|
147
|
+
- - '='
|
108
148
|
- !ruby/object:Gem::Version
|
109
149
|
version: 0.9.1
|
110
150
|
type: :development
|
111
151
|
prerelease: false
|
112
|
-
version_requirements:
|
152
|
+
version_requirements: !ruby/object:Gem::Requirement
|
153
|
+
none: false
|
154
|
+
requirements:
|
155
|
+
- - '='
|
156
|
+
- !ruby/object:Gem::Version
|
157
|
+
version: 0.9.1
|
113
158
|
- !ruby/object:Gem::Dependency
|
114
159
|
name: growl
|
115
|
-
requirement:
|
160
|
+
requirement: !ruby/object:Gem::Requirement
|
116
161
|
none: false
|
117
162
|
requirements:
|
118
|
-
- - =
|
163
|
+
- - '='
|
119
164
|
- !ruby/object:Gem::Version
|
120
165
|
version: 1.0.3
|
121
166
|
type: :development
|
122
167
|
prerelease: false
|
123
|
-
version_requirements:
|
168
|
+
version_requirements: !ruby/object:Gem::Requirement
|
169
|
+
none: false
|
170
|
+
requirements:
|
171
|
+
- - '='
|
172
|
+
- !ruby/object:Gem::Version
|
173
|
+
version: 1.0.3
|
124
174
|
- !ruby/object:Gem::Dependency
|
125
175
|
name: activesupport
|
126
|
-
requirement:
|
176
|
+
requirement: !ruby/object:Gem::Requirement
|
127
177
|
none: false
|
128
178
|
requirements:
|
129
|
-
- - =
|
179
|
+
- - '='
|
130
180
|
- !ruby/object:Gem::Version
|
131
181
|
version: 3.2.3
|
132
182
|
type: :runtime
|
133
183
|
prerelease: false
|
134
|
-
version_requirements:
|
184
|
+
version_requirements: !ruby/object:Gem::Requirement
|
185
|
+
none: false
|
186
|
+
requirements:
|
187
|
+
- - '='
|
188
|
+
- !ruby/object:Gem::Version
|
189
|
+
version: 3.2.3
|
135
190
|
- !ruby/object:Gem::Dependency
|
136
191
|
name: faraday
|
137
|
-
requirement:
|
192
|
+
requirement: !ruby/object:Gem::Requirement
|
138
193
|
none: false
|
139
194
|
requirements:
|
140
|
-
- - =
|
195
|
+
- - '='
|
141
196
|
- !ruby/object:Gem::Version
|
142
197
|
version: 0.8.0
|
143
198
|
type: :runtime
|
144
199
|
prerelease: false
|
145
|
-
version_requirements:
|
200
|
+
version_requirements: !ruby/object:Gem::Requirement
|
201
|
+
none: false
|
202
|
+
requirements:
|
203
|
+
- - '='
|
204
|
+
- !ruby/object:Gem::Version
|
205
|
+
version: 0.8.0
|
146
206
|
- !ruby/object:Gem::Dependency
|
147
207
|
name: multi_json
|
148
|
-
requirement:
|
208
|
+
requirement: !ruby/object:Gem::Requirement
|
149
209
|
none: false
|
150
210
|
requirements:
|
151
|
-
- - =
|
211
|
+
- - '='
|
152
212
|
- !ruby/object:Gem::Version
|
153
213
|
version: 1.3.4
|
154
214
|
type: :runtime
|
155
215
|
prerelease: false
|
156
|
-
version_requirements:
|
216
|
+
version_requirements: !ruby/object:Gem::Requirement
|
217
|
+
none: false
|
218
|
+
requirements:
|
219
|
+
- - '='
|
220
|
+
- !ruby/object:Gem::Version
|
221
|
+
version: 1.3.4
|
157
222
|
description: Her is an ORM that maps REST resources and collections to Ruby objects
|
158
223
|
email:
|
159
224
|
- remi@exomel.com
|
@@ -168,6 +233,7 @@ files:
|
|
168
233
|
- LICENSE
|
169
234
|
- README.md
|
170
235
|
- Rakefile
|
236
|
+
- UPGRADE.md
|
171
237
|
- examples/twitter-oauth/Gemfile
|
172
238
|
- examples/twitter-oauth/app.rb
|
173
239
|
- examples/twitter-oauth/config.ru
|
@@ -216,7 +282,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
216
282
|
version: '0'
|
217
283
|
segments:
|
218
284
|
- 0
|
219
|
-
hash:
|
285
|
+
hash: -3092731316656290620
|
220
286
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
221
287
|
none: false
|
222
288
|
requirements:
|
@@ -225,10 +291,10 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
225
291
|
version: '0'
|
226
292
|
segments:
|
227
293
|
- 0
|
228
|
-
hash:
|
294
|
+
hash: -3092731316656290620
|
229
295
|
requirements: []
|
230
296
|
rubyforge_project:
|
231
|
-
rubygems_version: 1.8.
|
297
|
+
rubygems_version: 1.8.18
|
232
298
|
signing_key:
|
233
299
|
specification_version: 3
|
234
300
|
summary: A simple Representational State Transfer-based Hypertext Transfer Protocol-powered
|