Skip to content

Commit

Permalink
Merge pull request #87 from dblock/eager-navigation-fix
Browse files Browse the repository at this point in the history
Fix: eager delegation causes link skipping.
  • Loading branch information
dblock committed Jun 5, 2015
2 parents b4026dc + c25e5d3 commit 21552df
Show file tree
Hide file tree
Showing 9 changed files with 66 additions and 13 deletions.
8 changes: 4 additions & 4 deletions .rubocop_todo.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
# This configuration was generated by `rubocop --auto-gen-config`
# on 2014-10-17 09:13:36 -0400 using RuboCop version 0.26.1.
# on 2015-06-05 09:21:59 -0400 using RuboCop version 0.27.1.
# The point is for the user to remove these configuration records
# one by one as the offenses are removed from the code base.
# Note that changes in the inspected code, or installation of new
Expand All @@ -8,12 +8,12 @@
# Offense count: 1
# Configuration parameters: CountComments.
Metrics/ClassLength:
Max: 129
Max: 103

# Offense count: 72
# Offense count: 78
# Configuration parameters: AllowURI, URISchemes.
Metrics/LineLength:
Max: 140
Max: 142

# Offense count: 3
# Configuration parameters: CountComments.
Expand Down
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
### 0.7.1 (Next)

* [#87](https://github.com/codegram/hyperclient/pull/87): Fix: eager delegation causes link skipping - [@dblock](https://github.com/dblock).
* Your contribution here.

### 0.7.0 (February 23, 2015)
Expand Down
5 changes: 5 additions & 0 deletions features/api_navigation.feature
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,8 @@ Feature: API navigation
Given I connect to the API
When I load a single post
Then I should also be able to access it's embedded comments

Scenario: Navigation links
When I connect to the API
Then I should be able to navigate to next page
Then I should be able to navigate to next page without links
8 changes: 8 additions & 0 deletions features/steps/api_navigation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -30,4 +30,12 @@ class Spinach::Features::ApiNavigation < Spinach::FeatureSteps
comment = @post._embedded.comments.first
comment._attributes.title.wont_equal nil
end

step 'I should be able to navigate to next page' do
assert_equal '/posts_of_page2', api._links.next._links.posts._url
end

step 'I should be able to navigate to next page without links' do
assert_equal '/posts_of_page2', api.next.posts._url
end
end
2 changes: 2 additions & 0 deletions features/support/api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@ module API
stub_request(:any, %r{api.example.org*}).to_return(body: root_response, headers: { 'Content-Type' => 'application/hal+json' })
stub_request(:get, 'api.example.org/posts').to_return(body: posts_response, headers: { 'Content-Type' => 'application/hal+json' })
stub_request(:get, 'api.example.org/posts/1').to_return(body: post_response, headers: { 'Content-Type' => 'application/hal+json' })
stub_request(:get, 'api.example.org/page2').to_return(body: page2_response, headers: { 'Content-Type' => 'application/hal+json' })
stub_request(:get, 'api.example.org/page3').to_return(body: page3_response, headers: { 'Content-Type' => 'application/hal+json' })
end

def api
Expand Down
23 changes: 22 additions & 1 deletion features/support/fixtures.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ def root_response
"self": { "href": "/" },
"posts": { "href": "/posts" },
"search": { "href": "/search{?q}", "templated": true },
"api:authors": { "href": "/authors" }
"api:authors": { "href": "/authors" },
"next": { "href": "/page2" }
}
}'
end
Expand Down Expand Up @@ -39,5 +40,25 @@ def post_response
}
}'
end

def page2_response
'{
"_links": {
"self": { "href": "/page2" },
"posts": { "href": "/posts_of_page2" },
"next": { "href": "/page3" }
}
}'
end

def page3_response
'{
"_links": {
"self": { "href": "/page3" },
"posts": { "href": "/posts_of_page3" },
"api:authors": { "href": "/authors" }
}
}'
end
end
end
1 change: 1 addition & 0 deletions lib/hyperclient/entry_point.rb
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ def message
#
class EntryPoint < Link
extend Forwardable

# Public: Delegates common methods to be used with the Faraday connection.
def_delegators :connection, :basic_auth, :digest_auth, :token_auth, :headers, :headers=, :params, :params=

Expand Down
21 changes: 13 additions & 8 deletions lib/hyperclient/link.rb
Original file line number Diff line number Diff line change
Expand Up @@ -123,20 +123,25 @@ def to_s

private

# Internal: Delegate the method to the API if it exists.
#
# This allows `api.posts` instead of `api.links.posts.embedded`
# Internal: Delegate the method further down the API if the resource cannot serve it.
def method_missing(method, *args, &block)
if @key && _resource.respond_to?(@key) && (delegate = _resource.send(@key)) && delegate.respond_to?(method.to_s)
# named.named becomes named
delegate.send(method, *args, &block)
elsif _resource.respond_to?(method.to_s)
_resource.send(method, *args, &block)
if _resource.respond_to?(method.to_s)
_resource.send(method, *args, &block) || delegate_method(method, *args, &block)
else
super
end
end

# Internal: Delegate the method to the API if the resource cannot serve it.
#
# This allows `api.posts` instead of `api._links.posts.embedded.posts`
def delegate_method(method, *args, &block)
return unless @key && _resource.respond_to?(@key)
@delegate ||= _resource.send(@key)
return unless @delegate && @delegate.respond_to?(method.to_s)
@delegate.send(method, *args, &block)
end

# Internal: Accessory method to allow the link respond to the
# methods that will hit method_missing.
def respond_to_missing?(method, _include_private = false)
Expand Down
10 changes: 10 additions & 0 deletions test/hyperclient/link_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,16 @@ module Hyperclient
resource.foos._embedded.orders.first.id.must_equal 1
resource.foos.first.must_equal nil
end

it 'backtracks when navigating links' do
resource = Resource.new({ '_links' => { 'next' => { 'href' => '/page2' } } }, entry_point)

stub_request(entry_point.connection) do |stub|
stub.get('http://api.example.org/page2') { [200, {}, { '_links' => { 'next' => { 'href' => 'http://api.example.org/page3' } } }] }
end

resource.next._links.next._url.must_equal 'http://api.example.org/page3'
end
end

describe 'resource' do
Expand Down

0 comments on commit 21552df

Please sign in to comment.