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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0fef7b6957e239321aff88f157c57b669cdaa388
4
- data.tar.gz: 5e1fc8350dbd97205743d716146a4b148202034e
3
+ metadata.gz: c935e08d5410e72969d8b83c213ef56d7ae5236e
4
+ data.tar.gz: a250cb39f383c471f637cec668ce683c0310e808
5
5
  SHA512:
6
- metadata.gz: 8f005fb328d44e78d11d443184361a8709422977c10a574ef98d8a21694acb72930058ca05075d06baa5290be17502060f5efe09b9d604264f2d9f8a26ec9171
7
- data.tar.gz: 7c587f7c4abfc82e571b3dc8a3b571521d13c077a84d12aca7497777b894630b648adf87e296e2f3f2d4806c3ed31a91152d8ced262f0dc9305a8f6814485da0
6
+ metadata.gz: 10c73a4a2d78e9947a69719e831d1dccd467fecf6006a21fba2561cd23e74e5c7b8604398dc75477a76a5327cf0dfc31e018424cf41c81067bb057854dbd5960
7
+ data.tar.gz: c4eba8f9223ccc8ffa166dc731e32ac842d8230f4e9ee507b9f175503ee935a235e5820d823a24378239080de2d8c74bfb2ee29a25949a841d44d78d5a4ff747
data/.rubocop_todo.yml CHANGED
@@ -1,5 +1,6 @@
1
- # This configuration was generated by `rubocop --auto-gen-config`
2
- # on 2014-10-17 09:13:36 -0400 using RuboCop version 0.26.1.
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: 129
12
+ Max: 103
12
13
 
13
- # Offense count: 72
14
+ # Offense count: 80
14
15
  # Configuration parameters: AllowURI, URISchemes.
15
16
  Metrics/LineLength:
16
- Max: 140
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
- Enabled: false
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
- Enabled: false
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
- Enabled: false
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
- Enabled: false
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
- Enabled: false
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: 5
45
- # Configuration parameters: MaxSlashes.
73
+ # Offense count: 1
74
+ # Cop supports --auto-correct.
75
+ # Configuration parameters: EnforcedStyle, SupportedStyles, AllowInnerSlashes.
46
76
  Style/RegexpLiteral:
47
- Enabled: false
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
@@ -13,4 +13,4 @@ gem 'redcarpet'
13
13
  gem 'yard', '~> 0.8'
14
14
  gem 'yard-tomdoc'
15
15
  gem 'simplecov', require: false
16
- gem 'rubocop', '~> 0.27.0', require: false
16
+ gem 'rubocop', '~> 0.33.0', require: false
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
@@ -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 wrapp a collection of elements and provide
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
- def include?(obj)
29
- @collection.include?(obj)
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 hash.
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) do
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
@@ -7,8 +7,8 @@ module Hyperclient
7
7
  class Curie
8
8
  # Public: Initializes a new Curie.
9
9
  #
10
- # curie - The String with the URI of the curie.
11
- # entry_point - The EntryPoint object to inject the cofnigutation.
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 - A Hash containing additional options.
47
- #
48
- # default - Set to true to reuse default Faraday connection options.
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 |conn|
127
- conn.use Faraday::Response::RaiseError
128
- conn.use FaradayMiddleware::FollowRedirects
129
- conn.request :hal_json
130
- conn.response :hal_json, content_type: /\bjson$/
131
- conn.adapter :net_http
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
 
@@ -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 cofnigutation.
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
- def _connection
98
- @entry_point.connection
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
- @resource = begin
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
- @resource = begin
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
- @resource = begin
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
- @resource = begin
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
- @resource = begin
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
- @resource = begin
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 to the API if it exists.
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 @key && _resource.respond_to?(@key) && (delegate = _resource.send(@key)) && delegate.respond_to?(method.to_s)
170
- # named.named becomes named
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 - The Hash with the links.
17
- # curies - Link 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
- # entry_point - The EntryPoint object to inject the configuration.
38
- # curies - Optional curies for templated links.
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 array of Links when given an Array.
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)
@@ -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 cofnigutation.
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
@@ -1,3 +1,3 @@
1
1
  module Hyperclient
2
- VERSION = '0.7.0'
2
+ VERSION = '0.7.1'
3
3
  end
@@ -70,6 +70,5 @@ module Hyperclient
70
70
  end
71
71
  end
72
72
  end
73
-
74
73
  end
75
74
  end
@@ -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.0
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-02-23 00:00:00.000000000 Z
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.4.5
269
+ rubygems_version: 2.2.2
269
270
  signing_key:
270
271
  specification_version: 4
271
272
  summary: ''