hyperclient 0.4.0 → 0.5.0

Sign up to get free protection for your applications and to get access to all the features.
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