hal-client 1.5.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +5 -1
- data/lib/hal_client/errors.rb +4 -0
- data/lib/hal_client/representation.rb +37 -43
- data/lib/hal_client/version.rb +1 -1
- data/lib/hal_client.rb +2 -1
- data/spec/hal_client/representation_set_spec.rb +2 -2
- data/spec/hal_client/representation_spec.rb +25 -12
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b0358df2e93e1a3ea4df131e23c87ff76871877f
|
4
|
+
data.tar.gz: 50eeadae4660c967681e88ba235b0c5b34af3e02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9f04ed673200ada3eeaf69da3efdff848f66b53364bf6091d0951ccf25ece8dfa4664d10d44eea60f16a318a61a5daa188142e374fc1d575fa2ec34c77675065
|
7
|
+
data.tar.gz: 062b8060773d2733ead788b829b93024d51bc397c3e5647bab0a80e401cd94964ca65fcaa9a4271496e4ac9c58d64dcaa1b604a56095cc108adf787805eee8b6
|
data/README.md
CHANGED
@@ -100,12 +100,16 @@ If the API uses one or more a custom mime types we can specify that they be incl
|
|
100
100
|
|
101
101
|
HalClient can be used by servers of HAL APIs to interpret the bodies of requests. For example,
|
102
102
|
|
103
|
-
new_post_repr = HalClient::Representation.new(JSON.load(request.raw_post))
|
103
|
+
new_post_repr = HalClient::Representation.new(parsed_json: JSON.load(request.raw_post))
|
104
104
|
author = Author.by_href(new_post_repr.related('author').first.href)
|
105
105
|
new_post = Post.new title: new_post_repr['title'], author: author, #...
|
106
106
|
|
107
107
|
Created this way the representation will not dereference any links (because it doesn't have a HalClient) but it will provide `HalClient::Representation`s of both embedded and linked resources.
|
108
108
|
|
109
|
+
## Upgrading from 1.x to 2.x
|
110
|
+
|
111
|
+
The signature of `HalClient::Representation#new` changed such that keyword arguments are required. Any direct uses of that method must be changed. This is the only breaking change.
|
112
|
+
|
109
113
|
## Contributing
|
110
114
|
|
111
115
|
1. Fork it ( http://github.com/pezra/hal-client/fork )
|
@@ -17,44 +17,16 @@ class HalClient
|
|
17
17
|
# document.
|
18
18
|
# href - The href of this representation.
|
19
19
|
# hal_client - The HalClient instance to use when navigating.
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
# initialize(parsed_json, hal_client)
|
25
|
-
#
|
26
|
-
# Initialize this representation with a parsed json document and a
|
27
|
-
# hal_client with which to make requests.
|
28
|
-
#
|
29
|
-
# initialize(href, hal_client)
|
30
|
-
#
|
31
|
-
# Initialize this representation with an href and a hal_client
|
32
|
-
# with which to make requests. Any attempt to retrieve properties
|
33
|
-
# or related representations will result in the href being
|
34
|
-
# dereferenced.
|
35
|
-
#
|
36
|
-
# initialize(href)
|
37
|
-
#
|
38
|
-
# Initialize this representation with an href. The representation
|
39
|
-
# will not be able to make requests to dereference itself but this
|
40
|
-
# can still be useful in test situations to maintain a uniform
|
41
|
-
# interface.
|
42
|
-
#
|
43
|
-
# initialize(parse_json)
|
44
|
-
#
|
45
|
-
# Initializes representation that cannot request related
|
46
|
-
# representations.
|
47
|
-
#
|
48
|
-
def initialize(*args)
|
49
|
-
(raise ArgumentError, "wrong number of arguments (#{args.size} for 1 or 2)") if
|
50
|
-
args.size > 2
|
20
|
+
def initialize(parsed_json: nil, hal_client: nil, href: nil)
|
21
|
+
@raw = parsed_json
|
22
|
+
@hal_client = hal_client
|
23
|
+
@href = href
|
51
24
|
|
52
|
-
|
53
|
-
|
25
|
+
(fail ArgumentError, "Either parsed_json or href must be provided") if
|
26
|
+
@raw.nil? && href.nil?
|
54
27
|
|
55
|
-
|
56
|
-
|
57
|
-
end
|
28
|
+
(fail InvalidRepresentationError, "Invalid HAL representation: #{raw.inspect}") if
|
29
|
+
raw && ! hashish?(raw)
|
58
30
|
end
|
59
31
|
|
60
32
|
# Returns The value of the specified property or the specified
|
@@ -118,6 +90,7 @@ class HalClient
|
|
118
90
|
def has_related?(link_rel)
|
119
91
|
_ = related link_rel
|
120
92
|
true
|
93
|
+
|
121
94
|
rescue KeyError
|
122
95
|
false
|
123
96
|
end
|
@@ -178,7 +151,11 @@ class HalClient
|
|
178
151
|
MISSING = Object.new
|
179
152
|
|
180
153
|
def raw
|
181
|
-
@raw
|
154
|
+
if @raw.nil? && @href && hal_client
|
155
|
+
@raw ||= hal_client.get(@href).raw
|
156
|
+
end
|
157
|
+
|
158
|
+
@raw
|
182
159
|
end
|
183
160
|
|
184
161
|
def link_section
|
@@ -192,8 +169,11 @@ class HalClient
|
|
192
169
|
def embedded(link_rel)
|
193
170
|
relations = boxed embedded_section.fetch(link_rel)
|
194
171
|
|
195
|
-
relations.map{|it| Representation.new hal_client, it}
|
196
|
-
|
172
|
+
relations.map{|it| Representation.new hal_client: hal_client, parsed_json: it}
|
173
|
+
|
174
|
+
rescue InvalidRepresentationError => err
|
175
|
+
fail InvalidRepresentationError, "/_embedded/#{jpointer_esc(link_rel)} is not a valid representation"
|
176
|
+
end
|
197
177
|
|
198
178
|
def embedded_or_nil(link_rel)
|
199
179
|
embedded link_rel
|
@@ -207,7 +187,14 @@ class HalClient
|
|
207
187
|
|
208
188
|
relations.
|
209
189
|
map {|link| href_from link, options }.
|
210
|
-
map {|href| Representation.new href, hal_client }
|
190
|
+
map {|href| Representation.new href: href, hal_client: hal_client }
|
191
|
+
|
192
|
+
rescue InvalidRepresentationError => err
|
193
|
+
fail InvalidRepresentationError, "/_links/#{jpointer_esc(link_rel)} is not a valid link"
|
194
|
+
end
|
195
|
+
|
196
|
+
def jpointer_esc(str)
|
197
|
+
str.gsub "/", "~1"
|
211
198
|
end
|
212
199
|
|
213
200
|
def linked_or_nil(link_rel, options)
|
@@ -219,10 +206,15 @@ class HalClient
|
|
219
206
|
|
220
207
|
|
221
208
|
def boxed(list_hash_or_nil)
|
222
|
-
if
|
209
|
+
if hashish? list_hash_or_nil
|
223
210
|
[list_hash_or_nil]
|
224
|
-
|
211
|
+
elsif list_hash_or_nil.respond_to? :map
|
225
212
|
list_hash_or_nil
|
213
|
+
else
|
214
|
+
# The only valid values for a link/embedded set are hashes or
|
215
|
+
# array-ish things.
|
216
|
+
|
217
|
+
fail InvalidRepresentationError
|
226
218
|
end
|
227
219
|
end
|
228
220
|
|
@@ -246,7 +238,9 @@ class HalClient
|
|
246
238
|
@namespaces ||= CurieResolver.new raw.fetch("_links", {}).fetch("curies", [])
|
247
239
|
end
|
248
240
|
|
249
|
-
|
241
|
+
def hashish?(thing)
|
242
|
+
thing.respond_to?(:fetch) && thing.respond_to?(:key?)
|
243
|
+
end
|
250
244
|
|
251
245
|
end
|
252
246
|
end
|
data/lib/hal_client/version.rb
CHANGED
data/lib/hal_client.rb
CHANGED
@@ -6,6 +6,7 @@ class HalClient
|
|
6
6
|
autoload :Representation, 'hal_client/representation'
|
7
7
|
autoload :RepresentationSet, 'hal_client/representation_set'
|
8
8
|
autoload :CurieResolver, 'hal_client/curie_resolver'
|
9
|
+
autoload :InvalidRepresentationError, 'hal_client/errors'
|
9
10
|
|
10
11
|
# Initializes a new client instance
|
11
12
|
#
|
@@ -22,7 +23,7 @@ class HalClient
|
|
22
23
|
# options - set of options to pass to `RestClient#get`
|
23
24
|
def get(url, options={})
|
24
25
|
resp = RestClient.get url, rest_client_options(options)
|
25
|
-
Representation.new self, MultiJson.load(resp)
|
26
|
+
Representation.new hal_client: self, parsed_json: MultiJson.load(resp)
|
26
27
|
end
|
27
28
|
|
28
29
|
protected
|
@@ -58,7 +58,7 @@ describe HalClient::RepresentationSet do
|
|
58
58
|
|
59
59
|
let(:a_client) { HalClient.new }
|
60
60
|
|
61
|
-
let(:foo_repr) { HalClient::Representation.new a_client, MultiJson.load(foo_hal)}
|
61
|
+
let(:foo_repr) { HalClient::Representation.new hal_client: a_client, parsed_json: MultiJson.load(foo_hal)}
|
62
62
|
let(:foo_hal) { <<-HAL }
|
63
63
|
{ "_links":{
|
64
64
|
"self": { "href":"http://example.com/foo" }
|
@@ -73,7 +73,7 @@ describe HalClient::RepresentationSet do
|
|
73
73
|
}
|
74
74
|
HAL
|
75
75
|
|
76
|
-
let(:bar_repr) { HalClient::Representation.new a_client, MultiJson.load(bar_hal) }
|
76
|
+
let(:bar_repr) { HalClient::Representation.new hal_client: a_client, parsed_json: MultiJson.load(bar_hal) }
|
77
77
|
let(:bar_hal) { <<-HAL }
|
78
78
|
{ "_links":{
|
79
79
|
"self": { "href":"http://example.com/bar" }
|
@@ -3,14 +3,6 @@ require_relative "../spec_helper"
|
|
3
3
|
require "hal_client/representation"
|
4
4
|
|
5
5
|
describe HalClient::Representation do
|
6
|
-
describe ".new(a_hal_client, a_parsed_json_doc)" do
|
7
|
-
let!(:return_val) { described_class.new(a_client, MultiJson.load(raw_repr)) }
|
8
|
-
describe "return_val" do
|
9
|
-
subject { return_val }
|
10
|
-
it { should be_kind_of described_class }
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
6
|
let(:raw_repr) { <<-HAL }
|
15
7
|
{ "prop1": 1
|
16
8
|
,"_links": {
|
@@ -28,7 +20,8 @@ describe HalClient::Representation do
|
|
28
20
|
}
|
29
21
|
}
|
30
22
|
HAL
|
31
|
-
subject(:repr) { described_class.new(a_client,
|
23
|
+
subject(:repr) { described_class.new(hal_client: a_client,
|
24
|
+
parsed_json: MultiJson.load(raw_repr)) }
|
32
25
|
|
33
26
|
describe "#to_s" do
|
34
27
|
subject(:return_val) { repr.to_s }
|
@@ -212,8 +205,28 @@ HAL
|
|
212
205
|
end
|
213
206
|
end
|
214
207
|
|
208
|
+
context "invalid link/embedded" do
|
209
|
+
let(:raw_repr) { <<-HAL }
|
210
|
+
{ "_links": {
|
211
|
+
"self": { "href": "http://example.com/foo" }
|
212
|
+
,"bare_url": "http://example.com/bar"
|
213
|
+
}
|
214
|
+
,"_embedded": {
|
215
|
+
"atom": "hello"
|
216
|
+
,"array-of-atoms": [1,2,3]
|
217
|
+
}
|
218
|
+
}
|
219
|
+
HAL
|
215
220
|
|
221
|
+
specify { expect{repr.related("bare_url")}
|
222
|
+
.to raise_error HalClient::InvalidRepresentationError, %r(/_links/bare_url) }
|
223
|
+
specify { expect{repr.related("atom")}
|
224
|
+
.to raise_error HalClient::InvalidRepresentationError, %r(/_embedded/atom) }
|
225
|
+
specify { expect{repr.related("array-of-atoms")}
|
226
|
+
.to raise_error HalClient::InvalidRepresentationError, %r(/_embedded/array-of-atoms) }
|
216
227
|
|
228
|
+
end
|
229
|
+
# Background
|
217
230
|
|
218
231
|
let(:a_client) { HalClient.new }
|
219
232
|
let!(:bar_request) { stub_identity_request("http://example.com/bar") }
|
@@ -227,7 +240,7 @@ HAL
|
|
227
240
|
to_return body: %Q|{"_links":{"self":{"href":#{url.to_json}}}}|
|
228
241
|
end
|
229
242
|
|
230
|
-
|
243
|
+
matcher :include_representation_of do |url|
|
231
244
|
match { |repr_set|
|
232
245
|
repr_set.any?{|it| it.href == url}
|
233
246
|
}
|
@@ -238,7 +251,7 @@ HAL
|
|
238
251
|
end
|
239
252
|
|
240
253
|
describe HalClient::Representation, "w/o hal_client" do
|
241
|
-
subject(:repr) { described_class.new(MultiJson.load(raw_repr)) }
|
254
|
+
subject(:repr) { described_class.new(parsed_json: MultiJson.load(raw_repr)) }
|
242
255
|
|
243
256
|
specify { expect(subject.href).to eq "http://example.com/foo" }
|
244
257
|
specify { expect(subject.related_hrefs "link1").to include "http://example.com/bar" }
|
@@ -259,4 +272,4 @@ describe HalClient::Representation, "w/o hal_client" do
|
|
259
272
|
}
|
260
273
|
}
|
261
274
|
HAL
|
262
|
-
end
|
275
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hal-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Peter Williams
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-03-
|
11
|
+
date: 2014-03-14 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rest-client
|
@@ -161,6 +161,7 @@ files:
|
|
161
161
|
- lib/hal-client.rb
|
162
162
|
- lib/hal_client.rb
|
163
163
|
- lib/hal_client/curie_resolver.rb
|
164
|
+
- lib/hal_client/errors.rb
|
164
165
|
- lib/hal_client/representation.rb
|
165
166
|
- lib/hal_client/representation_set.rb
|
166
167
|
- lib/hal_client/version.rb
|