hyperclient 0.4.0 → 0.5.0

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.rubocop.yml +2 -0
  4. data/.rubocop_todo.yml +55 -0
  5. data/.travis.yml +2 -0
  6. data/CHANGELOG.md +33 -10
  7. data/CONTRIBUTING.md +117 -0
  8. data/Gemfile +2 -1
  9. data/Guardfile +6 -6
  10. data/LICENSE +2 -2
  11. data/README.md +138 -0
  12. data/Rakefile +5 -3
  13. data/UPGRADING.md +37 -0
  14. data/examples/splines_api.rb +22 -0
  15. data/features/steps/api_navigation.rb +8 -8
  16. data/features/steps/default_config.rb +6 -6
  17. data/features/support/api.rb +4 -4
  18. data/features/support/fixtures.rb +1 -1
  19. data/hyperclient.gemspec +9 -8
  20. data/lib/faraday/connection.rb +2 -2
  21. data/lib/hyperclient.rb +1 -1
  22. data/lib/hyperclient/attributes.rb +1 -1
  23. data/lib/hyperclient/collection.rb +3 -3
  24. data/lib/hyperclient/curie.rb +49 -0
  25. data/lib/hyperclient/entry_point.rb +6 -4
  26. data/lib/hyperclient/link.rb +70 -58
  27. data/lib/hyperclient/link_collection.rb +36 -11
  28. data/lib/hyperclient/resource.rb +49 -18
  29. data/lib/hyperclient/resource_collection.rb +2 -1
  30. data/lib/hyperclient/version.rb +1 -1
  31. data/test/fixtures/element.json +12 -1
  32. data/test/hyperclient/attributes_test.rb +2 -2
  33. data/test/hyperclient/collection_test.rb +6 -7
  34. data/test/hyperclient/curie_test.rb +34 -0
  35. data/test/hyperclient/entry_point_test.rb +3 -2
  36. data/test/hyperclient/link_collection_test.rb +26 -5
  37. data/test/hyperclient/link_test.rb +111 -86
  38. data/test/hyperclient/resource_collection_test.rb +2 -2
  39. data/test/hyperclient/resource_test.rb +67 -30
  40. data/test/test_helper.rb +2 -2
  41. metadata +54 -39
  42. data/Gemfile.lock +0 -112
  43. data/MIT-LICENSE +0 -20
  44. data/Readme.md +0 -180
  45. data/examples/cyberscore.rb +0 -76
  46. data/examples/hal_shop.rb +0 -53
  47. data/lib/faraday/request/digest_authentication.rb +0 -85
  48. data/test/faraday/digest_authentication_test.rb +0 -41
data/UPGRADING.md ADDED
@@ -0,0 +1,37 @@
1
+ Upgrading Hyperclient
2
+ =====================
3
+
4
+ ### Upgrading to >= 0.5.0
5
+
6
+ #### Remove Navigational Elements
7
+
8
+ You can, but no longer need to invoke `links`, `embedded`, `expand`, `attributes` or `resource` in most cases. Simply remove them. Navigational structures like `key.embedded.key` can also be collapsed.
9
+
10
+ Here're a few examples:
11
+
12
+ Instead Of | Write This
13
+ ----------------------------------------------- | -----------------------
14
+ `api.links.widgets` | `api.widgets`
15
+ `api.links.widgets.embedded.widgets.first` | `api.widgets.first`
16
+ `api.links.widgets.embedded.comments` | `api.widgets.comments`
17
+ `api.links.widget.expand(id: 3)` | `api.widget(id: 3)`
18
+ `api.links.widget.expand(id: 3).resource.id` | `api.widget(id: 3).id`
19
+
20
+ If you prefer to specify the complete HAL navigational structure, you must rename the methods to their new underscore equivalents. See below.
21
+
22
+ #### Change Naviational Elements and HTTP Verbs to Underscore Versions
23
+
24
+ Navigational methods and HTTP verbs have been renamed to their underscore versions and are otherwise treated as attributes.
25
+
26
+ Instead Of | Write This
27
+ ------------------------------------------------------- | ----------------------------------------------------------------
28
+ `api.links` | `api._links`
29
+ `api.links.widgets.embedded.widgets.first` | `api._links.widgets._embedded.first`
30
+ `api.links.widget.expand(id: 3).resource` | `api._links.widget._expand(id: 3)._resource`
31
+ `api.get` | `api._get`
32
+ `api.links.widgets.widget(id: 3).delete` | `api._links.widget._expand(id: 3)._delete`
33
+ `api.links.widgets.post(name: 'a widget')` | `api._links.widgets._post(name: 'a widget')
34
+ `api.links.widget.expand(id: 3).put(name: 'updated`) | `api._links.widget._expand(id: 3)._put(name: 'updated')`
35
+
36
+ For more information see [#63](https://github.com/codegram/hyperclient/pull/63).
37
+
@@ -0,0 +1,22 @@
1
+ require 'hyperclient'
2
+
3
+ api = Hyperclient.new('https://grape-with-roar.herokuapp.com/api')
4
+
5
+ api.splines.each do |spline|
6
+ puts "#{spline.uuid}"
7
+ puts " reticulated: #{spline.reticulated ? 'yes' : 'no'}"
8
+ puts " thumbnail: #{spline['images:thumbnail']}"
9
+ end
10
+
11
+ api._links.splines._embedded.splines.each do |_spline|
12
+ # ... equivalent to the above
13
+ end
14
+
15
+ puts '*' * 10
16
+
17
+ spline = api.spline(uuid: 'random-uuid')
18
+ puts "Spline #{spline.uuid} is #{spline.reticulated ? 'reticulated' : 'not reticulated'}."
19
+
20
+ # puts api._links.spline._expand(uuid: 'uuid')._resource._attributes.reticulated
21
+
22
+ # spline.to_h
@@ -2,15 +2,15 @@ class Spinach::Features::ApiNavigation < Spinach::FeatureSteps
2
2
  include API
3
3
 
4
4
  step 'I should be able to navigate to posts and authors' do
5
- api.links.posts.resource
6
- api.links['api:authors'].resource
5
+ api._links.posts._resource
6
+ api._links['api:authors']._resource
7
7
 
8
8
  assert_requested :get, 'http://api.example.org/posts'
9
9
  assert_requested :get, 'http://api.example.org/authors'
10
10
  end
11
11
 
12
12
  step 'I search for a post with a templated link' do
13
- api.links.search.expand(q: 'something').resource
13
+ api._links.search._expand(q: 'something')._resource
14
14
  end
15
15
 
16
16
  step 'the API should receive the request with all the params' do
@@ -18,16 +18,16 @@ class Spinach::Features::ApiNavigation < Spinach::FeatureSteps
18
18
  end
19
19
 
20
20
  step 'I load a single post' do
21
- @post = api.links.posts.links.last_post
21
+ @post = api._links.posts._links.last_post
22
22
  end
23
23
 
24
24
  step 'I should be able to access it\'s title and body' do
25
- @post.attributes.title.wont_equal nil
26
- @post.attributes.body.wont_equal nil
25
+ @post._attributes.title.wont_equal nil
26
+ @post._attributes.body.wont_equal nil
27
27
  end
28
28
 
29
29
  step 'I should also be able to access it\'s embedded comments' do
30
- comment = @post.embedded.comments.first
31
- comment.attributes.title.wont_equal nil
30
+ comment = @post._embedded.comments.first
31
+ comment._attributes.title.wont_equal nil
32
32
  end
33
33
  end
@@ -6,12 +6,12 @@ class Spinach::Features::DefaultConfig < Spinach::FeatureSteps
6
6
  end
7
7
 
8
8
  step 'the request should have been sent with the correct JSON headers' do
9
- assert_requested :get, 'api.example.org', headers: {'Content-Type' => 'application/json', 'Accept' => 'application/json'}
9
+ assert_requested :get, 'api.example.org', headers: { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
10
10
  end
11
11
 
12
12
  step 'I send some data to the API' do
13
- stub_request(:post, "http://api.example.org/posts")
14
- api.links.posts.post({title: 'My first blog post'})
13
+ stub_request(:post, 'http://api.example.org/posts')
14
+ assert_equal 200, api._links.posts._post(title: 'My first blog post').status
15
15
  end
16
16
 
17
17
  step 'it should have been encoded as JSON' do
@@ -19,11 +19,11 @@ class Spinach::Features::DefaultConfig < Spinach::FeatureSteps
19
19
  end
20
20
 
21
21
  step 'I get some data from the API' do
22
- @posts = api.links.posts
22
+ @posts = api._links.posts
23
23
  end
24
24
 
25
25
  step 'it should have been parsed as JSON' do
26
- @posts.attributes.total_posts.to_i.must_equal 9
27
- @posts.attributes['total_posts'].to_i.must_equal 9
26
+ @posts._attributes.total_posts.to_i.must_equal 9
27
+ @posts._attributes['total_posts'].to_i.must_equal 9
28
28
  end
29
29
  end
@@ -5,9 +5,9 @@ module API
5
5
  include Spinach::Fixtures
6
6
 
7
7
  before do
8
- stub_request(:any, %r{api.example.org*}).to_return(body: root_response, headers:{'Content-Type' => 'application/json'})
9
- stub_request(:get, 'api.example.org/posts').to_return(body: posts_response, headers: {'Content-Type' => 'application/json'})
10
- stub_request(:get, 'api.example.org/posts/1').to_return(body: post_response, headers: {'Content-Type' => 'application/json'})
8
+ stub_request(:any, %r{api.example.org*}).to_return(body: root_response, headers: { 'Content-Type' => 'application/json' })
9
+ stub_request(:get, 'api.example.org/posts').to_return(body: posts_response, headers: { 'Content-Type' => 'application/json' })
10
+ stub_request(:get, 'api.example.org/posts/1').to_return(body: post_response, headers: { 'Content-Type' => 'application/json' })
11
11
  end
12
12
 
13
13
  def api
@@ -15,7 +15,7 @@ module API
15
15
  end
16
16
 
17
17
  step 'I connect to the API' do
18
- api.links
18
+ api._links
19
19
  end
20
20
 
21
21
  after do
@@ -34,7 +34,7 @@ module Spinach
34
34
  "comments": [
35
35
  {
36
36
  "title": "Some comment"
37
- }
37
+ }
38
38
  ]
39
39
  }
40
40
  }'
data/hyperclient.gemspec CHANGED
@@ -2,16 +2,16 @@
2
2
  require File.expand_path('../lib/hyperclient/version', __FILE__)
3
3
 
4
4
  Gem::Specification.new do |gem|
5
- gem.authors = ["Oriol Gual"]
6
- gem.email = ["oriol.gual@gmail.com"]
7
- gem.description = %q{HyperClient is a Ruby Hypermedia API client.}
8
- gem.summary = %q{}
9
- gem.homepage = "http://codegram.github.com/hyperclient/"
10
- gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
5
+ gem.authors = ['Oriol Gual']
6
+ gem.email = ['oriol.gual@gmail.com']
7
+ gem.description = 'HyperClient is a Ruby Hypermedia API client.'
8
+ gem.summary = ''
9
+ gem.homepage = 'http://codegram.github.com/hyperclient/'
10
+ gem.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) }
11
11
  gem.files = `git ls-files`.split("\n")
12
12
  gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
13
- gem.name = "hyperclient"
14
- gem.require_paths = ["lib"]
13
+ gem.name = 'hyperclient'
14
+ gem.require_paths = ['lib']
15
15
  gem.version = Hyperclient::VERSION
16
16
 
17
17
  gem.add_dependency 'faraday', '~> 0.8'
@@ -19,6 +19,7 @@ Gem::Specification.new do |gem|
19
19
  gem.add_dependency 'faraday_middleware', '~> 0.9'
20
20
  gem.add_dependency 'uri_template', '~> 0.5'
21
21
  gem.add_dependency 'net-http-digest_auth', '~> 1.2'
22
+ gem.add_dependency 'faraday-digestauth', '~> 0.2'
22
23
 
23
24
  gem.add_development_dependency 'minitest', '~> 3.4.0'
24
25
  gem.add_development_dependency 'turn', '~> 0.9'
@@ -1,5 +1,5 @@
1
1
  require 'faraday'
2
- require_relative 'request/digest_authentication'
2
+ require 'faraday/digestauth'
3
3
 
4
4
  module Faraday
5
5
  # Reopen Faraday::Connection to add a helper to set the digest auth data.
@@ -11,7 +11,7 @@ module Faraday
11
11
  # password - A String with the password.
12
12
  #
13
13
  def digest_auth(user, password)
14
- self.builder.insert(0, Faraday::Request::DigestAuth, user, password)
14
+ builder.insert(0, Faraday::Request::DigestAuth, user, password)
15
15
  end
16
16
  end
17
17
  end
data/lib/hyperclient.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  require 'hyperclient/entry_point'
2
- require "hyperclient/version"
2
+ require 'hyperclient/version'
3
3
 
4
4
  # Public: Hyperclient namespace.
5
5
  #
@@ -17,7 +17,7 @@ module Hyperclient
17
17
  #
18
18
  def initialize(representation)
19
19
  @collection = if representation.is_a?(Hash)
20
- representation.delete_if {|key, value| RESERVED_PROPERTIES.any? {|p| p.match(key) } }
20
+ representation.delete_if { |key, _value| RESERVED_PROPERTIES.any? { |p| p.match(key) } }
21
21
  else
22
22
  representation
23
23
  end
@@ -69,15 +69,15 @@ module Hyperclient
69
69
  # `collection['name']`
70
70
  #
71
71
  # Returns an Object.
72
- def method_missing(method_name, *args, &block)
72
+ def method_missing(method_name, *_args, &_block)
73
73
  @collection.fetch(method_name.to_s) do
74
- raise "Could not find `#{method_name.to_s}` in #{self.class.name}"
74
+ fail "Could not find `#{method_name}` in #{self.class.name}"
75
75
  end
76
76
  end
77
77
 
78
78
  # Internal: Accessory method to allow the collection respond to the
79
79
  # methods that will hit method_missing.
80
- def respond_to_missing?(method_name, include_private = false)
80
+ def respond_to_missing?(method_name, _include_private = false)
81
81
  @collection.include?(method_name.to_s)
82
82
  end
83
83
  end
@@ -0,0 +1,49 @@
1
+ require 'hyperclient/resource'
2
+
3
+ module Hyperclient
4
+ # Internal: Curies are named tokens that you can define in the document and use
5
+ # to express curie relation URIs in a friendlier, more compact fashion.
6
+ #
7
+ class Curie
8
+ # Public: Initializes a new Curie.
9
+ #
10
+ # curie - The String with the URI of the curie.
11
+ # entry_point - The EntryPoint object to inject the cofnigutation.
12
+ def initialize(curie_hash, entry_point)
13
+ @curie_hash = curie_hash
14
+ @entry_point = entry_point
15
+ end
16
+
17
+ # Public: Indicates if the curie is an URITemplate or a regular URI.
18
+ #
19
+ # Returns true if it is templated.
20
+ # Returns false if it not templated.
21
+ def templated?
22
+ !!@curie_hash['templated']
23
+ end
24
+
25
+ # Public: Returns the name property of the Curie
26
+ def name
27
+ @curie_hash['name']
28
+ end
29
+
30
+ # Public: Returns the href property of the Curie
31
+ def href
32
+ @curie_hash['href']
33
+ end
34
+
35
+ def inspect
36
+ "#<#{self.class.name} #{@curie_hash}>"
37
+ end
38
+
39
+ # Public: Expands the Curie when is templated with the given variables.
40
+ #
41
+ # rel - The rel to expand.
42
+ #
43
+ # Returns a new expanded url.
44
+ def expand(rel)
45
+ return rel unless rel && templated?
46
+ href.gsub('{rel}', rel) if href
47
+ end
48
+ end
49
+ end
@@ -19,7 +19,7 @@ module Hyperclient
19
19
  #
20
20
  # url - A String with the entry point of your API.
21
21
  def initialize(url)
22
- @link = {'href' => url}
22
+ @link = { 'href' => url }
23
23
  @entry_point = self
24
24
  end
25
25
 
@@ -27,10 +27,11 @@ module Hyperclient
27
27
  #
28
28
  # Returns a Faraday::Connection.
29
29
  def connection
30
- @connection ||= Faraday.new(url, {headers: default_headers}, &default_faraday_block)
30
+ @connection ||= Faraday.new(_url, { headers: default_headers }, &default_faraday_block)
31
31
  end
32
32
 
33
33
  private
34
+
34
35
  # Internal: Returns a block to initialize the Faraday connection. The
35
36
  # default block includes a middleware to encode requests as JSON, a
36
37
  # response middleware to parse JSON responses and sets the adapter as
@@ -42,7 +43,8 @@ module Hyperclient
42
43
  # Returns a block.
43
44
  def default_faraday_block
44
45
  lambda do |faraday|
45
- faraday.request :json
46
+ faraday.use FaradayMiddleware::FollowRedirects
47
+ faraday.request :json
46
48
  faraday.response :json, content_type: /\bjson$/
47
49
  faraday.adapter :net_http
48
50
  end
@@ -53,7 +55,7 @@ module Hyperclient
53
55
  #
54
56
  # Returns a Hash.
55
57
  def default_headers
56
- {'Content-Type' => 'application/json', 'Accept' => 'application/json'}
58
+ { 'Content-Type' => 'application/json', 'Accept' => 'application/json' }
57
59
  end
58
60
  end
59
61
  end
@@ -3,16 +3,18 @@ require 'uri_template'
3
3
  require 'futuroscope'
4
4
 
5
5
  module Hyperclient
6
- # Internal: The Link is used to let a Resource interact with the API.
6
+ # Internal: The Link is used to let a Resource interact with the API.
7
7
  #
8
8
  class Link
9
9
  # Public: Initializes a new Link.
10
10
  #
11
+ # key - The key or name of the link.
11
12
  # link - The String with the URI of the link.
12
13
  # entry_point - The EntryPoint object to inject the cofnigutation.
13
14
  # uri_variables - The optional Hash with the variables to expand the link
14
15
  # if it is templated.
15
- def initialize(link, entry_point, uri_variables = nil)
16
+ def initialize(key, link, entry_point, uri_variables = nil)
17
+ @key = key
16
18
  @link = link
17
19
  @entry_point = entry_point
18
20
  @uri_variables = uri_variables
@@ -22,7 +24,7 @@ module Hyperclient
22
24
  #
23
25
  # Returns true if it is templated.
24
26
  # Returns false if it not templated.
25
- def templated?
27
+ def _templated?
26
28
  !!@link['templated']
27
29
  end
28
30
 
@@ -31,62 +33,62 @@ module Hyperclient
31
33
  # uri_variables - The Hash with the variables to expand the URITemplate.
32
34
  #
33
35
  # Returns a new Link with the expanded variables.
34
- def expand(uri_variables)
35
- self.class.new(@link, @entry_point, uri_variables)
36
+ def _expand(uri_variables)
37
+ self.class.new(@key, @link, @entry_point, uri_variables)
36
38
  end
37
39
 
38
40
  # Public: Returns the url of the Link.
39
41
  #
40
42
  # Raises MissingURITemplateVariables if the Link is templated but there are
41
43
  # no uri variables to expand it.
42
- def url
43
- return @link['href'] unless templated?
44
- raise MissingURITemplateVariablesException if @uri_variables == nil
44
+ def _url
45
+ return @link['href'] unless _templated?
46
+ fail MissingURITemplateVariablesException if @uri_variables.nil?
45
47
 
46
- @url ||= uri_template.expand(@uri_variables)
48
+ @url ||= _uri_template.expand(@uri_variables)
47
49
  end
48
50
 
49
51
  # Public: Returns an array of variables from the URITemplate.
50
52
  #
51
53
  # Returns an empty array for regular URIs.
52
- def variables
53
- uri_template.variables
54
+ def _variables
55
+ _uri_template.variables
54
56
  end
55
57
 
56
58
  # Public: Returns the type property of the Link
57
- def type
59
+ def _type
58
60
  @link['type']
59
61
  end
60
62
 
61
63
  # Public: Returns the name property of the Link
62
- def name
64
+ def _name
63
65
  @link['name']
64
66
  end
65
67
 
66
68
  # Public: Returns the deprecation property of the Link
67
- def deprecation
69
+ def _deprecation
68
70
  @link['deprecation']
69
71
  end
70
72
 
71
73
  # Public: Returns the profile property of the Link
72
- def profile
74
+ def _profile
73
75
  @link['profile']
74
76
  end
75
77
 
76
78
  # Public: Returns the title property of the Link
77
- def title
79
+ def _title
78
80
  @link['title']
79
81
  end
80
82
 
81
83
  # Public: Returns the hreflang property of the Link
82
- def hreflang
84
+ def _hreflang
83
85
  @link['hreflang']
84
86
  end
85
87
 
86
88
  # Public: Returns the Resource which the Link is pointing to.
87
- def resource
89
+ def _resource
88
90
  @resource ||= begin
89
- response = get
91
+ response = _get
90
92
 
91
93
  if response.success?
92
94
  Resource.new(response.body, @entry_point, response)
@@ -96,64 +98,71 @@ module Hyperclient
96
98
  end
97
99
  end
98
100
 
99
- def connection
101
+ def _connection
100
102
  @entry_point.connection
101
103
  end
102
104
 
103
- def get
104
- Futuroscope::Future.new{
105
- connection.get(url)
106
- }
105
+ def _get
106
+ Futuroscope::Future.new do
107
+ _connection.get(_url)
108
+ end
107
109
  end
108
110
 
109
- def options
110
- Futuroscope::Future.new{
111
- connection.run_request(:options, url, nil, nil)
112
- }
111
+ def _options
112
+ Futuroscope::Future.new do
113
+ _connection.run_request(:options, _url, nil, nil)
114
+ end
113
115
  end
114
116
 
115
- def head
116
- Futuroscope::Future.new{
117
- connection.head(url)
118
- }
117
+ def _head
118
+ Futuroscope::Future.new do
119
+ _connection.head(_url)
120
+ end
119
121
  end
120
122
 
121
- def delete
122
- Futuroscope::Future.new{
123
- connection.delete(url)
124
- }
123
+ def _delete
124
+ Futuroscope::Future.new do
125
+ _connection.delete(_url)
126
+ end
125
127
  end
126
128
 
127
- def post(params = {})
128
- Futuroscope::Future.new{
129
- connection.post(url, params)
130
- }
129
+ def _post(params = {})
130
+ Futuroscope::Future.new do
131
+ _connection.post(_url, params)
132
+ end
131
133
  end
132
134
 
133
- def put(params = {})
134
- Futuroscope::Future.new{
135
- connection.put(url, params)
136
- }
135
+ def _put(params = {})
136
+ Futuroscope::Future.new do
137
+ _connection.put(_url, params)
138
+ end
137
139
  end
138
140
 
139
- def patch(params = {})
140
- Futuroscope::Future.new{
141
- connection.patch(url, params)
142
- }
141
+ def _patch(params = {})
142
+ Futuroscope::Future.new do
143
+ _connection.patch(_url, params)
144
+ end
143
145
  end
144
146
 
145
147
  def inspect
146
- "#<#{self.class.name} #{@link}>"
148
+ "#<#{self.class.name}(#{@key}) #{@link}>"
149
+ end
150
+
151
+ def to_s
152
+ _url
147
153
  end
148
154
 
149
155
  private
156
+
150
157
  # Internal: Delegate the method to the API if it exists.
151
158
  #
152
- # This allows `api.links.posts.embedded` instead of
153
- # `api.links.posts.resource.embedded`
159
+ # This allows `api.posts` instead of `api.links.posts.embedded`
154
160
  def method_missing(method, *args, &block)
155
- if resource.respond_to?(method)
156
- resource.send(method, *args, &block)
161
+ if @key && _resource.respond_to?(@key) && (delegate = _resource.send(@key)) && delegate.respond_to?(method.to_s)
162
+ # named.named becomes named
163
+ delegate.send(method, *args, &block)
164
+ elsif _resource.respond_to?(method.to_s)
165
+ _resource.send(method, *args, &block)
157
166
  else
158
167
  super
159
168
  end
@@ -161,8 +170,12 @@ module Hyperclient
161
170
 
162
171
  # Internal: Accessory method to allow the link respond to the
163
172
  # methods that will hit method_missing.
164
- def respond_to_missing?(method, include_private = false)
165
- resource.respond_to?(method.to_s)
173
+ def respond_to_missing?(method, _include_private = false)
174
+ if @key && _resource.respond_to?(@key) && (delegate = _resource.send(@key)) && delegate.respond_to?(method.to_s)
175
+ true
176
+ else
177
+ _resource.respond_to?(method.to_s)
178
+ end
166
179
  end
167
180
 
168
181
  # Internal: avoid delegating to resource
@@ -174,7 +187,7 @@ module Hyperclient
174
187
  end
175
188
 
176
189
  # Internal: Memoization for a URITemplate instance
177
- def uri_template
190
+ def _uri_template
178
191
  @uri_template ||= URITemplate.new(@link['href'])
179
192
  end
180
193
  end
@@ -182,10 +195,9 @@ module Hyperclient
182
195
  # Public: Exception that is raised when building a templated Link without uri
183
196
  # variables.
184
197
  class MissingURITemplateVariablesException < StandardError
185
-
186
198
  # Public: Returns a String with the exception message.
187
199
  def message
188
- "The URL to this links is templated, but no variables where given."
200
+ 'The URL to this links is templated, but no variables where given.'
189
201
  end
190
202
  end
191
203
  end