hyperclient 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +44 -13
- data/CHANGELOG.md +5 -0
- data/Gemfile +1 -1
- data/README.md +9 -0
- data/RELEASING.md +69 -0
- data/UPGRADING.md +26 -1
- data/features/api_navigation.feature +5 -0
- data/features/steps/api_navigation.rb +8 -0
- data/features/support/api.rb +2 -0
- data/features/support/fixtures.rb +22 -1
- data/lib/hyperclient/collection.rb +10 -5
- data/lib/hyperclient/curie.rb +5 -5
- data/lib/hyperclient/entry_point.rb +10 -9
- data/lib/hyperclient/link.rb +32 -57
- data/lib/hyperclient/link_collection.rb +7 -5
- data/lib/hyperclient/resource.rb +12 -0
- data/lib/hyperclient/resource_collection.rb +1 -1
- data/lib/hyperclient/version.rb +1 -1
- data/test/hyperclient/collection_test.rb +0 -1
- data/test/hyperclient/link_test.rb +10 -12
- data/test/hyperclient/resource_test.rb +38 -0
- data/test/test_helper.rb +0 -2
- metadata +37 -36
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c935e08d5410e72969d8b83c213ef56d7ae5236e
|
4
|
+
data.tar.gz: a250cb39f383c471f637cec668ce683c0310e808
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 10c73a4a2d78e9947a69719e831d1dccd467fecf6006a21fba2561cd23e74e5c7b8604398dc75477a76a5327cf0dfc31e018424cf41c81067bb057854dbd5960
|
7
|
+
data.tar.gz: c4eba8f9223ccc8ffa166dc731e32ac842d8230f4e9ee507b9f175503ee935a235e5820d823a24378239080de2d8c74bfb2ee29a25949a841d44d78d5a4ff747
|
data/.rubocop_todo.yml
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
# This configuration was generated by
|
2
|
-
#
|
1
|
+
# This configuration was generated by
|
2
|
+
# `rubocop --auto-gen-config`
|
3
|
+
# on 2015-08-15 16:01:39 -0400 using RuboCop version 0.33.0.
|
3
4
|
# The point is for the user to remove these configuration records
|
4
5
|
# one by one as the offenses are removed from the code base.
|
5
6
|
# Note that changes in the inspected code, or installation of new
|
@@ -8,40 +9,70 @@
|
|
8
9
|
# Offense count: 1
|
9
10
|
# Configuration parameters: CountComments.
|
10
11
|
Metrics/ClassLength:
|
11
|
-
Max:
|
12
|
+
Max: 103
|
12
13
|
|
13
|
-
# Offense count:
|
14
|
+
# Offense count: 80
|
14
15
|
# Configuration parameters: AllowURI, URISchemes.
|
15
16
|
Metrics/LineLength:
|
16
|
-
Max:
|
17
|
+
Max: 142
|
17
18
|
|
18
19
|
# Offense count: 3
|
19
20
|
# Configuration parameters: CountComments.
|
20
21
|
Metrics/MethodLength:
|
21
22
|
Max: 14
|
22
23
|
|
24
|
+
# Offense count: 3
|
25
|
+
# Configuration parameters: CountComments.
|
26
|
+
Metrics/ModuleLength:
|
27
|
+
Max: 238
|
28
|
+
|
23
29
|
# Offense count: 1
|
24
30
|
Style/AsciiComments:
|
25
|
-
|
31
|
+
Exclude:
|
32
|
+
- 'lib/hyperclient/collection.rb'
|
26
33
|
|
27
34
|
# Offense count: 2
|
28
35
|
# Configuration parameters: EnforcedStyle, SupportedStyles.
|
29
36
|
Style/ClassAndModuleChildren:
|
30
|
-
|
37
|
+
Exclude:
|
38
|
+
- 'features/steps/api_navigation.rb'
|
39
|
+
- 'features/steps/default_config.rb'
|
31
40
|
|
32
41
|
# Offense count: 14
|
33
42
|
Style/Documentation:
|
34
|
-
|
43
|
+
Exclude:
|
44
|
+
- 'features/steps/api_navigation.rb'
|
45
|
+
- 'features/steps/default_config.rb'
|
46
|
+
- 'features/support/api.rb'
|
47
|
+
- 'features/support/fixtures.rb'
|
48
|
+
- 'lib/hyperclient/version.rb'
|
49
|
+
- 'test/faraday/connection_test.rb'
|
50
|
+
- 'test/hyperclient/attributes_test.rb'
|
51
|
+
- 'test/hyperclient/collection_test.rb'
|
52
|
+
- 'test/hyperclient/curie_test.rb'
|
53
|
+
- 'test/hyperclient/entry_point_test.rb'
|
54
|
+
- 'test/hyperclient/link_collection_test.rb'
|
55
|
+
- 'test/hyperclient/link_test.rb'
|
56
|
+
- 'test/hyperclient/resource_collection_test.rb'
|
57
|
+
- 'test/hyperclient/resource_test.rb'
|
35
58
|
|
36
59
|
# Offense count: 2
|
37
60
|
Style/DoubleNegation:
|
38
|
-
|
61
|
+
Exclude:
|
62
|
+
- 'lib/hyperclient/curie.rb'
|
63
|
+
- 'lib/hyperclient/link.rb'
|
39
64
|
|
40
65
|
# Offense count: 5
|
66
|
+
# Cop supports --auto-correct.
|
41
67
|
Style/Lambda:
|
42
|
-
|
68
|
+
Exclude:
|
69
|
+
- 'test/hyperclient/entry_point_test.rb'
|
70
|
+
- 'test/hyperclient/link_test.rb'
|
71
|
+
- 'test/hyperclient/resource_test.rb'
|
43
72
|
|
44
|
-
# Offense count:
|
45
|
-
#
|
73
|
+
# Offense count: 1
|
74
|
+
# Cop supports --auto-correct.
|
75
|
+
# Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
|
46
76
|
Style/RegexpLiteral:
|
47
|
-
|
77
|
+
Exclude:
|
78
|
+
- 'features/support/api.rb'
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
### 0.7.1 (August 15, 2015)
|
2
|
+
|
3
|
+
* [#89](https://github.com/codegram/hyperclient/issues/89): Added `Hyperclient::Resource#fetch` - [@alabeduarte](https://github.com/alabeduarte).
|
4
|
+
* [#87](https://github.com/codegram/hyperclient/pull/87): Fix: eager delegation causes link skipping - [@dblock](https://github.com/dblock).
|
5
|
+
|
1
6
|
### 0.7.0 (February 23, 2015)
|
2
7
|
|
3
8
|
This version introduces several backwards incompatible changes. See [UPGRADING](UPGRADING.md) for details.
|
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -95,6 +95,15 @@ api.splines.each do |spline|
|
|
95
95
|
end
|
96
96
|
```
|
97
97
|
|
98
|
+
Other methods, including `[]` and `fetch` are also available
|
99
|
+
|
100
|
+
```ruby
|
101
|
+
api.splines.each do |spline|
|
102
|
+
puts "A spline with ID #{spline[:uuid]}."
|
103
|
+
puts "Maybe with reticulated: #{spline.fetch(:reticulated, '-- no reticulated')}"
|
104
|
+
end
|
105
|
+
```
|
106
|
+
|
98
107
|
### Links and Embedded Resources
|
99
108
|
|
100
109
|
The splines example above followed a link called "splines". While you can, you do not need to specify the HAL navigational structure, including links or embedded resources. Hyperclient will resolve these for you. If you prefer, you can explicitly navigate the link structure via `_links`. In the following example the "splines" link leads to a collection of embedded splines. Invoking `api.splines` is equivalent to `api._links.splines._embedded.splines`.
|
data/RELEASING.md
ADDED
@@ -0,0 +1,69 @@
|
|
1
|
+
Releasing Hyperclient
|
2
|
+
=====================
|
3
|
+
|
4
|
+
There're no particular rules about when to release hyperclient. Release bug fixes frequenty, features not so frequently and breaking API changes rarely.
|
5
|
+
|
6
|
+
### Release
|
7
|
+
|
8
|
+
Run tests, check that all tests succeed locally.
|
9
|
+
|
10
|
+
```
|
11
|
+
bundle install
|
12
|
+
rake
|
13
|
+
```
|
14
|
+
|
15
|
+
Check that the last build succeeded in [Travis CI](https://travis-ci.org/codegram/hyperclient) for all supported platforms.
|
16
|
+
|
17
|
+
Increment the version, modify [lib/hyperclient/version.rb](lib/hyperclient/version.rb).
|
18
|
+
|
19
|
+
* Increment the third number if the release has bug fixes and/or very minor features, only (eg. change `0.5.1` to `0.5.2`).
|
20
|
+
* Increment the second number if the release contains major features or breaking API changes (eg. change `0.5.1` to `0.4.0`).
|
21
|
+
|
22
|
+
Change "Next Release" in [CHANGELOG.md](CHANGELOG.md) to the new version.
|
23
|
+
|
24
|
+
```
|
25
|
+
0.4.0 (2014-01-27)
|
26
|
+
==================
|
27
|
+
```
|
28
|
+
|
29
|
+
Remove the line with "Your contribution here.", since there will be no more contributions to this release.
|
30
|
+
|
31
|
+
Commit your changes.
|
32
|
+
|
33
|
+
```
|
34
|
+
git add CHANGELOG.md lib/hyperclient/version.rb
|
35
|
+
git commit -m "Preparing for release, 0.4.0."
|
36
|
+
git push origin master
|
37
|
+
```
|
38
|
+
|
39
|
+
Release.
|
40
|
+
|
41
|
+
```
|
42
|
+
$ rake release
|
43
|
+
|
44
|
+
hyperclient 0.4.0 built to pkg/hyperclient-0.4.0.gem.
|
45
|
+
Tagged v0.4.0.
|
46
|
+
Pushed git commits and tags.
|
47
|
+
Pushed hyperclient 0.4.0 to rubygems.org.
|
48
|
+
```
|
49
|
+
|
50
|
+
### Prepare for the Next Version
|
51
|
+
|
52
|
+
Add the next release to [CHANGELOG.md](CHANGELOG.md).
|
53
|
+
|
54
|
+
```
|
55
|
+
Next Release
|
56
|
+
============
|
57
|
+
|
58
|
+
* Your contribution here.
|
59
|
+
```
|
60
|
+
|
61
|
+
Increment the minor version, modify [lib/hyperclient/version.rb](lib/hyperclient/version.rb).
|
62
|
+
|
63
|
+
Comit your changes.
|
64
|
+
|
65
|
+
```
|
66
|
+
git add CHANGELOG.md lib/hyperclient/version.rb
|
67
|
+
git commit -m "Preparing for next release, 0.4.1."
|
68
|
+
git push origin master
|
69
|
+
```
|
data/UPGRADING.md
CHANGED
@@ -14,6 +14,32 @@ Hyperclient.new('https://api.example.org/') do |client|
|
|
14
14
|
end
|
15
15
|
```
|
16
16
|
|
17
|
+
#### Changes to default headers may impact Hyperclient in test
|
18
|
+
|
19
|
+
If you are using Hyperclient to test an API as [described in README.md](https://github.com/codegram/hyperclient#testing-using-hyperclient) and if the API expects 'application/hal+json' as the content_type for requests, you may need to update how you set up Hyperclient in your specs. [As defined in the ```default_faraday_block``` method in ```Hyperclient::EntryPoint```](https://github.com/codegram/hyperclient/blob/9f908854395523b38e0d4fc834d6db1f8b6dfb22/lib/hyperclient/entry_point.rb#L129), you can specify that you are encoding requests via faraday as ```:hal_json```.
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
Hyperclient.new('http://example.org/api') do |client|
|
23
|
+
client.connection(default: false) do |conn|
|
24
|
+
conn.request :hal_json
|
25
|
+
conn.response :json
|
26
|
+
conn.use Faraday::Adapter::Rack, app
|
27
|
+
end
|
28
|
+
end
|
29
|
+
```
|
30
|
+
|
31
|
+
instead of:
|
32
|
+
|
33
|
+
```ruby
|
34
|
+
Hyperclient.new('http://example.org/api') do |client|
|
35
|
+
client.connection(default: false) do |conn|
|
36
|
+
conn.request :json
|
37
|
+
conn.response :json
|
38
|
+
conn.use Faraday::Adapter::Rack, app
|
39
|
+
end
|
40
|
+
end
|
41
|
+
```
|
42
|
+
|
17
43
|
### Upgrading to >= 0.6.0
|
18
44
|
|
19
45
|
#### Changes in HTTP Error Handling
|
@@ -61,4 +87,3 @@ Instead Of | Write This
|
|
61
87
|
`api.links.widget.expand(id: 3).put(name: 'updated`) | `api._links.widget._expand(id: 3)._put(name: 'updated')`
|
62
88
|
|
63
89
|
For more information see [#63](https://github.com/codegram/hyperclient/pull/63).
|
64
|
-
|
@@ -21,3 +21,8 @@ Feature: API navigation
|
|
21
21
|
Given I connect to the API
|
22
22
|
When I load a single post
|
23
23
|
Then I should also be able to access it's embedded comments
|
24
|
+
|
25
|
+
Scenario: Navigation links
|
26
|
+
When I connect to the API
|
27
|
+
Then I should be able to navigate to next page
|
28
|
+
Then I should be able to navigate to next page without links
|
@@ -30,4 +30,12 @@ class Spinach::Features::ApiNavigation < Spinach::FeatureSteps
|
|
30
30
|
comment = @post._embedded.comments.first
|
31
31
|
comment._attributes.title.wont_equal nil
|
32
32
|
end
|
33
|
+
|
34
|
+
step 'I should be able to navigate to next page' do
|
35
|
+
assert_equal '/posts_of_page2', api._links.next._links.posts._url
|
36
|
+
end
|
37
|
+
|
38
|
+
step 'I should be able to navigate to next page without links' do
|
39
|
+
assert_equal '/posts_of_page2', api.next.posts._url
|
40
|
+
end
|
33
41
|
end
|
data/features/support/api.rb
CHANGED
@@ -8,6 +8,8 @@ module API
|
|
8
8
|
stub_request(:any, %r{api.example.org*}).to_return(body: root_response, headers: { 'Content-Type' => 'application/hal+json' })
|
9
9
|
stub_request(:get, 'api.example.org/posts').to_return(body: posts_response, headers: { 'Content-Type' => 'application/hal+json' })
|
10
10
|
stub_request(:get, 'api.example.org/posts/1').to_return(body: post_response, headers: { 'Content-Type' => 'application/hal+json' })
|
11
|
+
stub_request(:get, 'api.example.org/page2').to_return(body: page2_response, headers: { 'Content-Type' => 'application/hal+json' })
|
12
|
+
stub_request(:get, 'api.example.org/page3').to_return(body: page3_response, headers: { 'Content-Type' => 'application/hal+json' })
|
11
13
|
end
|
12
14
|
|
13
15
|
def api
|
@@ -8,7 +8,8 @@ module Spinach
|
|
8
8
|
"self": { "href": "/" },
|
9
9
|
"posts": { "href": "/posts" },
|
10
10
|
"search": { "href": "/search{?q}", "templated": true },
|
11
|
-
"api:authors": { "href": "/authors" }
|
11
|
+
"api:authors": { "href": "/authors" },
|
12
|
+
"next": { "href": "/page2" }
|
12
13
|
}
|
13
14
|
}'
|
14
15
|
end
|
@@ -39,5 +40,25 @@ module Spinach
|
|
39
40
|
}
|
40
41
|
}'
|
41
42
|
end
|
43
|
+
|
44
|
+
def page2_response
|
45
|
+
'{
|
46
|
+
"_links": {
|
47
|
+
"self": { "href": "/page2" },
|
48
|
+
"posts": { "href": "/posts_of_page2" },
|
49
|
+
"next": { "href": "/page3" }
|
50
|
+
}
|
51
|
+
}'
|
52
|
+
end
|
53
|
+
|
54
|
+
def page3_response
|
55
|
+
'{
|
56
|
+
"_links": {
|
57
|
+
"self": { "href": "/page3" },
|
58
|
+
"posts": { "href": "/posts_of_page3" },
|
59
|
+
"api:authors": { "href": "/authors" }
|
60
|
+
}
|
61
|
+
}'
|
62
|
+
end
|
42
63
|
end
|
43
64
|
end
|
@@ -1,5 +1,5 @@
|
|
1
1
|
module Hyperclient
|
2
|
-
# Public: A helper class to
|
2
|
+
# Public: A helper class to wrap a collection of elements and provide
|
3
3
|
# Hash-like access or via a method call.
|
4
4
|
#
|
5
5
|
# Examples
|
@@ -25,8 +25,13 @@ module Hyperclient
|
|
25
25
|
@collection.each(&block)
|
26
26
|
end
|
27
27
|
|
28
|
-
|
29
|
-
|
28
|
+
# Public: Checks if this collection includes a given key.
|
29
|
+
#
|
30
|
+
# key - A String or Symbol to check for existance.
|
31
|
+
#
|
32
|
+
# Returns True/False.
|
33
|
+
def include?(key)
|
34
|
+
@collection.include?(key)
|
30
35
|
end
|
31
36
|
|
32
37
|
# Public: Returns a value from the collection for the given key.
|
@@ -51,7 +56,7 @@ module Hyperclient
|
|
51
56
|
@collection[name.to_s]
|
52
57
|
end
|
53
58
|
|
54
|
-
# Public: Returns the wrapped collection as a
|
59
|
+
# Public: Returns the wrapped collection as a Hash.
|
55
60
|
#
|
56
61
|
# Returns a Hash.
|
57
62
|
def to_h
|
@@ -70,7 +75,7 @@ module Hyperclient
|
|
70
75
|
#
|
71
76
|
# Returns an Object.
|
72
77
|
def method_missing(method_name, *_args, &_block)
|
73
|
-
@collection.fetch(method_name.to_s)
|
78
|
+
@collection.fetch(method_name.to_s) do
|
74
79
|
fail "Could not find `#{method_name}` in #{self.class.name}"
|
75
80
|
end
|
76
81
|
end
|
data/lib/hyperclient/curie.rb
CHANGED
@@ -7,8 +7,8 @@ module Hyperclient
|
|
7
7
|
class Curie
|
8
8
|
# Public: Initializes a new Curie.
|
9
9
|
#
|
10
|
-
#
|
11
|
-
# entry_point
|
10
|
+
# curie_hash - The String with the URI of the curie.
|
11
|
+
# entry_point - The EntryPoint object to inject the configuration.
|
12
12
|
def initialize(curie_hash, entry_point)
|
13
13
|
@curie_hash = curie_hash
|
14
14
|
@entry_point = entry_point
|
@@ -22,12 +22,12 @@ module Hyperclient
|
|
22
22
|
!!@curie_hash['templated']
|
23
23
|
end
|
24
24
|
|
25
|
-
# Public: Returns the name property of the Curie
|
25
|
+
# Public: Returns the name property of the Curie.
|
26
26
|
def name
|
27
27
|
@curie_hash['name']
|
28
28
|
end
|
29
29
|
|
30
|
-
# Public: Returns the href property of the Curie
|
30
|
+
# Public: Returns the href property of the Curie.
|
31
31
|
def href
|
32
32
|
@curie_hash['href']
|
33
33
|
end
|
@@ -38,7 +38,7 @@ module Hyperclient
|
|
38
38
|
|
39
39
|
# Public: Expands the Curie when is templated with the given variables.
|
40
40
|
#
|
41
|
-
# rel - The rel to expand.
|
41
|
+
# rel - The String rel to expand.
|
42
42
|
#
|
43
43
|
# Returns a new expanded url.
|
44
44
|
def expand(rel)
|
@@ -29,6 +29,7 @@ module Hyperclient
|
|
29
29
|
#
|
30
30
|
class EntryPoint < Link
|
31
31
|
extend Forwardable
|
32
|
+
|
32
33
|
# Public: Delegates common methods to be used with the Faraday connection.
|
33
34
|
def_delegators :connection, :basic_auth, :digest_auth, :token_auth, :headers, :headers=, :params, :params=
|
34
35
|
|
@@ -43,9 +44,9 @@ module Hyperclient
|
|
43
44
|
|
44
45
|
# Public: A Faraday connection to use as a HTTP client.
|
45
46
|
#
|
46
|
-
# options
|
47
|
-
#
|
48
|
-
#
|
47
|
+
# options - A Hash containing additional options to pass to Farday. Use
|
48
|
+
# {default: false} if you want to skip using default Faraday options set by
|
49
|
+
# Hyperclient.
|
49
50
|
#
|
50
51
|
# Returns a Faraday::Connection.
|
51
52
|
def connection(options = {}, &block)
|
@@ -123,12 +124,12 @@ module Hyperclient
|
|
123
124
|
#
|
124
125
|
# Returns a block.
|
125
126
|
def default_faraday_block
|
126
|
-
lambda do |
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
127
|
+
lambda do |connection|
|
128
|
+
connection.use Faraday::Response::RaiseError
|
129
|
+
connection.use FaradayMiddleware::FollowRedirects
|
130
|
+
connection.request :hal_json
|
131
|
+
connection.response :hal_json, content_type: /\bjson$/
|
132
|
+
connection.adapter :net_http
|
132
133
|
end
|
133
134
|
end
|
134
135
|
|
data/lib/hyperclient/link.rb
CHANGED
@@ -10,7 +10,7 @@ module Hyperclient
|
|
10
10
|
#
|
11
11
|
# key - The key or name of the link.
|
12
12
|
# link - The String with the URI of the link.
|
13
|
-
# entry_point - The EntryPoint object to inject the
|
13
|
+
# entry_point - The EntryPoint object to inject the configuration.
|
14
14
|
# uri_variables - The optional Hash with the variables to expand the link
|
15
15
|
# if it is templated.
|
16
16
|
def initialize(key, link, entry_point, uri_variables = nil)
|
@@ -80,76 +80,37 @@ module Hyperclient
|
|
80
80
|
@link['hreflang']
|
81
81
|
end
|
82
82
|
|
83
|
-
# Public: Returns the Resource which the Link is pointing to.
|
84
|
-
def _get
|
85
|
-
@resource = begin
|
86
|
-
response = Futuroscope::Future.new do
|
87
|
-
_connection.get(_url)
|
88
|
-
end
|
89
|
-
Resource.new(response.body, @entry_point, response)
|
90
|
-
end
|
91
|
-
end
|
92
|
-
|
93
83
|
def _resource
|
94
84
|
@resource || _get
|
95
85
|
end
|
96
86
|
|
97
|
-
|
98
|
-
|
87
|
+
# Public: Returns the Resource which the Link is pointing to.
|
88
|
+
def _get
|
89
|
+
http_method(:get)
|
99
90
|
end
|
100
91
|
|
101
92
|
def _options
|
102
|
-
|
103
|
-
response = Futuroscope::Future.new do
|
104
|
-
_connection.run_request(:options, _url, nil, nil)
|
105
|
-
end
|
106
|
-
Resource.new(response.body, @entry_point, response)
|
107
|
-
end
|
93
|
+
http_method(:options)
|
108
94
|
end
|
109
95
|
|
110
96
|
def _head
|
111
|
-
|
112
|
-
response = Futuroscope::Future.new do
|
113
|
-
_connection.head(_url)
|
114
|
-
end
|
115
|
-
Resource.new(response.body, @entry_point, response)
|
116
|
-
end
|
97
|
+
http_method(:head)
|
117
98
|
end
|
118
99
|
|
119
100
|
def _delete
|
120
|
-
|
121
|
-
response = Futuroscope::Future.new do
|
122
|
-
_connection.delete(_url)
|
123
|
-
end
|
124
|
-
Resource.new(response.body, @entry_point, response)
|
125
|
-
end
|
101
|
+
http_method(:delete)
|
126
102
|
end
|
127
103
|
|
128
104
|
def _post(params = {})
|
129
|
-
|
130
|
-
response = Futuroscope::Future.new do
|
131
|
-
_connection.post(_url, params)
|
132
|
-
end
|
133
|
-
Resource.new(response.body, @entry_point, response)
|
134
|
-
end
|
105
|
+
http_method(:post, params)
|
135
106
|
end
|
136
107
|
|
137
108
|
def _put(params = {})
|
138
|
-
|
139
|
-
response = Futuroscope::Future.new do
|
140
|
-
_connection.put(_url, params)
|
141
|
-
end
|
142
|
-
Resource.new(response.body, @entry_point, response)
|
143
|
-
end
|
109
|
+
http_method(:put, params)
|
144
110
|
end
|
145
111
|
|
146
112
|
def _patch(params = {})
|
147
|
-
|
148
|
-
response = Futuroscope::Future.new do
|
149
|
-
_connection.patch(_url, params)
|
150
|
-
end
|
151
|
-
Resource.new(response.body, @entry_point, response)
|
152
|
-
end
|
113
|
+
http_method(:patch, params)
|
153
114
|
end
|
154
115
|
|
155
116
|
def inspect
|
@@ -162,20 +123,25 @@ module Hyperclient
|
|
162
123
|
|
163
124
|
private
|
164
125
|
|
165
|
-
# Internal: Delegate the method
|
166
|
-
#
|
167
|
-
# This allows `api.posts` instead of `api.links.posts.embedded`
|
126
|
+
# Internal: Delegate the method further down the API if the resource cannot serve it.
|
168
127
|
def method_missing(method, *args, &block)
|
169
|
-
if
|
170
|
-
|
171
|
-
delegate.send(method, *args, &block)
|
172
|
-
elsif _resource.respond_to?(method.to_s)
|
173
|
-
_resource.send(method, *args, &block)
|
128
|
+
if _resource.respond_to?(method.to_s)
|
129
|
+
_resource.send(method, *args, &block) || delegate_method(method, *args, &block)
|
174
130
|
else
|
175
131
|
super
|
176
132
|
end
|
177
133
|
end
|
178
134
|
|
135
|
+
# Internal: Delegate the method to the API if the resource cannot serve it.
|
136
|
+
#
|
137
|
+
# This allows `api.posts` instead of `api._links.posts.embedded.posts`
|
138
|
+
def delegate_method(method, *args, &block)
|
139
|
+
return unless @key && _resource.respond_to?(@key)
|
140
|
+
@delegate ||= _resource.send(@key)
|
141
|
+
return unless @delegate && @delegate.respond_to?(method.to_s)
|
142
|
+
@delegate.send(method, *args, &block)
|
143
|
+
end
|
144
|
+
|
179
145
|
# Internal: Accessory method to allow the link respond to the
|
180
146
|
# methods that will hit method_missing.
|
181
147
|
def respond_to_missing?(method, _include_private = false)
|
@@ -198,5 +164,14 @@ module Hyperclient
|
|
198
164
|
def _uri_template
|
199
165
|
@uri_template ||= URITemplate.new(@link['href'])
|
200
166
|
end
|
167
|
+
|
168
|
+
def http_method(method, body = nil)
|
169
|
+
@resource = begin
|
170
|
+
response = Futuroscope::Future.new do
|
171
|
+
@entry_point.connection.run_request(method, _url, body, nil)
|
172
|
+
end
|
173
|
+
Resource.new(response.body, @entry_point, response)
|
174
|
+
end
|
175
|
+
end
|
201
176
|
end
|
202
177
|
end
|
@@ -13,8 +13,8 @@ module Hyperclient
|
|
13
13
|
class LinkCollection < Collection
|
14
14
|
# Public: Initializes a LinkCollection.
|
15
15
|
#
|
16
|
-
# collection
|
17
|
-
# curies
|
16
|
+
# collection - The Hash with the links.
|
17
|
+
# curies - The Hash with link curies.
|
18
18
|
# entry_point - The EntryPoint object to inject the configuration.
|
19
19
|
def initialize(collection, curies, entry_point)
|
20
20
|
fail "Invalid response for LinkCollection. The response was: #{collection.inspect}" if collection && !collection.respond_to?(:collect)
|
@@ -33,13 +33,15 @@ module Hyperclient
|
|
33
33
|
|
34
34
|
# Internal: Creates links from the response hash.
|
35
35
|
#
|
36
|
+
# name - A String to identify the link's name.
|
36
37
|
# link_or_links - A Hash or an Array of hashes with the links to build.
|
37
|
-
#
|
38
|
-
#
|
38
|
+
# curies - An Array of Curies for templated links.
|
39
|
+
# entry_point - The EntryPoint object to inject the configuration.
|
39
40
|
#
|
40
|
-
# Returns a Link or an
|
41
|
+
# Returns a Link or an Array of Links when given an Array.
|
41
42
|
def build_link(name, link_or_links, curies, entry_point)
|
42
43
|
return unless link_or_links
|
44
|
+
|
43
45
|
if link_or_links.respond_to?(:to_ary)
|
44
46
|
link_or_links.map do |link|
|
45
47
|
build_link(name, link, curies, entry_point)
|
data/lib/hyperclient/resource.rb
CHANGED
@@ -57,6 +57,18 @@ module Hyperclient
|
|
57
57
|
send(name) if respond_to?(name)
|
58
58
|
end
|
59
59
|
|
60
|
+
def fetch(key, *args)
|
61
|
+
return self[key] if respond_to?(key)
|
62
|
+
|
63
|
+
if args.any?
|
64
|
+
args.first
|
65
|
+
elsif block_given?
|
66
|
+
yield key
|
67
|
+
else
|
68
|
+
fail KeyError
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
60
72
|
private
|
61
73
|
|
62
74
|
# Internal: Returns the self Link of the Resource. Used to handle the HTTP
|
@@ -14,7 +14,7 @@ module Hyperclient
|
|
14
14
|
# Public: Initializes a ResourceCollection.
|
15
15
|
#
|
16
16
|
# collection - The Hash with the embedded resources.
|
17
|
-
# entry_point - The EntryPoint object to inject the
|
17
|
+
# entry_point - The EntryPoint object to inject the configuration.
|
18
18
|
#
|
19
19
|
def initialize(collection, entry_point)
|
20
20
|
@entry_point = entry_point
|
data/lib/hyperclient/version.rb
CHANGED
@@ -117,12 +117,6 @@ module Hyperclient
|
|
117
117
|
end
|
118
118
|
end
|
119
119
|
|
120
|
-
describe '_connection' do
|
121
|
-
it 'returns the entry point connection' do
|
122
|
-
Link.new('key', {}, entry_point)._connection.must_equal entry_point.connection
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
120
|
describe 'get' do
|
127
121
|
it 'sends a GET request with the link url' do
|
128
122
|
link = Link.new('key', { 'href' => '/productions/1' }, entry_point)
|
@@ -185,7 +179,6 @@ module Hyperclient
|
|
185
179
|
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
186
180
|
|
187
181
|
it 'sends a POST request with the link url and params' do
|
188
|
-
|
189
182
|
stub_request(entry_point.connection) do |stub|
|
190
183
|
stub.post('http://api.example.org/productions/1') { [200, {}, nil] }
|
191
184
|
end
|
@@ -194,7 +187,6 @@ module Hyperclient
|
|
194
187
|
end
|
195
188
|
|
196
189
|
it 'defaults params to an empty hash' do
|
197
|
-
|
198
190
|
stub_request(entry_point.connection) do |stub|
|
199
191
|
stub.post('http://api.example.org/productions/1') { [200, {}, nil] }
|
200
192
|
end
|
@@ -207,7 +199,6 @@ module Hyperclient
|
|
207
199
|
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
208
200
|
|
209
201
|
it 'sends a PUT request with the link url and params' do
|
210
|
-
|
211
202
|
stub_request(entry_point.connection) do |stub|
|
212
203
|
stub.put('http://api.example.org/productions/1', '{"foo":"bar"}') { [200, {}, nil] }
|
213
204
|
end
|
@@ -216,7 +207,6 @@ module Hyperclient
|
|
216
207
|
end
|
217
208
|
|
218
209
|
it 'defaults params to an empty hash' do
|
219
|
-
|
220
210
|
stub_request(entry_point.connection) do |stub|
|
221
211
|
stub.put('http://api.example.org/productions/1') { [200, {}, nil] }
|
222
212
|
end
|
@@ -229,7 +219,6 @@ module Hyperclient
|
|
229
219
|
let(:link) { Link.new('key', { 'href' => '/productions/1' }, entry_point) }
|
230
220
|
|
231
221
|
it 'sends a PATCH request with the link url and params' do
|
232
|
-
|
233
222
|
stub_request(entry_point.connection) do |stub|
|
234
223
|
stub.patch('http://api.example.org/productions/1', '{"foo":"bar"}') { [200, {}, nil] }
|
235
224
|
end
|
@@ -278,11 +267,20 @@ module Hyperclient
|
|
278
267
|
resource.foos._embedded.orders.first.id.must_equal 1
|
279
268
|
resource.foos.first.must_equal nil
|
280
269
|
end
|
270
|
+
|
271
|
+
it 'backtracks when navigating links' do
|
272
|
+
resource = Resource.new({ '_links' => { 'next' => { 'href' => '/page2' } } }, entry_point)
|
273
|
+
|
274
|
+
stub_request(entry_point.connection) do |stub|
|
275
|
+
stub.get('http://api.example.org/page2') { [200, {}, { '_links' => { 'next' => { 'href' => 'http://api.example.org/page3' } } }] }
|
276
|
+
end
|
277
|
+
|
278
|
+
resource.next._links.next._url.must_equal 'http://api.example.org/page3'
|
279
|
+
end
|
281
280
|
end
|
282
281
|
|
283
282
|
describe 'resource' do
|
284
283
|
before do
|
285
|
-
|
286
284
|
stub_request(entry_point.connection) do |stub|
|
287
285
|
stub.get('http://myapi.org/orders') { [200, {}, '{"resource": "This is the resource"}'] }
|
288
286
|
end
|
@@ -101,6 +101,44 @@ module Hyperclient
|
|
101
101
|
resource._attributes.expects(:foo).returns('bar')
|
102
102
|
resource['foo'].must_equal 'bar'
|
103
103
|
end
|
104
|
+
|
105
|
+
describe '#fetch' do
|
106
|
+
it 'returns the value for keys that exist' do
|
107
|
+
resource._attributes.expects(:foo).returns('bar')
|
108
|
+
|
109
|
+
resource.fetch('foo').must_equal 'bar'
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'raises an error for missing keys' do
|
113
|
+
proc { resource.fetch('missing key') }.must_raise KeyError
|
114
|
+
end
|
115
|
+
|
116
|
+
describe 'with a default value' do
|
117
|
+
it 'returns the value for keys that exist' do
|
118
|
+
resource._attributes.expects(:foo).returns('bar')
|
119
|
+
resource.fetch('foo', 'default value').must_equal 'bar'
|
120
|
+
end
|
121
|
+
|
122
|
+
it 'returns the default value for missing keys' do
|
123
|
+
resource.fetch('missing key', 'default value').must_equal 'default value'
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
describe 'with a block' do
|
128
|
+
it 'returns the value for keys that exist' do
|
129
|
+
resource._attributes.expects(:foo).returns('bar')
|
130
|
+
resource.fetch('foo') { 'default value' }.must_equal 'bar'
|
131
|
+
end
|
132
|
+
|
133
|
+
it 'returns the value from the block' do
|
134
|
+
resource.fetch('z') { 'go fish!' }.must_equal 'go fish!'
|
135
|
+
end
|
136
|
+
|
137
|
+
it 'returns the value with args from the block' do
|
138
|
+
resource.fetch('z') { |el| "go fish, #{el}" }.must_equal 'go fish, z'
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
104
142
|
end
|
105
143
|
end
|
106
144
|
|
data/test/test_helper.rb
CHANGED
@@ -9,10 +9,8 @@ require 'json'
|
|
9
9
|
require 'pry'
|
10
10
|
|
11
11
|
MiniTest::Unit::TestCase.class_eval do
|
12
|
-
|
13
12
|
def stub_request(conn, adapter_class = Faraday::Adapter::Test, &stubs_block)
|
14
13
|
adapter_handler = conn.builder.handlers.find { |h| h.klass < Faraday::Adapter }
|
15
14
|
conn.builder.swap(adapter_handler, adapter_class, &stubs_block)
|
16
15
|
end
|
17
|
-
|
18
16
|
end
|
metadata
CHANGED
@@ -1,195 +1,195 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hyperclient
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.7.
|
4
|
+
version: 0.7.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Oriol Gual
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: faraday
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '0.8'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0.8'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: futuroscope
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: 0.0.10
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: 0.0.10
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: faraday_middleware
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- - ~>
|
45
|
+
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
47
|
version: '0.9'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- - ~>
|
52
|
+
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '0.9'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: faraday_hal_middleware
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
58
58
|
requirements:
|
59
|
-
- - ~>
|
59
|
+
- - "~>"
|
60
60
|
- !ruby/object:Gem::Version
|
61
61
|
version: 0.0.1
|
62
62
|
type: :runtime
|
63
63
|
prerelease: false
|
64
64
|
version_requirements: !ruby/object:Gem::Requirement
|
65
65
|
requirements:
|
66
|
-
- - ~>
|
66
|
+
- - "~>"
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: 0.0.1
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: uri_template
|
71
71
|
requirement: !ruby/object:Gem::Requirement
|
72
72
|
requirements:
|
73
|
-
- - ~>
|
73
|
+
- - "~>"
|
74
74
|
- !ruby/object:Gem::Version
|
75
75
|
version: '0.5'
|
76
76
|
type: :runtime
|
77
77
|
prerelease: false
|
78
78
|
version_requirements: !ruby/object:Gem::Requirement
|
79
79
|
requirements:
|
80
|
-
- - ~>
|
80
|
+
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0.5'
|
83
83
|
- !ruby/object:Gem::Dependency
|
84
84
|
name: net-http-digest_auth
|
85
85
|
requirement: !ruby/object:Gem::Requirement
|
86
86
|
requirements:
|
87
|
-
- - ~>
|
87
|
+
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
89
|
version: '1.2'
|
90
90
|
type: :runtime
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
|
-
- - ~>
|
94
|
+
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
96
|
version: '1.2'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: faraday-digestauth
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
100
100
|
requirements:
|
101
|
-
- - ~>
|
101
|
+
- - "~>"
|
102
102
|
- !ruby/object:Gem::Version
|
103
103
|
version: '0.2'
|
104
104
|
type: :runtime
|
105
105
|
prerelease: false
|
106
106
|
version_requirements: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- - ~>
|
108
|
+
- - "~>"
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0.2'
|
111
111
|
- !ruby/object:Gem::Dependency
|
112
112
|
name: minitest
|
113
113
|
requirement: !ruby/object:Gem::Requirement
|
114
114
|
requirements:
|
115
|
-
- - ~>
|
115
|
+
- - "~>"
|
116
116
|
- !ruby/object:Gem::Version
|
117
117
|
version: 3.4.0
|
118
118
|
type: :development
|
119
119
|
prerelease: false
|
120
120
|
version_requirements: !ruby/object:Gem::Requirement
|
121
121
|
requirements:
|
122
|
-
- - ~>
|
122
|
+
- - "~>"
|
123
123
|
- !ruby/object:Gem::Version
|
124
124
|
version: 3.4.0
|
125
125
|
- !ruby/object:Gem::Dependency
|
126
126
|
name: turn
|
127
127
|
requirement: !ruby/object:Gem::Requirement
|
128
128
|
requirements:
|
129
|
-
- - ~>
|
129
|
+
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
131
|
version: '0.9'
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
|
-
- - ~>
|
136
|
+
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
138
|
version: '0.9'
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: webmock
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
142
142
|
requirements:
|
143
|
-
- - ~>
|
143
|
+
- - "~>"
|
144
144
|
- !ruby/object:Gem::Version
|
145
145
|
version: '1.8'
|
146
146
|
type: :development
|
147
147
|
prerelease: false
|
148
148
|
version_requirements: !ruby/object:Gem::Requirement
|
149
149
|
requirements:
|
150
|
-
- - ~>
|
150
|
+
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '1.8'
|
153
153
|
- !ruby/object:Gem::Dependency
|
154
154
|
name: mocha
|
155
155
|
requirement: !ruby/object:Gem::Requirement
|
156
156
|
requirements:
|
157
|
-
- - ~>
|
157
|
+
- - "~>"
|
158
158
|
- !ruby/object:Gem::Version
|
159
159
|
version: '0.13'
|
160
160
|
type: :development
|
161
161
|
prerelease: false
|
162
162
|
version_requirements: !ruby/object:Gem::Requirement
|
163
163
|
requirements:
|
164
|
-
- - ~>
|
164
|
+
- - "~>"
|
165
165
|
- !ruby/object:Gem::Version
|
166
166
|
version: '0.13'
|
167
167
|
- !ruby/object:Gem::Dependency
|
168
168
|
name: rack-test
|
169
169
|
requirement: !ruby/object:Gem::Requirement
|
170
170
|
requirements:
|
171
|
-
- - ~>
|
171
|
+
- - "~>"
|
172
172
|
- !ruby/object:Gem::Version
|
173
173
|
version: '0.6'
|
174
174
|
type: :development
|
175
175
|
prerelease: false
|
176
176
|
version_requirements: !ruby/object:Gem::Requirement
|
177
177
|
requirements:
|
178
|
-
- - ~>
|
178
|
+
- - "~>"
|
179
179
|
- !ruby/object:Gem::Version
|
180
180
|
version: '0.6'
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: spinach
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
184
184
|
requirements:
|
185
|
-
- -
|
185
|
+
- - ">="
|
186
186
|
- !ruby/object:Gem::Version
|
187
187
|
version: '0'
|
188
188
|
type: :development
|
189
189
|
prerelease: false
|
190
190
|
version_requirements: !ruby/object:Gem::Requirement
|
191
191
|
requirements:
|
192
|
-
- -
|
192
|
+
- - ">="
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '0'
|
195
195
|
description: HyperClient is a Ruby Hypermedia API client.
|
@@ -199,17 +199,18 @@ executables: []
|
|
199
199
|
extensions: []
|
200
200
|
extra_rdoc_files: []
|
201
201
|
files:
|
202
|
-
- .gitignore
|
203
|
-
- .rubocop.yml
|
204
|
-
- .rubocop_todo.yml
|
205
|
-
- .travis.yml
|
206
|
-
- .yardopts
|
202
|
+
- ".gitignore"
|
203
|
+
- ".rubocop.yml"
|
204
|
+
- ".rubocop_todo.yml"
|
205
|
+
- ".travis.yml"
|
206
|
+
- ".yardopts"
|
207
207
|
- CHANGELOG.md
|
208
208
|
- CONTRIBUTING.md
|
209
209
|
- Gemfile
|
210
210
|
- Guardfile
|
211
211
|
- LICENSE
|
212
212
|
- README.md
|
213
|
+
- RELEASING.md
|
213
214
|
- Rakefile
|
214
215
|
- UPGRADING.md
|
215
216
|
- examples/splines_api.rb
|
@@ -255,17 +256,17 @@ require_paths:
|
|
255
256
|
- lib
|
256
257
|
required_ruby_version: !ruby/object:Gem::Requirement
|
257
258
|
requirements:
|
258
|
-
- -
|
259
|
+
- - ">="
|
259
260
|
- !ruby/object:Gem::Version
|
260
261
|
version: '0'
|
261
262
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
262
263
|
requirements:
|
263
|
-
- -
|
264
|
+
- - ">="
|
264
265
|
- !ruby/object:Gem::Version
|
265
266
|
version: '0'
|
266
267
|
requirements: []
|
267
268
|
rubyforge_project:
|
268
|
-
rubygems_version: 2.
|
269
|
+
rubygems_version: 2.2.2
|
269
270
|
signing_key:
|
270
271
|
specification_version: 4
|
271
272
|
summary: ''
|