hyperclient 0.4.0 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rubocop.yml +2 -0
- data/.rubocop_todo.yml +55 -0
- data/.travis.yml +2 -0
- data/CHANGELOG.md +33 -10
- data/CONTRIBUTING.md +117 -0
- data/Gemfile +2 -1
- data/Guardfile +6 -6
- data/LICENSE +2 -2
- data/README.md +138 -0
- data/Rakefile +5 -3
- data/UPGRADING.md +37 -0
- data/examples/splines_api.rb +22 -0
- data/features/steps/api_navigation.rb +8 -8
- data/features/steps/default_config.rb +6 -6
- data/features/support/api.rb +4 -4
- data/features/support/fixtures.rb +1 -1
- data/hyperclient.gemspec +9 -8
- data/lib/faraday/connection.rb +2 -2
- data/lib/hyperclient.rb +1 -1
- data/lib/hyperclient/attributes.rb +1 -1
- data/lib/hyperclient/collection.rb +3 -3
- data/lib/hyperclient/curie.rb +49 -0
- data/lib/hyperclient/entry_point.rb +6 -4
- data/lib/hyperclient/link.rb +70 -58
- data/lib/hyperclient/link_collection.rb +36 -11
- data/lib/hyperclient/resource.rb +49 -18
- data/lib/hyperclient/resource_collection.rb +2 -1
- data/lib/hyperclient/version.rb +1 -1
- data/test/fixtures/element.json +12 -1
- data/test/hyperclient/attributes_test.rb +2 -2
- data/test/hyperclient/collection_test.rb +6 -7
- data/test/hyperclient/curie_test.rb +34 -0
- data/test/hyperclient/entry_point_test.rb +3 -2
- data/test/hyperclient/link_collection_test.rb +26 -5
- data/test/hyperclient/link_test.rb +111 -86
- data/test/hyperclient/resource_collection_test.rb +2 -2
- data/test/hyperclient/resource_test.rb +67 -30
- data/test/test_helper.rb +2 -2
- metadata +54 -39
- data/Gemfile.lock +0 -112
- data/MIT-LICENSE +0 -20
- data/Readme.md +0 -180
- data/examples/cyberscore.rb +0 -76
- data/examples/hal_shop.rb +0 -53
- data/lib/faraday/request/digest_authentication.rb +0 -85
- 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.
|
6
|
-
api.
|
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.
|
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.
|
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.
|
26
|
-
@post.
|
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.
|
31
|
-
comment.
|
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,
|
14
|
-
api.
|
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.
|
22
|
+
@posts = api._links.posts
|
23
23
|
end
|
24
24
|
|
25
25
|
step 'it should have been parsed as JSON' do
|
26
|
-
@posts.
|
27
|
-
@posts.
|
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
|
data/features/support/api.rb
CHANGED
@@ -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.
|
18
|
+
api._links
|
19
19
|
end
|
20
20
|
|
21
21
|
after do
|
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 = [
|
6
|
-
gem.email = [
|
7
|
-
gem.description =
|
8
|
-
gem.summary =
|
9
|
-
gem.homepage =
|
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 =
|
14
|
-
gem.require_paths = [
|
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'
|
data/lib/faraday/connection.rb
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
require 'faraday'
|
2
|
-
|
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
|
-
|
14
|
+
builder.insert(0, Faraday::Request::DigestAuth, user, password)
|
15
15
|
end
|
16
16
|
end
|
17
17
|
end
|
data/lib/hyperclient.rb
CHANGED
@@ -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,
|
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, *
|
72
|
+
def method_missing(method_name, *_args, &_block)
|
73
73
|
@collection.fetch(method_name.to_s) do
|
74
|
-
|
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,
|
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(
|
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.
|
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
|
data/lib/hyperclient/link.rb
CHANGED
@@ -3,16 +3,18 @@ require 'uri_template'
|
|
3
3
|
require 'futuroscope'
|
4
4
|
|
5
5
|
module Hyperclient
|
6
|
-
# Internal: The Link is
|
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
|
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
|
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
|
43
|
-
return @link['href'] unless
|
44
|
-
|
44
|
+
def _url
|
45
|
+
return @link['href'] unless _templated?
|
46
|
+
fail MissingURITemplateVariablesException if @uri_variables.nil?
|
45
47
|
|
46
|
-
@url ||=
|
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
|
53
|
-
|
54
|
+
def _variables
|
55
|
+
_uri_template.variables
|
54
56
|
end
|
55
57
|
|
56
58
|
# Public: Returns the type property of the Link
|
57
|
-
def
|
59
|
+
def _type
|
58
60
|
@link['type']
|
59
61
|
end
|
60
62
|
|
61
63
|
# Public: Returns the name property of the Link
|
62
|
-
def
|
64
|
+
def _name
|
63
65
|
@link['name']
|
64
66
|
end
|
65
67
|
|
66
68
|
# Public: Returns the deprecation property of the Link
|
67
|
-
def
|
69
|
+
def _deprecation
|
68
70
|
@link['deprecation']
|
69
71
|
end
|
70
72
|
|
71
73
|
# Public: Returns the profile property of the Link
|
72
|
-
def
|
74
|
+
def _profile
|
73
75
|
@link['profile']
|
74
76
|
end
|
75
77
|
|
76
78
|
# Public: Returns the title property of the Link
|
77
|
-
def
|
79
|
+
def _title
|
78
80
|
@link['title']
|
79
81
|
end
|
80
82
|
|
81
83
|
# Public: Returns the hreflang property of the Link
|
82
|
-
def
|
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
|
89
|
+
def _resource
|
88
90
|
@resource ||= begin
|
89
|
-
response =
|
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
|
101
|
+
def _connection
|
100
102
|
@entry_point.connection
|
101
103
|
end
|
102
104
|
|
103
|
-
def
|
104
|
-
Futuroscope::Future.new
|
105
|
-
|
106
|
-
|
105
|
+
def _get
|
106
|
+
Futuroscope::Future.new do
|
107
|
+
_connection.get(_url)
|
108
|
+
end
|
107
109
|
end
|
108
110
|
|
109
|
-
def
|
110
|
-
Futuroscope::Future.new
|
111
|
-
|
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
|
116
|
-
Futuroscope::Future.new
|
117
|
-
|
118
|
-
|
117
|
+
def _head
|
118
|
+
Futuroscope::Future.new do
|
119
|
+
_connection.head(_url)
|
120
|
+
end
|
119
121
|
end
|
120
122
|
|
121
|
-
def
|
122
|
-
Futuroscope::Future.new
|
123
|
-
|
124
|
-
|
123
|
+
def _delete
|
124
|
+
Futuroscope::Future.new do
|
125
|
+
_connection.delete(_url)
|
126
|
+
end
|
125
127
|
end
|
126
128
|
|
127
|
-
def
|
128
|
-
Futuroscope::Future.new
|
129
|
-
|
130
|
-
|
129
|
+
def _post(params = {})
|
130
|
+
Futuroscope::Future.new do
|
131
|
+
_connection.post(_url, params)
|
132
|
+
end
|
131
133
|
end
|
132
134
|
|
133
|
-
def
|
134
|
-
Futuroscope::Future.new
|
135
|
-
|
136
|
-
|
135
|
+
def _put(params = {})
|
136
|
+
Futuroscope::Future.new do
|
137
|
+
_connection.put(_url, params)
|
138
|
+
end
|
137
139
|
end
|
138
140
|
|
139
|
-
def
|
140
|
-
Futuroscope::Future.new
|
141
|
-
|
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`
|
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
|
156
|
-
|
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,
|
165
|
-
|
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
|
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
|
-
|
200
|
+
'The URL to this links is templated, but no variables where given.'
|
189
201
|
end
|
190
202
|
end
|
191
203
|
end
|