her 0.2.3 → 0.2.4
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 +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
|