excon-hypermedia 0.4.3 → 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.
- checksums.yaml +4 -4
- data/.wercker.yml +26 -2
- data/README.md +48 -2
- data/excon-hypermedia.gemspec +2 -1
- data/lib/excon/hypermedia/errors.rb +10 -0
- data/lib/excon/hypermedia/helpers/collection.rb +16 -1
- data/lib/excon/hypermedia/middleware.rb +8 -0
- data/lib/excon/hypermedia/middlewares/hypertext_cache_pattern.rb +59 -0
- data/lib/excon/hypermedia/resource_object.rb +4 -8
- data/lib/excon/hypermedia/response.rb +24 -5
- data/lib/excon/hypermedia/version.rb +1 -1
- data/lib/excon/hypermedia.rb +2 -0
- data/test/excon/edgecase_test.rb +88 -0
- data/test/excon/hcp_test.rb +59 -0
- data/test/excon/integration_test.rb +0 -4
- data/test/excon/link_object_test.rb +1 -1
- data/test/excon/links_test.rb +1 -1
- data/test/excon/properties_test.rb +1 -1
- data/test/excon/resource_object_test.rb +1 -1
- data/test/excon/response_test.rb +34 -0
- data/test/test_helper.rb +29 -8
- metadata +9 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6bc648cfd5761dfb1236aada3be47b061620a3ad
|
4
|
+
data.tar.gz: f0fc534b110a5de92cbe548a4dbe5eb4bcb6f5e6
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83c3ec47d43ce609a789f2bf0ae0281822ae0b4ba25b00596516ef7ed54e9ecc8ab4f3e834e642172b4a1560da4c8184aa4f6a6ac611f63dc84f22e19b4ee226
|
7
|
+
data.tar.gz: 74fb5d0362acce99b511533c487d18612c81f0c8b455d62633c6fd52e74eb8a262429e6873913e5a5f60e5efae9fdda15132c1602b38a3597e02e0573bf929ea
|
data/.wercker.yml
CHANGED
@@ -1,5 +1,29 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
ruby-latest:
|
2
|
+
box: ruby:latest
|
3
|
+
steps:
|
4
|
+
- bundle-install
|
5
|
+
- script:
|
6
|
+
name: tests
|
7
|
+
code: bundle exec rake
|
8
|
+
|
9
|
+
ruby-23:
|
10
|
+
box: ruby:2.3
|
11
|
+
steps:
|
12
|
+
- bundle-install
|
13
|
+
- script:
|
14
|
+
name: tests
|
15
|
+
code: bundle exec rake
|
16
|
+
|
17
|
+
ruby-22:
|
18
|
+
box: ruby:2.2
|
19
|
+
steps:
|
20
|
+
- bundle-install
|
21
|
+
- script:
|
22
|
+
name: tests
|
23
|
+
code: bundle exec rake
|
24
|
+
|
25
|
+
ruby-21:
|
26
|
+
box: ruby:2.1
|
3
27
|
steps:
|
4
28
|
- bundle-install
|
5
29
|
- script:
|
data/README.md
CHANGED
@@ -10,6 +10,8 @@ Teaches [Excon][] how to talk to [HyperMedia APIs][hypermedia].
|
|
10
10
|
* [relations](#relations)
|
11
11
|
* [properties](#properties)
|
12
12
|
* [embedded](#embedded)
|
13
|
+
* [Hypertext Cache Pattern](#hypertext-cache-pattern)
|
14
|
+
* [shortcuts](#shortcuts)
|
13
15
|
* [License](#license)
|
14
16
|
|
15
17
|
## Installation
|
@@ -254,8 +256,51 @@ For more information on this concept, see the [formal specification][_embedded].
|
|
254
256
|
Embedded resources work the same as the top-level resource:
|
255
257
|
|
256
258
|
```ruby
|
257
|
-
product._embedded.pump.class # => Excon::HyperMedia::ResourceObject
|
258
|
-
product._embedded.pump.weight # => '2kg'
|
259
|
+
product.resource._embedded.pump.class # => Excon::HyperMedia::ResourceObject
|
260
|
+
product.resource._embedded.pump.weight # => '2kg'
|
261
|
+
```
|
262
|
+
|
263
|
+
### Hypertext Cache Pattern
|
264
|
+
|
265
|
+
You can leverage embedded resources to dynamically reduce the number of requests
|
266
|
+
you have to make to get the desired results, improving the efficiency and
|
267
|
+
performance of the application. This technique is called
|
268
|
+
"[Hypertext Cache Pattern][hcp]".
|
269
|
+
|
270
|
+
When you enable `hcp`, the library detects if a requested resource is already
|
271
|
+
embedded, and will use that resource as a mocked response, eliminating any extra
|
272
|
+
request to get the resource:
|
273
|
+
|
274
|
+
```ruby
|
275
|
+
pump = product.rel('pump', hcp: true).get
|
276
|
+
|
277
|
+
pump[:hcp] # => true
|
278
|
+
pump.remote_ip # => '127.0.0.1'
|
279
|
+
pump.resource.weight # => '2kg'
|
280
|
+
```
|
281
|
+
|
282
|
+
This feature only works if you are sure the embedded resource is equal to the
|
283
|
+
resource returned by the link relation. Because of this requirement, the default
|
284
|
+
configuration has `hcp` disabled, you can either enable it per request (which
|
285
|
+
also enables it for future requests in the chain), or enable it globally:
|
286
|
+
|
287
|
+
```ruby
|
288
|
+
Excon.defaults[:hcp] = true
|
289
|
+
```
|
290
|
+
|
291
|
+
### shortcuts
|
292
|
+
|
293
|
+
While the above examples shows the clean separation between the different
|
294
|
+
concepts like `response`, `resource`, `links`, `properties` and `emeds`.
|
295
|
+
|
296
|
+
Traversing these objects always starts from the response object. To make moving
|
297
|
+
around a bit faster, there are several methods available on the
|
298
|
+
`Excon::Response` object for ease-of-use:
|
299
|
+
|
300
|
+
```ruby
|
301
|
+
product.links.class # => Excon::HyperMedia::ResourceObject::Links
|
302
|
+
product.properties.class # => Excon::HyperMedia::ResourceObject::Properties
|
303
|
+
product.embedded.class # => Excon::HyperMedia::ResourceObject::Embedded
|
259
304
|
```
|
260
305
|
|
261
306
|
## License
|
@@ -267,3 +312,4 @@ The gem is available as open source under the terms of the [MIT License](http://
|
|
267
312
|
[excon-addressable]: https://github.com/JeanMertz/excon-addressable
|
268
313
|
[options]: https://github.com/excon/excon#options
|
269
314
|
[_embedded]: https://tools.ietf.org/html/draft-kelly-json-hal-08#section-4.1.2
|
315
|
+
[hcp]: https://tools.ietf.org/html/draft-kelly-json-hal-06#section-8.3
|
data/excon-hypermedia.gemspec
CHANGED
@@ -17,13 +17,14 @@ Gem::Specification.new do |spec|
|
|
17
17
|
spec.files = `git ls-files -z`.split("\x0")
|
18
18
|
spec.require_paths = %w(lib)
|
19
19
|
|
20
|
-
spec.add_development_dependency 'bundler', '~> 1.
|
20
|
+
spec.add_development_dependency 'bundler', '~> 1.9'
|
21
21
|
spec.add_development_dependency 'rake', '~> 10.0'
|
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
25
|
spec.add_development_dependency 'm', '~> 1.5'
|
26
26
|
|
27
|
+
spec.add_dependency 'backport_dig' if RUBY_VERSION < '2.3'
|
27
28
|
spec.add_dependency 'excon', '~> 0.49'
|
28
29
|
spec.add_dependency 'excon-addressable', '~> 0.3'
|
29
30
|
end
|
@@ -12,7 +12,7 @@ module Excon
|
|
12
12
|
include Enumerable
|
13
13
|
|
14
14
|
def initialize(collection = {})
|
15
|
-
@collection ||= collection
|
15
|
+
@collection ||= collection.to_h
|
16
16
|
to_properties
|
17
17
|
end
|
18
18
|
|
@@ -34,6 +34,21 @@ module Excon
|
|
34
34
|
|
35
35
|
private
|
36
36
|
|
37
|
+
# method_missing
|
38
|
+
#
|
39
|
+
# Collections can be accessed using both the "dot notation" and the hash
|
40
|
+
# notation:
|
41
|
+
#
|
42
|
+
# collection.hello_world
|
43
|
+
# collection['hello_world']
|
44
|
+
#
|
45
|
+
# The second notation returns `nil` on missing keys, the first should do
|
46
|
+
# as well.
|
47
|
+
#
|
48
|
+
def method_missing(_)
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
|
37
52
|
def to_properties
|
38
53
|
collection.each do |key, value|
|
39
54
|
key = key.downcase
|
@@ -1,5 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
+
require 'backport_dig' if RUBY_VERSION < '2.3'
|
4
|
+
|
3
5
|
Excon.defaults[:middlewares].delete(Excon::Addressable::Middleware)
|
4
6
|
Excon.defaults[:middlewares].unshift(Excon::Addressable::Middleware)
|
5
7
|
|
@@ -14,6 +16,12 @@ module Excon
|
|
14
16
|
# will be left alone by this middleware.
|
15
17
|
#
|
16
18
|
class Middleware < Excon::Middleware::Base
|
19
|
+
def request_call(datum)
|
20
|
+
orig_stack = @stack
|
21
|
+
@stack = Excon::HyperMedia::Middlewares::HypertextCachePattern.new(orig_stack)
|
22
|
+
super
|
23
|
+
end
|
24
|
+
|
17
25
|
def response_call(datum)
|
18
26
|
return super unless (content_type = datum.dig(:response, :headers, 'Content-Type').to_s)
|
19
27
|
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Excon
|
4
|
+
module HyperMedia
|
5
|
+
module Middlewares
|
6
|
+
# HypertextCachePattern
|
7
|
+
#
|
8
|
+
# This middleware handles hcp-enabled requests.
|
9
|
+
#
|
10
|
+
# @see: https://tools.ietf.org/html/draft-kelly-json-hal-06#section-8.3
|
11
|
+
#
|
12
|
+
class HypertextCachePattern < Excon::Middleware::Base
|
13
|
+
attr_reader :datum
|
14
|
+
|
15
|
+
def request_call(datum)
|
16
|
+
@datum = datum
|
17
|
+
|
18
|
+
return super unless datum[:hcp] == true && datum[:method] == :get && find_embedded
|
19
|
+
|
20
|
+
datum[:response] = {
|
21
|
+
body: @embedded.to_json,
|
22
|
+
hcp: true,
|
23
|
+
headers: content_type_header,
|
24
|
+
remote_ip: '127.0.0.1',
|
25
|
+
status: 200
|
26
|
+
}
|
27
|
+
|
28
|
+
super
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def find_embedded
|
34
|
+
datum.dig(:hcp_params, :embedded).to_h.each do |_, object|
|
35
|
+
break if (@embedded = object_to_embedded(object))
|
36
|
+
end
|
37
|
+
|
38
|
+
@embedded
|
39
|
+
end
|
40
|
+
|
41
|
+
def object_to_embedded(object)
|
42
|
+
uri = ::Addressable::URI.new(datum.tap { |h| h.delete(:port) })
|
43
|
+
|
44
|
+
if object.respond_to?(:to_ary)
|
45
|
+
object.find { |hash| hash.dig('_links', 'self', 'href') == uri.to_s }
|
46
|
+
elsif object.dig('_links', 'self', 'href') == uri.to_s
|
47
|
+
object
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def content_type_header
|
52
|
+
return {} unless (header = datum.dig(:hcp_params, :content_type))
|
53
|
+
|
54
|
+
{ 'Content-Type' => header }
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -15,14 +15,6 @@ module Excon
|
|
15
15
|
|
16
16
|
def initialize(data)
|
17
17
|
@data = data
|
18
|
-
|
19
|
-
_properties.each do |key, value|
|
20
|
-
key = key.downcase
|
21
|
-
next unless /[@$"]/ !~ key.to_sym.inspect
|
22
|
-
|
23
|
-
singleton_class.class_eval { attr_reader key }
|
24
|
-
instance_variable_set("@#{key}", value.respond_to?(:keys) ? Properties.new(value) : value)
|
25
|
-
end
|
26
18
|
end
|
27
19
|
|
28
20
|
def _properties
|
@@ -64,6 +56,10 @@ module Excon
|
|
64
56
|
def [](key)
|
65
57
|
_properties[key]
|
66
58
|
end
|
59
|
+
|
60
|
+
def method_missing(method_name, *_)
|
61
|
+
_properties.send(method_name)
|
62
|
+
end
|
67
63
|
end
|
68
64
|
end
|
69
65
|
end
|
@@ -18,12 +18,15 @@ module Excon
|
|
18
18
|
#
|
19
19
|
# Correctly handle the hypermedia request.
|
20
20
|
#
|
21
|
-
def handle(method_name, *params)
|
21
|
+
def handle(method_name, *params) # rubocop:disable Metrics/CyclomaticComplexity
|
22
22
|
return false unless enabled?
|
23
23
|
|
24
24
|
case method_name
|
25
|
-
when :resource
|
26
|
-
when :
|
25
|
+
when :resource then resource
|
26
|
+
when :_links, :links then resource._links
|
27
|
+
when :_embedded, :embedded then resource._embedded
|
28
|
+
when :_properties, :properties then resource._properties
|
29
|
+
when :rel then rel(params.shift, params)
|
27
30
|
else false
|
28
31
|
end
|
29
32
|
end
|
@@ -49,11 +52,27 @@ module Excon
|
|
49
52
|
end
|
50
53
|
|
51
54
|
def rel(name, params)
|
52
|
-
|
53
|
-
|
55
|
+
raise ArgumentError, 'missing relation name' unless name
|
56
|
+
|
57
|
+
unless (link = resource._links[name])
|
58
|
+
raise UnknownRelationError, "unknown relation: #{name}"
|
59
|
+
end
|
60
|
+
|
61
|
+
options = rel_params(params.first.to_h)
|
54
62
|
|
55
63
|
link.respond_to?(:to_ary) ? link.map { |l| l.rel(options) } : link.rel(options)
|
56
64
|
end
|
65
|
+
|
66
|
+
def rel_params(params)
|
67
|
+
params.merge(
|
68
|
+
hypermedia: true,
|
69
|
+
hcp: (params[:hcp].nil? ? response.data[:hcp] : params[:hcp]),
|
70
|
+
hcp_params: {
|
71
|
+
content_type: response.headers['Content-Type'],
|
72
|
+
embedded: resource._embedded
|
73
|
+
}
|
74
|
+
)
|
75
|
+
end
|
57
76
|
end
|
58
77
|
end
|
59
78
|
end
|
data/lib/excon/hypermedia.rb
CHANGED
@@ -3,9 +3,11 @@
|
|
3
3
|
require 'excon'
|
4
4
|
require 'excon/addressable'
|
5
5
|
|
6
|
+
require 'excon/hypermedia/errors'
|
6
7
|
require 'excon/hypermedia/helpers/collection'
|
7
8
|
require 'excon/hypermedia/link_object'
|
8
9
|
require 'excon/hypermedia/middleware'
|
10
|
+
require 'excon/hypermedia/middlewares/hypertext_cache_pattern'
|
9
11
|
require 'excon/hypermedia/resource_object'
|
10
12
|
require 'excon/hypermedia/response'
|
11
13
|
require 'excon/hypermedia/version'
|
@@ -0,0 +1,88 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../test_helper'
|
4
|
+
|
5
|
+
module Excon
|
6
|
+
# EdgeCaseTest
|
7
|
+
#
|
8
|
+
# Validate edge cases (or: non-happy path)
|
9
|
+
#
|
10
|
+
class EdgeCaseTest < HyperMediaTest
|
11
|
+
def setup
|
12
|
+
Excon.defaults[:mock] = true
|
13
|
+
Excon.defaults[:middlewares].push(Excon::HyperMedia::Middleware)
|
14
|
+
|
15
|
+
response = { headers: { 'Content-Type' => 'application/hal+json' } }
|
16
|
+
Excon.stub({ path: '/api.json' }, response.merge(body: api_body))
|
17
|
+
Excon.stub({ path: '/empty_json' }, response.merge(body: '{}'))
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
Excon.stubs.clear
|
22
|
+
Excon.defaults[:middlewares].delete(Excon::HyperMedia::Middleware)
|
23
|
+
end
|
24
|
+
|
25
|
+
def api
|
26
|
+
Excon.get('https://www.example.org/api.json')
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_missing_middleware
|
30
|
+
Excon.defaults[:middlewares].delete(Excon::HyperMedia::Middleware)
|
31
|
+
|
32
|
+
assert_raises(NoMethodError) { api.rel }
|
33
|
+
end
|
34
|
+
|
35
|
+
def test_rel_missing_name
|
36
|
+
ex = assert_raises(ArgumentError) { api.rel }
|
37
|
+
assert_equal 'missing relation name', ex.message
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_rel_missing_arguments
|
41
|
+
assert_equal Excon::Connection, api.rel('self').class
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_rel_unknown_relation
|
45
|
+
ex = assert_raises(Excon::HyperMedia::UnknownRelationError) { api.rel('invalid') }
|
46
|
+
assert_equal 'unknown relation: invalid', ex.message
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_missing_links
|
50
|
+
resource = Excon.get('https://www.example.org/empty_json').resource
|
51
|
+
|
52
|
+
assert_equal({}, resource._links.to_h)
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_missing_embedded
|
56
|
+
resource = Excon.get('https://www.example.org/empty_json').resource
|
57
|
+
|
58
|
+
assert_equal({}, resource._embedded.to_h)
|
59
|
+
end
|
60
|
+
|
61
|
+
def test_missing_properties
|
62
|
+
resource = Excon.get('https://www.example.org/empty_json').resource
|
63
|
+
|
64
|
+
assert_equal({}, resource._properties.to_h)
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_unknown_property
|
68
|
+
resource = Excon.get('https://www.example.org/api.json').resource
|
69
|
+
|
70
|
+
assert_equal nil, resource._properties.invalid
|
71
|
+
assert_equal nil, resource._properties['invalid']
|
72
|
+
end
|
73
|
+
|
74
|
+
def test_unknown_link
|
75
|
+
resource = Excon.get('https://www.example.org/empty_json').resource
|
76
|
+
|
77
|
+
assert_equal nil, resource._links.invalid
|
78
|
+
assert_equal nil, resource._links['invalid']
|
79
|
+
end
|
80
|
+
|
81
|
+
def test_unknown_embed
|
82
|
+
resource = Excon.get('https://www.example.org/api.json').resource
|
83
|
+
|
84
|
+
assert_equal nil, resource._embedded.invalid
|
85
|
+
assert_equal nil, resource._embedded['invalid']
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../test_helper'
|
4
|
+
|
5
|
+
module Excon
|
6
|
+
# HCPTest
|
7
|
+
#
|
8
|
+
# Validate the workings of `Excon::HyperResource::Middlewares::HypertextCachePattern`.
|
9
|
+
#
|
10
|
+
class HCPTest < HyperMediaTest
|
11
|
+
def response
|
12
|
+
@response ||= Excon.get('https://example.org/product/bicycle')
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_non_hcp_response
|
16
|
+
assert_equal nil, response[:hcp]
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_hcp_response
|
20
|
+
assert response.rel('pump', hcp: true).get[:hcp]
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_hcp_response_with_missing_embedding
|
24
|
+
api = Excon.get('https://www.example.org/api.json')
|
25
|
+
response = api.rel('product', expand: { uid: 'bicycle' }, rel: true).get
|
26
|
+
|
27
|
+
assert_equal nil, response[:hcp]
|
28
|
+
end
|
29
|
+
|
30
|
+
def test_hcp_response_with_embedded_array
|
31
|
+
wheels = response.rel('wheels', hcp: true)
|
32
|
+
|
33
|
+
assert wheels.map(&:get).all? { |res| res[:hcp] }
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_nested_hcp_responses
|
37
|
+
pump = response.rel('pump', hcp: true).get
|
38
|
+
response = pump.rel('parts', expand: { uid: 'bicycle' }).get
|
39
|
+
|
40
|
+
assert response[:hcp]
|
41
|
+
end
|
42
|
+
|
43
|
+
def test_hcp_not_working_for_non_get_requests
|
44
|
+
assert_equal nil, response.rel('pump', hcp: true).post[:hcp]
|
45
|
+
end
|
46
|
+
|
47
|
+
def test_hcp_resource
|
48
|
+
resource = response.rel('pump', hcp: true).get.resource
|
49
|
+
|
50
|
+
assert_equal Excon::HyperMedia::ResourceObject, resource.class
|
51
|
+
end
|
52
|
+
|
53
|
+
def test_hcp_links
|
54
|
+
resource = response.rel('pump', hcp: true).get.resource
|
55
|
+
|
56
|
+
assert_equal data(:parts)['_links']['self']['href'], resource._links.parts.href
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
@@ -48,10 +48,6 @@ module Excon
|
|
48
48
|
assert response.body.include?('https://www.example.org/product/bicycle')
|
49
49
|
end
|
50
50
|
|
51
|
-
def test_invalid_relation
|
52
|
-
assert_raises(NoMethodError) { api.rel('invalid') }
|
53
|
-
end
|
54
|
-
|
55
51
|
def test_link
|
56
52
|
response = api.rel('product', expand: { uid: 'bicycle' }).get
|
57
53
|
|
data/test/excon/links_test.rb
CHANGED
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../test_helper'
|
4
|
+
|
5
|
+
module Excon
|
6
|
+
# ResourceObjectTest
|
7
|
+
#
|
8
|
+
# Validate the workings of `Excon::HyperResource::ResourceObject`.
|
9
|
+
#
|
10
|
+
class ResponseTest < HyperMediaTest
|
11
|
+
def response
|
12
|
+
@response ||= Excon.get('https://example.org/product/bicycle')
|
13
|
+
end
|
14
|
+
|
15
|
+
def test_response
|
16
|
+
assert_equal Excon::Response, response.class
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_links
|
20
|
+
assert_equal response.resource._links, response.links
|
21
|
+
assert_equal response.resource._links, response._links
|
22
|
+
end
|
23
|
+
|
24
|
+
def test_embedded
|
25
|
+
assert_equal response.resource._embedded, response.embedded
|
26
|
+
assert_equal response.resource._embedded, response._embedded
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_properties
|
30
|
+
assert_equal response.resource._properties, response.properties
|
31
|
+
assert_equal response.resource._properties, response._properties
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -21,7 +21,8 @@ module Excon
|
|
21
21
|
Excon.stub({ method: :get, path: '/product/bicycle' }, response.merge(body: bicycle_body))
|
22
22
|
Excon.stub({ method: :get, path: '/product/bicycle/wheels/front' }, response.merge(body: front_wheel_body))
|
23
23
|
Excon.stub({ method: :get, path: '/product/bicycle/wheels/rear' }, response.merge(body: rear_wheel_body))
|
24
|
-
Excon.stub({
|
24
|
+
Excon.stub({ path: '/product/pump' }, response.merge(body: pump_body))
|
25
|
+
Excon.stub({ method: :get, path: '/product/pump/parts' }, response.merge(body: parts_body))
|
25
26
|
Excon.stub({ method: :get, path: '/product/handlebar' }, response.merge(body: handlebar_body))
|
26
27
|
Excon.stub({ method: :get, path: '/api_v2.json' }, body: api_body, headers: { 'Content-Type' => 'application/json' })
|
27
28
|
end
|
@@ -37,7 +38,7 @@ module Excon
|
|
37
38
|
end
|
38
39
|
|
39
40
|
def api_body
|
40
|
-
|
41
|
+
<<-EOF
|
41
42
|
{
|
42
43
|
"_links": {
|
43
44
|
"self": {
|
@@ -53,7 +54,7 @@ module Excon
|
|
53
54
|
end
|
54
55
|
|
55
56
|
def bicycle_body
|
56
|
-
|
57
|
+
<<-EOF
|
57
58
|
{
|
58
59
|
"_links": {
|
59
60
|
"self": {
|
@@ -90,7 +91,7 @@ module Excon
|
|
90
91
|
end
|
91
92
|
|
92
93
|
def handlebar_body
|
93
|
-
|
94
|
+
<<-EOF
|
94
95
|
{
|
95
96
|
"_links": {
|
96
97
|
"self": {
|
@@ -105,22 +106,42 @@ module Excon
|
|
105
106
|
end
|
106
107
|
|
107
108
|
def pump_body
|
108
|
-
|
109
|
+
<<-EOF
|
109
110
|
{
|
110
111
|
"_links": {
|
111
112
|
"self": {
|
112
113
|
"href": "https://www.example.org/product/pump"
|
114
|
+
},
|
115
|
+
"parts": {
|
116
|
+
"href": "https://www.example.org/product/pump/parts"
|
113
117
|
}
|
114
118
|
},
|
115
119
|
"weight": "2kg",
|
116
120
|
"type": "Floor Pump",
|
117
|
-
"valve-type": "Presta"
|
121
|
+
"valve-type": "Presta",
|
122
|
+
"_embedded": {
|
123
|
+
"parts": #{parts_body}
|
124
|
+
}
|
125
|
+
|
126
|
+
}
|
127
|
+
EOF
|
128
|
+
end
|
129
|
+
|
130
|
+
def parts_body
|
131
|
+
<<-EOF
|
132
|
+
{
|
133
|
+
"_links": {
|
134
|
+
"self": {
|
135
|
+
"href": "https://www.example.org/product/pump/parts"
|
136
|
+
}
|
137
|
+
},
|
138
|
+
"count": 47
|
118
139
|
}
|
119
140
|
EOF
|
120
141
|
end
|
121
142
|
|
122
143
|
def rear_wheel_body
|
123
|
-
|
144
|
+
<<-EOF
|
124
145
|
{
|
125
146
|
"_links": {
|
126
147
|
"self": {
|
@@ -134,7 +155,7 @@ module Excon
|
|
134
155
|
end
|
135
156
|
|
136
157
|
def front_wheel_body
|
137
|
-
|
158
|
+
<<-EOF
|
138
159
|
{
|
139
160
|
"_links": {
|
140
161
|
"self": {
|
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.5.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-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|
@@ -17,14 +17,14 @@ dependencies:
|
|
17
17
|
requirements:
|
18
18
|
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
|
-
version: '1.
|
20
|
+
version: '1.9'
|
21
21
|
type: :development
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
25
|
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
-
version: '1.
|
27
|
+
version: '1.9'
|
28
28
|
- !ruby/object:Gem::Dependency
|
29
29
|
name: rake
|
30
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -140,21 +140,26 @@ files:
|
|
140
140
|
- Rakefile
|
141
141
|
- excon-hypermedia.gemspec
|
142
142
|
- lib/excon/hypermedia.rb
|
143
|
+
- lib/excon/hypermedia/errors.rb
|
143
144
|
- lib/excon/hypermedia/ext/response.rb
|
144
145
|
- lib/excon/hypermedia/helpers/collection.rb
|
145
146
|
- lib/excon/hypermedia/link_object.rb
|
146
147
|
- lib/excon/hypermedia/middleware.rb
|
148
|
+
- lib/excon/hypermedia/middlewares/hypertext_cache_pattern.rb
|
147
149
|
- lib/excon/hypermedia/resource_object.rb
|
148
150
|
- lib/excon/hypermedia/resource_object/embedded.rb
|
149
151
|
- lib/excon/hypermedia/resource_object/links.rb
|
150
152
|
- lib/excon/hypermedia/resource_object/properties.rb
|
151
153
|
- lib/excon/hypermedia/response.rb
|
152
154
|
- lib/excon/hypermedia/version.rb
|
155
|
+
- test/excon/edgecase_test.rb
|
156
|
+
- test/excon/hcp_test.rb
|
153
157
|
- test/excon/integration_test.rb
|
154
158
|
- test/excon/link_object_test.rb
|
155
159
|
- test/excon/links_test.rb
|
156
160
|
- test/excon/properties_test.rb
|
157
161
|
- test/excon/resource_object_test.rb
|
162
|
+
- test/excon/response_test.rb
|
158
163
|
- test/test_helper.rb
|
159
164
|
homepage: https://github.com/JeanMertz/excon-hypermedia
|
160
165
|
licenses:
|