hal-client 1.5.0 → 2.0.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/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
|