excon-hypermedia 0.4.3 → 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/.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:
|