excon-hypermedia 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.rubocop.yml +3 -0
- data/README.md +11 -19
- data/excon-hypermedia.gemspec +2 -1
- data/lib/excon/hypermedia/ext/response.rb +31 -0
- data/lib/excon/hypermedia/link.rb +40 -0
- data/lib/excon/hypermedia/middleware.rb +29 -0
- data/lib/excon/hypermedia/resource.rb +49 -0
- data/lib/excon/hypermedia/response.rb +65 -0
- data/lib/excon/hypermedia/version.rb +3 -2
- data/lib/excon/hypermedia.rb +6 -14
- data/test/excon/hypermedia_test.rb +54 -48
- data/test/excon/link_test.rb +56 -0
- data/test/excon/resource_test.rb +47 -0
- metadata +23 -4
- data/lib/excon/hypermedia/hyper_media.rb +0 -26
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 375d919cb0b7562e0664ae44c30d3bdd7b71acf3
|
4
|
+
data.tar.gz: 5d48e0eff3d6f00c2968bb32a330949833a81745
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cc9e8bfd092cef7babc130b59e8debd50eb84680a37d91da238ec84888ebdae22ea9808035cc324a52ba81833eb67daffb4a5cdd68856fe8c4209bb5d0ca5d77
|
7
|
+
data.tar.gz: 080f93835dba3d7648c37377293428dadaf1e60281511f8d014debf4dacb5f65555cb96de919461229c718fa0fa253481275a4beff9f9b383d0888184d9c0c56
|
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -30,19 +30,20 @@ relations. It returns raw response bodies in string format.
|
|
30
30
|
|
31
31
|
This gem adds a thin layer on top of [Excon][excon] to make it talk with an
|
32
32
|
HyperMedia-enabled API. To let Excon know the connection supports HyperMedia,
|
33
|
-
simply
|
33
|
+
simply enable the correct middleware (either globally, or per-connection):
|
34
34
|
|
35
35
|
```ruby
|
36
|
-
|
37
|
-
|
36
|
+
Excon.defaults[:middlewares].push(Excon::HyperMedia::Middleware)
|
37
|
+
|
38
|
+
api = Excon.get('http://www.example.com/api.json')
|
39
|
+
api.class # => Excon::Response
|
38
40
|
```
|
39
41
|
|
40
|
-
|
41
|
-
|
42
|
-
long as you keep chaining the requests from the original top-level connection.
|
42
|
+
Using the `HyperMedia` middleware, the `Excon::Response` object now knows how
|
43
|
+
to handle the HyperMedia aspect of the API:
|
43
44
|
|
44
45
|
```ruby
|
45
|
-
product =
|
46
|
+
product = api.product(expand: { uid: 'hello' })
|
46
47
|
product.class # => Excon::Connection
|
47
48
|
|
48
49
|
response = product.get
|
@@ -53,16 +54,9 @@ response.body.class # => String
|
|
53
54
|
As seen above, you can expand URI Template variables using the `expand` option,
|
54
55
|
provided by the [`excon-addressable` library][excon-addressable].
|
55
56
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
```ruby
|
60
|
-
user = Excon.new('http://www.example.com/users/jeanmertz', hypermedia: true)
|
61
|
-
user.orders.class # => Excon::Connection
|
62
|
-
```
|
63
|
-
|
64
|
-
Since each new resource is simply an `Excon::Connection` object, all
|
65
|
-
[Excon-provided options][options] are available as well:
|
57
|
+
Since each new resource is simply an `Excon::Response` object, accessed through
|
58
|
+
the default `Excon::Connection` object, all [Excon-provided options][options]
|
59
|
+
are available as well:
|
66
60
|
|
67
61
|
```ruby
|
68
62
|
product.get(idempotent: true, retry_limit: 6)
|
@@ -74,10 +68,8 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
74
68
|
|
75
69
|
## TODO
|
76
70
|
|
77
|
-
* use Excon's Middleware system
|
78
71
|
* make it easy to access attributes in response objects
|
79
72
|
* properly handle curied-links and/or non-valid Ruby method name links
|
80
|
-
* work correctly with Excon.get/post/delete shortcut methods
|
81
73
|
|
82
74
|
[excon]: https://github.com/excon/excon
|
83
75
|
[hypermedia]: https://en.wikipedia.org/wiki/HATEOAS
|
data/excon-hypermedia.gemspec
CHANGED
@@ -6,7 +6,7 @@ require 'excon/hypermedia/version'
|
|
6
6
|
|
7
7
|
Gem::Specification.new do |spec|
|
8
8
|
spec.name = 'excon-hypermedia'
|
9
|
-
spec.version = Excon::
|
9
|
+
spec.version = Excon::HyperMedia::VERSION
|
10
10
|
spec.authors = %w(Jean Mertz)
|
11
11
|
spec.email = %w(jean@mertz.fm)
|
12
12
|
|
@@ -22,6 +22,7 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.add_development_dependency 'minitest', '~> 5.0'
|
23
23
|
spec.add_development_dependency 'rubocop', '~> 0.40'
|
24
24
|
spec.add_development_dependency 'pry', '~> 0.10'
|
25
|
+
spec.add_development_dependency 'm', '~> 1.5.0'
|
25
26
|
|
26
27
|
spec.add_dependency 'excon', '~> 0.49'
|
27
28
|
spec.add_dependency 'excon-addressable', '~> 0.1'
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Excon
|
4
|
+
module HyperMedia
|
5
|
+
module Ext
|
6
|
+
# Ext::Response
|
7
|
+
#
|
8
|
+
# Overloads the default `Excon::Response` to add a thin HyperMedia layer
|
9
|
+
# on top.
|
10
|
+
#
|
11
|
+
module Response
|
12
|
+
def method_missing(method_name, *params)
|
13
|
+
hypermedia_response.handle(method_name, *params) || super
|
14
|
+
end
|
15
|
+
|
16
|
+
def respond_to_missing?(method_name, include_private = false)
|
17
|
+
hypermedia_response.handle(method_name, *params) != false || super
|
18
|
+
end
|
19
|
+
|
20
|
+
def hypermedia_response
|
21
|
+
@hypermedia_response ||= HyperMedia::Response.new(self)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# :nodoc:
|
28
|
+
class Response
|
29
|
+
prepend HyperMedia::Ext::Response
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Excon
|
4
|
+
module HyperMedia
|
5
|
+
# Link
|
6
|
+
#
|
7
|
+
# This HyperMedia::Link object encapsulates a link pointing to a resource.
|
8
|
+
#
|
9
|
+
class Link
|
10
|
+
attr_reader :name
|
11
|
+
|
12
|
+
def initialize(name:, hash:)
|
13
|
+
@hash = hash
|
14
|
+
@name = name
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
link_data.keys.any?
|
19
|
+
end
|
20
|
+
|
21
|
+
def invalid?
|
22
|
+
!valid?
|
23
|
+
end
|
24
|
+
|
25
|
+
def uri
|
26
|
+
::Addressable::URI.parse(href)
|
27
|
+
end
|
28
|
+
|
29
|
+
def href
|
30
|
+
link_data['href']
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def link_data
|
36
|
+
@hash.dig('_links', name.to_s) || {}
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
Excon.defaults[:middlewares].unshift(Excon::Addressable::Middleware)
|
4
|
+
|
5
|
+
module Excon
|
6
|
+
module HyperMedia
|
7
|
+
# Middleware
|
8
|
+
#
|
9
|
+
# This middleware sets the `hypermedia` datum to `true`, if the returned
|
10
|
+
# `Content-Type` header contains `hal+json`.
|
11
|
+
#
|
12
|
+
# If the `hypermedia` attribute is already set for the connection, it
|
13
|
+
# will be left alone by this middleware.
|
14
|
+
#
|
15
|
+
class Middleware < Excon::Middleware::Base
|
16
|
+
def request_call(datum)
|
17
|
+
return super unless (content_type = datum.dig(:response, :headers, 'Content-Type').to_s)
|
18
|
+
|
19
|
+
datum[:response][:hypermedia] = if datum[:hypermedia].nil?
|
20
|
+
content_type.include?('hal+json')
|
21
|
+
else
|
22
|
+
datum[:hypermedia]
|
23
|
+
end
|
24
|
+
|
25
|
+
super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'json'
|
4
|
+
|
5
|
+
module Excon
|
6
|
+
module HyperMedia
|
7
|
+
# Resource
|
8
|
+
#
|
9
|
+
# This HyperMedia::Resource object encapsulates the returned JSON and
|
10
|
+
# makes it easy to access the links and attributes.
|
11
|
+
#
|
12
|
+
class Resource
|
13
|
+
attr_reader :data
|
14
|
+
|
15
|
+
def initialize(body)
|
16
|
+
@body = body
|
17
|
+
end
|
18
|
+
|
19
|
+
def links
|
20
|
+
data.fetch('_links', {}).keys.map { |name| link(name) }
|
21
|
+
end
|
22
|
+
|
23
|
+
def link(link_name)
|
24
|
+
Link.new(name: link_name, hash: data)
|
25
|
+
end
|
26
|
+
|
27
|
+
def attributes
|
28
|
+
attributes = data.reject do |k, _|
|
29
|
+
k == '_links'
|
30
|
+
end
|
31
|
+
|
32
|
+
Struct.new(*attributes.keys.map(&:to_sym)).new(*attributes.values)
|
33
|
+
end
|
34
|
+
|
35
|
+
def type?(name)
|
36
|
+
return :link if link(name).valid?
|
37
|
+
return :attribute if attributes.respond_to?(name.to_s)
|
38
|
+
|
39
|
+
:unknown
|
40
|
+
end
|
41
|
+
|
42
|
+
def data
|
43
|
+
@data ||= JSON.parse(@body)
|
44
|
+
rescue JSON::ParserError
|
45
|
+
{}
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,65 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'excon/hypermedia/ext/response'
|
4
|
+
|
5
|
+
module Excon
|
6
|
+
module HyperMedia
|
7
|
+
# Response
|
8
|
+
#
|
9
|
+
# This HyperMedia::Response object helps determine valid subsequent
|
10
|
+
# requests and attribute values.
|
11
|
+
#
|
12
|
+
class Response
|
13
|
+
attr_reader :response
|
14
|
+
|
15
|
+
def initialize(response)
|
16
|
+
@response = response
|
17
|
+
end
|
18
|
+
|
19
|
+
# handle
|
20
|
+
#
|
21
|
+
# Correctly handle the hypermedia request.
|
22
|
+
#
|
23
|
+
def handle(method_name, *params)
|
24
|
+
return false if disabled?
|
25
|
+
|
26
|
+
case resource.type?(method_name)
|
27
|
+
when :link then return handle_link(method_name, params)
|
28
|
+
when :attribute then return handle_attribute(method_name)
|
29
|
+
end
|
30
|
+
|
31
|
+
respond_to?(method_name) ? send(method_name) : false
|
32
|
+
end
|
33
|
+
|
34
|
+
def links
|
35
|
+
resource.links
|
36
|
+
end
|
37
|
+
|
38
|
+
def attributes
|
39
|
+
resource.attributes
|
40
|
+
end
|
41
|
+
|
42
|
+
def resource
|
43
|
+
@resource ||= Resource.new(response.body)
|
44
|
+
end
|
45
|
+
|
46
|
+
def enabled?
|
47
|
+
response.data[:hypermedia] == true
|
48
|
+
end
|
49
|
+
|
50
|
+
def disabled?
|
51
|
+
!enabled?
|
52
|
+
end
|
53
|
+
|
54
|
+
private
|
55
|
+
|
56
|
+
def handle_link(name, params)
|
57
|
+
Excon.new(resource.link(name).href, params.first.to_h.merge(hypermedia: true))
|
58
|
+
end
|
59
|
+
|
60
|
+
def handle_attribute(name)
|
61
|
+
attributes[name.to_s]
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
data/lib/excon/hypermedia.rb
CHANGED
@@ -1,17 +1,9 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
+
|
2
3
|
require 'excon'
|
3
4
|
require 'excon/addressable'
|
4
|
-
require 'excon/hypermedia/
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
#
|
10
|
-
module Hypermedia
|
11
|
-
def new(url, params = {})
|
12
|
-
params[:hypermedia] ? super.extend(HyperMedia) : super
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
singleton_class.prepend Hypermedia
|
17
|
-
end
|
5
|
+
require 'excon/hypermedia/link'
|
6
|
+
require 'excon/hypermedia/middleware'
|
7
|
+
require 'excon/hypermedia/resource'
|
8
|
+
require 'excon/hypermedia/response'
|
9
|
+
require 'excon/hypermedia/version'
|
@@ -1,5 +1,5 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
|
-
# rubocop:disable Metrics/
|
2
|
+
# rubocop:disable Metrics/LineLength
|
3
3
|
require_relative '../test_helper'
|
4
4
|
|
5
5
|
module Excon
|
@@ -9,75 +9,81 @@ module Excon
|
|
9
9
|
#
|
10
10
|
class HypermediaTest < Minitest::Test
|
11
11
|
def entrypoint
|
12
|
-
|
13
|
-
{
|
14
|
-
"_links": {
|
15
|
-
"hello": {
|
16
|
-
"href":"http://www.example.com/hello/{location}"
|
17
|
-
}
|
18
|
-
}
|
19
|
-
}
|
20
|
-
EOF
|
12
|
+
'{ "_links": { "hello": { "href":"http://www.example.com/hello/{location}" } } }'
|
21
13
|
end
|
22
14
|
|
23
|
-
def hello_world
|
15
|
+
def hello_world # rubocop:disable Metrics/MethodLength
|
24
16
|
<<~EOF
|
25
17
|
{
|
26
18
|
"_links": {
|
27
19
|
"goodbye": {
|
28
20
|
"href":"http://www.example.com/hello/world/goodbye{?message}"
|
29
21
|
}
|
30
|
-
}
|
31
|
-
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def hello_universe
|
36
|
-
<<~EOF
|
37
|
-
{
|
38
|
-
"_links": {
|
39
|
-
"goodbye": {
|
40
|
-
"href":"http://www.example.com/hello/universe/goodbye{?message}"
|
41
|
-
}
|
42
|
-
}
|
22
|
+
},
|
23
|
+
"uid": "hello",
|
24
|
+
"message": "goodbye!"
|
43
25
|
}
|
44
|
-
|
26
|
+
EOF
|
45
27
|
end
|
46
28
|
|
47
29
|
def setup
|
48
30
|
Excon.defaults[:mock] = true
|
31
|
+
Excon.defaults[:middlewares].push(Excon::HyperMedia::Middleware)
|
32
|
+
|
33
|
+
response = { headers: { 'Content-Type' => 'application/hal+json' } }
|
34
|
+
Excon.stub({ method: :get, path: '/api' }, response.merge(body: entrypoint))
|
35
|
+
Excon.stub({ method: :get, path: '/hello/world' }, response.merge(body: hello_world))
|
36
|
+
Excon.stub({ method: :get, path: '/hello/world/goodbye', query: nil }, response.merge(body: 'bye!'))
|
37
|
+
Excon.stub({ method: :get, path: '/hello/world/goodbye', query: 'message=farewell' }, response.merge(body: 'farewell'))
|
38
|
+
end
|
39
|
+
|
40
|
+
def client
|
41
|
+
Excon.get('http://www.example.com/api')
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_request
|
45
|
+
response = client.hello(expand: { location: 'world' }).get
|
46
|
+
|
47
|
+
assert response.body.include?('http://www.example.com/hello/world/goodbye{?message}')
|
48
|
+
end
|
49
|
+
|
50
|
+
def test_nested_request
|
51
|
+
hello = client.hello(expand: { location: 'world' })
|
52
|
+
response = hello.get.goodbye.get
|
49
53
|
|
50
|
-
|
51
|
-
Excon.stub({ method: :get, path: '/hello/world' }, body: hello_world, status: 200)
|
52
|
-
Excon.stub({ method: :get, path: '/hello/world/goodbye', query: nil }, body: 'bye!', status: 200)
|
53
|
-
Excon.stub({ method: :get, path: '/hello/world/goodbye', query: 'message=farewell' }, body: 'farewell', status: 200)
|
54
|
-
Excon.stub({ method: :get, path: '/hello/universe' }, body: hello_universe, status: 200)
|
54
|
+
assert_equal 'bye!', response.body
|
55
55
|
end
|
56
56
|
|
57
|
-
def
|
58
|
-
|
59
|
-
|
60
|
-
conn3 = conn.hello(expand: { location: 'universe' })
|
57
|
+
def test_nested_query_parameters
|
58
|
+
hello = client.hello(expand: { location: 'world' })
|
59
|
+
response = hello.get.goodbye(expand: { message: 'farewell' }).get
|
61
60
|
|
62
|
-
assert_equal '
|
63
|
-
|
61
|
+
assert_equal 'farewell', response.body
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_expand_in_get
|
65
|
+
response = client.hello.get(expand: { location: 'world' })
|
64
66
|
|
65
|
-
|
66
|
-
assert conn3.get.body.include?('http://www.example.com/hello/universe/goodbye{?message}')
|
67
|
+
assert response.body.include?('http://www.example.com/hello/world/goodbye{?message}')
|
67
68
|
end
|
68
69
|
|
69
|
-
def
|
70
|
-
|
71
|
-
|
72
|
-
|
70
|
+
def test_attribute
|
71
|
+
response = client.hello(expand: { location: 'world' }).get
|
72
|
+
|
73
|
+
assert_equal response.uid, 'hello'
|
74
|
+
assert_equal response.message, 'goodbye!'
|
75
|
+
end
|
76
|
+
|
77
|
+
def test_links
|
78
|
+
response = client.hello(expand: { location: 'world' }).get
|
79
|
+
|
80
|
+
assert_equal response.links.first.name, 'goodbye'
|
81
|
+
end
|
73
82
|
|
74
|
-
|
75
|
-
|
76
|
-
assert_equal 'bye!', conn2.get.body
|
83
|
+
def test_attributes
|
84
|
+
response = client.hello(expand: { location: 'world' }).get
|
77
85
|
|
78
|
-
assert_equal '
|
79
|
-
assert_equal 'message=farewell', conn3.data[:query]
|
80
|
-
assert_equal 'farewell', conn3.get.body
|
86
|
+
assert_equal response.attributes.uid, 'hello'
|
81
87
|
end
|
82
88
|
|
83
89
|
def teardown
|
@@ -0,0 +1,56 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '../test_helper'
|
3
|
+
|
4
|
+
module Excon
|
5
|
+
# LinkTest
|
6
|
+
#
|
7
|
+
# Validate the workings of `Excon::HyperResource::Link`.
|
8
|
+
#
|
9
|
+
class LinkTest < Minitest::Test
|
10
|
+
def body # rubocop:disable Metrics/MethodLength
|
11
|
+
<<~EOF
|
12
|
+
{
|
13
|
+
"_links": {
|
14
|
+
"hello": {
|
15
|
+
"href": "http://www.example.com/hello/{location}"
|
16
|
+
}
|
17
|
+
},
|
18
|
+
"uid": "universe",
|
19
|
+
"hello": "world"
|
20
|
+
}
|
21
|
+
EOF
|
22
|
+
end
|
23
|
+
|
24
|
+
def data
|
25
|
+
JSON.parse(body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def link
|
29
|
+
@link ||= Excon::HyperMedia::Link.new(name: 'hello', hash: data)
|
30
|
+
end
|
31
|
+
|
32
|
+
def invalid_link
|
33
|
+
@invalid_link ||= Excon::HyperMedia::Link.new(name: 'goodbye', hash: data)
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_link
|
37
|
+
assert_equal link.name, 'hello'
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_valid_link
|
41
|
+
assert link.valid?
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_invalid_link
|
45
|
+
refute invalid_link.valid?
|
46
|
+
end
|
47
|
+
|
48
|
+
def test_uri
|
49
|
+
assert_equal link.uri.to_s, data['_links']['hello']['href']
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_href
|
53
|
+
assert_equal link.href, data['_links']['hello']['href']
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require_relative '../test_helper'
|
3
|
+
|
4
|
+
module Excon
|
5
|
+
# ResourceTest
|
6
|
+
#
|
7
|
+
# Validate the workings of `Excon::HyperResource::Resource`.
|
8
|
+
#
|
9
|
+
class ResourceTest < Minitest::Test
|
10
|
+
def body # rubocop:disable Metrics/MethodLength
|
11
|
+
<<~EOF
|
12
|
+
{
|
13
|
+
"_links": {
|
14
|
+
"hello": {
|
15
|
+
"href": "http://www.example.com/hello/{location}"
|
16
|
+
}
|
17
|
+
},
|
18
|
+
"uid": "universe",
|
19
|
+
"hello": "world"
|
20
|
+
}
|
21
|
+
EOF
|
22
|
+
end
|
23
|
+
|
24
|
+
def data
|
25
|
+
@data ||= JSON.parse(body)
|
26
|
+
end
|
27
|
+
|
28
|
+
def resource
|
29
|
+
@resource ||= Excon::HyperMedia::Resource.new(body)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_resource
|
33
|
+
assert_equal data, resource.data
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_links
|
37
|
+
assert_equal data['_links']['hello']['href'], resource.links.first.href
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_attributes
|
41
|
+
assert_equal resource.attributes.uid, 'universe'
|
42
|
+
assert_equal resource.attributes.hello, 'world'
|
43
|
+
|
44
|
+
refute resource.attributes.respond_to?('_links')
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: excon-hypermedia
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jean
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-05-
|
12
|
+
date: 2016-05-18 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -81,6 +81,20 @@ dependencies:
|
|
81
81
|
- - "~>"
|
82
82
|
- !ruby/object:Gem::Version
|
83
83
|
version: '0.10'
|
84
|
+
- !ruby/object:Gem::Dependency
|
85
|
+
name: m
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - "~>"
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: 1.5.0
|
91
|
+
type: :development
|
92
|
+
prerelease: false
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
94
|
+
requirements:
|
95
|
+
- - "~>"
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: 1.5.0
|
84
98
|
- !ruby/object:Gem::Dependency
|
85
99
|
name: excon
|
86
100
|
requirement: !ruby/object:Gem::Requirement
|
@@ -126,9 +140,15 @@ files:
|
|
126
140
|
- Rakefile
|
127
141
|
- excon-hypermedia.gemspec
|
128
142
|
- lib/excon/hypermedia.rb
|
129
|
-
- lib/excon/hypermedia/
|
143
|
+
- lib/excon/hypermedia/ext/response.rb
|
144
|
+
- lib/excon/hypermedia/link.rb
|
145
|
+
- lib/excon/hypermedia/middleware.rb
|
146
|
+
- lib/excon/hypermedia/resource.rb
|
147
|
+
- lib/excon/hypermedia/response.rb
|
130
148
|
- lib/excon/hypermedia/version.rb
|
131
149
|
- test/excon/hypermedia_test.rb
|
150
|
+
- test/excon/link_test.rb
|
151
|
+
- test/excon/resource_test.rb
|
132
152
|
- test/test_helper.rb
|
133
153
|
homepage: https://github.com/JeanMertz/excon-hypermedia
|
134
154
|
licenses:
|
@@ -155,4 +175,3 @@ signing_key:
|
|
155
175
|
specification_version: 4
|
156
176
|
summary: Excon, with Hypermedia traversing baked in.
|
157
177
|
test_files: []
|
158
|
-
has_rdoc:
|
@@ -1,26 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
require 'json'
|
3
|
-
|
4
|
-
module Excon
|
5
|
-
# HyperMedia
|
6
|
-
#
|
7
|
-
module HyperMedia
|
8
|
-
def method_missing(method_name, *params)
|
9
|
-
return super unless (url = entrypoint.dig('_links', method_name.to_s, 'href'))
|
10
|
-
|
11
|
-
Excon.new(url, params.first.to_h.merge(hypermedia: true))
|
12
|
-
end
|
13
|
-
|
14
|
-
def respond_to_missing?(method_name, include_private = false)
|
15
|
-
entrypoint.dig('_links', method_name.to_s, 'href') ? true : super
|
16
|
-
end
|
17
|
-
|
18
|
-
private
|
19
|
-
|
20
|
-
def entrypoint
|
21
|
-
@entrypoint ||= JSON.parse(get.body)
|
22
|
-
rescue JSON::ParserError
|
23
|
-
{}
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|