hal-client 3.16.0 → 3.17.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.travis.yml +4 -1
- data/hal-client.gemspec +2 -1
- data/lib/hal_client/links_section.rb +8 -3
- data/lib/hal_client/representation.rb +22 -20
- data/lib/hal_client/version.rb +1 -1
- data/lib/hal_client.rb +17 -19
- data/spec/hal_client/collection_spec.rb +2 -4
- data/spec/hal_client/curie_resolver_spec.rb +1 -3
- data/spec/hal_client/link_spec.rb +1 -3
- data/spec/hal_client/links_section_spec.rb +4 -5
- data/spec/hal_client/representation_editor_spec.rb +0 -1
- data/spec/hal_client/representation_set_spec.rb +14 -16
- data/spec/hal_client/representation_spec.rb +30 -32
- data/spec/hal_client_spec.rb +83 -9
- data/spec/spec_helper.rb +74 -2
- metadata +19 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c738c6f35a8c627363d55bde0e10116bf46eb1b
|
4
|
+
data.tar.gz: 32b562905f475064e94fbf2128222292dc44bc4c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cf65e375001c9c167d557fe6345c58cdb07d5d70d63da052d7ce82392f9805002cbe6e91c703879fbe3f3c7cede65a2c88a74cf0943fa7fd4e825ad52541a263
|
7
|
+
data.tar.gz: 6749283d49cc6f3aa0ae7f37e5aeda09c08ad875d4206a8250fbac21200ca7afc09e42a6388bdd392bb8e667b88b574751771f1d6275e92892d725a663b9a9c9
|
data/.gitignore
CHANGED
data/.rspec
ADDED
data/.travis.yml
CHANGED
data/hal-client.gemspec
CHANGED
@@ -24,7 +24,8 @@ Gem::Specification.new do |spec|
|
|
24
24
|
|
25
25
|
spec.add_development_dependency "bundler", "~> 1.5"
|
26
26
|
spec.add_development_dependency "rake", "~> 10.1"
|
27
|
-
spec.add_development_dependency "rspec", "~> 3.
|
27
|
+
spec.add_development_dependency "rspec", "~> 3.5"
|
28
28
|
spec.add_development_dependency "webmock", ["~> 1.17", ">= 1.17.4"]
|
29
29
|
spec.add_development_dependency "rspec-collection_matchers"
|
30
|
+
spec.add_development_dependency "pry"
|
30
31
|
end
|
@@ -2,6 +2,13 @@ class HalClient
|
|
2
2
|
|
3
3
|
# Encapsulates a "_links" section.
|
4
4
|
class LinksSection
|
5
|
+
|
6
|
+
NO_RELATED_RESOURCE = ->(link_rel) {
|
7
|
+
raise KeyError, "No resources are related via `#{link_rel}`"
|
8
|
+
}
|
9
|
+
|
10
|
+
private_constant :NO_RELATED_RESOURCE
|
11
|
+
|
5
12
|
# section - json hash for the links section
|
6
13
|
# base_url - base URL with which to resolve relative URLs
|
7
14
|
def initialize(section, opts={} )
|
@@ -27,9 +34,7 @@ class HalClient
|
|
27
34
|
# Raises KeyError if the specified link_rel is not present and no
|
28
35
|
# default_value or default_proc are provided.
|
29
36
|
def hrefs(link_rel, &default_proc)
|
30
|
-
default_proc ||=
|
31
|
-
raise KeyError, "No resources are related via `#{link_rel}`"
|
32
|
-
}
|
37
|
+
default_proc ||= NO_RELATED_RESOURCE
|
33
38
|
|
34
39
|
return default_proc.call(link_rel) unless section.key? link_rel
|
35
40
|
|
@@ -15,6 +15,20 @@ class HalClient
|
|
15
15
|
# https://tools.ietf.org/html/draft-kelly-json-hal-07#section-4.1
|
16
16
|
RESERVED_PROPERTIES = ['_links', '_embedded'].freeze
|
17
17
|
|
18
|
+
NO_RELATED_RESOURCE = ->(link_rel) {
|
19
|
+
raise KeyError, "No resources are related via `#{link_rel}`"
|
20
|
+
}
|
21
|
+
|
22
|
+
NO_EMBED_FOUND = ->(link_rel) {
|
23
|
+
raise KeyError, "#{link_rel} embed not found"
|
24
|
+
}
|
25
|
+
|
26
|
+
NO_LINK_FOUND = ->(link_rel, _options) {
|
27
|
+
raise KeyError, "#{link_rel} link not found"
|
28
|
+
}
|
29
|
+
|
30
|
+
private_constant :NO_RELATED_RESOURCE, :NO_EMBED_FOUND, :NO_LINK_FOUND
|
31
|
+
|
18
32
|
# Create a new Representation
|
19
33
|
#
|
20
34
|
# options - name parameters
|
@@ -145,11 +159,7 @@ class HalClient
|
|
145
159
|
#
|
146
160
|
# link_rel - The link rel of interest
|
147
161
|
def related?(link_rel)
|
148
|
-
|
149
|
-
true
|
150
|
-
|
151
|
-
rescue KeyError
|
152
|
-
false
|
162
|
+
!!(linked(link_rel) { false } || embedded(link_rel) { false })
|
153
163
|
end
|
154
164
|
alias_method :has_related?, :related?
|
155
165
|
|
@@ -166,9 +176,7 @@ class HalClient
|
|
166
176
|
# Raises KeyError if the specified link does not exist
|
167
177
|
# and no default_proc is provided.
|
168
178
|
def related(link_rel, options = {}, &default_proc)
|
169
|
-
default_proc ||=
|
170
|
-
raise KeyError, "No resources are related via `#{link_rel}`"
|
171
|
-
}
|
179
|
+
default_proc ||= NO_RELATED_RESOURCE
|
172
180
|
|
173
181
|
embedded = embedded(link_rel) { nil }
|
174
182
|
linked = linked(link_rel, options) { nil }
|
@@ -231,9 +239,7 @@ class HalClient
|
|
231
239
|
# Raises KeyError if the specified link does not exist
|
232
240
|
# and no default_proc is provided.
|
233
241
|
def raw_related_hrefs(link_rel, &default_proc)
|
234
|
-
default_proc ||=
|
235
|
-
raise KeyError, "No resources are related via `#{link_rel}`"
|
236
|
-
}
|
242
|
+
default_proc ||= NO_RELATED_RESOURCE
|
237
243
|
|
238
244
|
embedded = embedded(link_rel) { nil }
|
239
245
|
linked = links.hrefs(link_rel) { nil }
|
@@ -346,23 +352,19 @@ class HalClient
|
|
346
352
|
end
|
347
353
|
|
348
354
|
def embedded(link_rel, &default_proc)
|
349
|
-
default_proc ||=
|
350
|
-
fail KeyError, "#{link_rel} embed not found"
|
351
|
-
}
|
355
|
+
default_proc ||= NO_EMBED_FOUND
|
352
356
|
|
353
357
|
relations = embedded_section.fetch(link_rel) { MISSING }
|
354
358
|
return default_proc.call(link_rel) if relations == MISSING
|
355
359
|
|
356
360
|
(boxed relations).map{|it| Representation.new hal_client: hal_client, parsed_json: it}
|
357
361
|
|
358
|
-
rescue InvalidRepresentationError
|
362
|
+
rescue InvalidRepresentationError
|
359
363
|
fail InvalidRepresentationError, "/_embedded/#{jpointer_esc(link_rel)} is not a valid representation"
|
360
364
|
end
|
361
365
|
|
362
|
-
def linked(link_rel, options, &default_proc)
|
363
|
-
default_proc ||=
|
364
|
-
fail KeyError, "#{link_rel} link not found"
|
365
|
-
}
|
366
|
+
def linked(link_rel, options = {}, &default_proc)
|
367
|
+
default_proc ||= NO_LINK_FOUND
|
366
368
|
|
367
369
|
relations = links.hrefs(link_rel) { MISSING }
|
368
370
|
return default_proc.call(link_rel, options) if relations == MISSING
|
@@ -376,7 +378,7 @@ class HalClient
|
|
376
378
|
end }
|
377
379
|
.map {|href| Representation.new href: href, hal_client: hal_client }
|
378
380
|
|
379
|
-
rescue InvalidRepresentationError
|
381
|
+
rescue InvalidRepresentationError
|
380
382
|
fail InvalidRepresentationError, "/_links/#{jpointer_esc(link_rel)} is not a valid link"
|
381
383
|
end
|
382
384
|
|
data/lib/hal_client/version.rb
CHANGED
data/lib/hal_client.rb
CHANGED
@@ -44,6 +44,7 @@ class HalClient
|
|
44
44
|
@base_client ||= options[:base_client]
|
45
45
|
@logger = options.fetch(:logger, NullLogger.new)
|
46
46
|
@timeout = options.fetch(:timeout, Float::INFINITY)
|
47
|
+
@base_client_with_headers = {}
|
47
48
|
|
48
49
|
default_message_request_headers.set('Accept', options[:accept]) if
|
49
50
|
options[:accept]
|
@@ -185,7 +186,7 @@ class HalClient
|
|
185
186
|
begin
|
186
187
|
Representation.new(hal_client: self, parsed_json: MultiJson.load(resp.to_s),
|
187
188
|
href: location)
|
188
|
-
rescue MultiJson::ParseError, InvalidRepresentationError
|
189
|
+
rescue MultiJson::ParseError, InvalidRepresentationError
|
189
190
|
if location
|
190
191
|
# response doesn't have a HAL body but we know what resource
|
191
192
|
# was created so we can be helpful.
|
@@ -213,13 +214,9 @@ class HalClient
|
|
213
214
|
# options
|
214
215
|
# :override_headers -
|
215
216
|
def client_for_get(options={})
|
216
|
-
|
217
|
+
headers = default_message_request_headers.merge(options[:override_headers])
|
217
218
|
|
218
|
-
|
219
|
-
@client_for_get ||= base_client.with_headers(default_message_request_headers)
|
220
|
-
else
|
221
|
-
client_for_get.with_headers(override_headers)
|
222
|
-
end
|
219
|
+
base_client_with_headers(headers)
|
223
220
|
end
|
224
221
|
|
225
222
|
# Returns the HTTP client to be used to make post requests.
|
@@ -227,19 +224,24 @@ class HalClient
|
|
227
224
|
# options
|
228
225
|
# :override_headers -
|
229
226
|
def client_for_post(options={})
|
230
|
-
|
227
|
+
headers = default_entity_and_message_request_headers.merge(options[:override_headers])
|
231
228
|
|
232
|
-
|
233
|
-
@client_for_post ||=
|
234
|
-
base_client.with_headers(default_entity_and_message_request_headers)
|
235
|
-
else
|
236
|
-
client_for_post.with_headers(override_headers)
|
237
|
-
end
|
229
|
+
base_client_with_headers(headers)
|
238
230
|
end
|
239
231
|
|
240
232
|
# Returns an HTTP client.
|
241
233
|
def base_client
|
242
|
-
@base_client ||=
|
234
|
+
@base_client ||= begin
|
235
|
+
logger.debug 'Created base_client'
|
236
|
+
HTTP::Client.new(follow: true)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
def base_client_with_headers(headers)
|
241
|
+
@base_client_with_headers[headers.to_h] ||= begin
|
242
|
+
logger.debug { "Created base_client with headers #{headers.inspect}" }
|
243
|
+
base_client.with_headers(headers)
|
244
|
+
end
|
243
245
|
end
|
244
246
|
|
245
247
|
attr_reader :default_entity_request_headers, :default_message_request_headers
|
@@ -249,10 +251,6 @@ class HalClient
|
|
249
251
|
default_message_request_headers.merge(default_entity_request_headers)
|
250
252
|
end
|
251
253
|
|
252
|
-
def default_entity_request_headers
|
253
|
-
@default_entity_request_headers
|
254
|
-
end
|
255
|
-
|
256
254
|
def entity_header_field?(field_name)
|
257
255
|
[:content_type, /^content-type$/i].any?{|pat| pat === field_name}
|
258
256
|
end
|
@@ -1,8 +1,6 @@
|
|
1
|
-
require_relative "../spec_helper"
|
2
|
-
|
3
1
|
require 'hal_client/collection'
|
4
2
|
|
5
|
-
describe HalClient::Collection do
|
3
|
+
RSpec.describe HalClient::Collection do
|
6
4
|
# BACKGROUND
|
7
5
|
|
8
6
|
shared_context "multi-item, multi-page" do
|
@@ -81,7 +79,7 @@ describe HalClient::Collection do
|
|
81
79
|
context do
|
82
80
|
include_context "multi-item, multi-page"
|
83
81
|
|
84
|
-
specify { expect { collection.count }.to raise_exception }
|
82
|
+
specify { expect { collection.count }.to raise_exception(NotImplementedError) }
|
85
83
|
end
|
86
84
|
end
|
87
85
|
|
@@ -1,8 +1,6 @@
|
|
1
|
-
require_relative "../spec_helper"
|
2
|
-
|
3
1
|
require 'hal_client/curie_resolver'
|
4
2
|
|
5
|
-
describe HalClient::CurieResolver do
|
3
|
+
RSpec.describe HalClient::CurieResolver do
|
6
4
|
describe "#new" do
|
7
5
|
it "takes an array of curie definitions" do
|
8
6
|
expect(described_class.new([f_ns, b_ns])).to be_kind_of described_class
|
@@ -1,7 +1,6 @@
|
|
1
|
-
require "spec_helper"
|
2
1
|
require 'hal-client'
|
3
2
|
|
4
|
-
describe HalClient::LinksSection, "namespaces embedded" do
|
3
|
+
RSpec.describe HalClient::LinksSection, "namespaces embedded" do
|
5
4
|
subject(:section) {
|
6
5
|
described_class.new(raw_section,
|
7
6
|
base_url: Addressable::URI.parse("http://example.com/foo"))
|
@@ -21,7 +20,7 @@ describe HalClient::LinksSection, "namespaces embedded" do
|
|
21
20
|
|
22
21
|
specify { expect(section.hrefs(fully_qualified_second_rel))
|
23
22
|
.to contain_exactly "http://example.com/bar", "http://example.com/baz" }
|
24
|
-
|
23
|
+
|
25
24
|
specify { expect(section.hrefs("ns2:second"))
|
26
25
|
.to contain_exactly "http://example.com/bar", "http://example.com/baz" }
|
27
26
|
|
@@ -56,7 +55,7 @@ describe HalClient::LinksSection, "namespaces embedded" do
|
|
56
55
|
end
|
57
56
|
end
|
58
57
|
|
59
|
-
describe HalClient::LinksSection, "invalid" do
|
58
|
+
RSpec.describe HalClient::LinksSection, "invalid" do
|
60
59
|
subject(:section) {
|
61
60
|
described_class.new(raw_section,
|
62
61
|
base_url: Addressable::URI.parse("http://example.com/"))
|
@@ -69,4 +68,4 @@ describe HalClient::LinksSection, "invalid" do
|
|
69
68
|
{ "bareurl" => "http://example.com/boom" }
|
70
69
|
}
|
71
70
|
|
72
|
-
end
|
71
|
+
end
|
@@ -1,14 +1,12 @@
|
|
1
|
-
require_relative '../spec_helper'
|
2
|
-
|
3
1
|
require 'hal_client'
|
4
2
|
require 'hal_client/representation'
|
5
3
|
require 'hal_client/representation_set'
|
6
4
|
|
7
|
-
describe HalClient::RepresentationSet do
|
5
|
+
RSpec.describe HalClient::RepresentationSet do
|
8
6
|
describe "#new" do
|
9
7
|
let!(:return_val) { described_class.new([foo_repr, bar_repr]) }
|
10
|
-
it {
|
11
|
-
it {
|
8
|
+
it { is_expected.to be_kind_of described_class }
|
9
|
+
it { is_expected.to have(2).items }
|
12
10
|
end
|
13
11
|
|
14
12
|
subject(:repr_set) { described_class.new([foo_repr, bar_repr]) }
|
@@ -41,25 +39,25 @@ describe HalClient::RepresentationSet do
|
|
41
39
|
describe "#related" do
|
42
40
|
context "single target in each member" do
|
43
41
|
subject(:returned_val) { repr_set.related("spouse") }
|
44
|
-
it {
|
45
|
-
it {
|
46
|
-
it {
|
42
|
+
it { is_expected.to include_representation_of "http://example.com/foo-spouse" }
|
43
|
+
it { is_expected.to include_representation_of "http://example.com/bar-spouse" }
|
44
|
+
it { is_expected.to have(2).items }
|
47
45
|
end
|
48
46
|
|
49
47
|
context "multiple targets" do
|
50
48
|
subject(:returned_val) { repr_set.related("sibling") }
|
51
|
-
it {
|
52
|
-
it {
|
53
|
-
it {
|
54
|
-
it {
|
49
|
+
it { is_expected.to include_representation_of "http://example.com/foo-brother" }
|
50
|
+
it { is_expected.to include_representation_of "http://example.com/foo-sister" }
|
51
|
+
it { is_expected.to include_representation_of "http://example.com/bar-brother" }
|
52
|
+
it { is_expected.to have(3).items }
|
55
53
|
end
|
56
54
|
|
57
55
|
context "templated" do
|
58
56
|
subject(:returned_val) { repr_set.related("cousin", distance: "first") }
|
59
|
-
it {
|
60
|
-
it {
|
61
|
-
it {
|
62
|
-
it {
|
57
|
+
it { is_expected.to include_representation_of "http://example.com/foo-first-cousin" }
|
58
|
+
it { is_expected.to include_representation_of "http://example.com/bar-paternal-first-cousin" }
|
59
|
+
it { is_expected.to include_representation_of "http://example.com/bar-maternal-first-cousin" }
|
60
|
+
it { is_expected.to have(3).items }
|
63
61
|
end
|
64
62
|
end
|
65
63
|
|
@@ -1,8 +1,6 @@
|
|
1
|
-
require_relative "../spec_helper"
|
2
|
-
|
3
1
|
require "hal_client/representation"
|
4
2
|
|
5
|
-
describe HalClient::Representation do
|
3
|
+
RSpec.describe HalClient::Representation do
|
6
4
|
let(:raw_repr) { <<-HAL }
|
7
5
|
{ "prop1": 1
|
8
6
|
,"prop2": 2
|
@@ -176,12 +174,12 @@ HAL
|
|
176
174
|
describe "#fetch" do
|
177
175
|
context "for existent property" do
|
178
176
|
subject { repr.fetch "prop1" }
|
179
|
-
it {
|
177
|
+
it { is_expected.to eq 1 }
|
180
178
|
end
|
181
179
|
|
182
180
|
context "for existent link" do
|
183
181
|
subject { repr.fetch "link1" }
|
184
|
-
it {
|
182
|
+
it { is_expected.to have(1).item }
|
185
183
|
it "includes related resource representation" do
|
186
184
|
expect(subject.first.href).to eq "http://example.com/bar"
|
187
185
|
end
|
@@ -189,7 +187,7 @@ HAL
|
|
189
187
|
|
190
188
|
context "for existent embedded" do
|
191
189
|
subject { repr.fetch "embed1" }
|
192
|
-
it {
|
190
|
+
it { is_expected.to have(1).item }
|
193
191
|
it "includes related resource representation" do
|
194
192
|
expect(subject.first.href).to eq "http://example.com/baz"
|
195
193
|
end
|
@@ -203,63 +201,63 @@ HAL
|
|
203
201
|
|
204
202
|
context "non-existent item w/ default value" do
|
205
203
|
subject { repr.fetch "wat", "whatevs" }
|
206
|
-
it {
|
204
|
+
it { is_expected.to eq "whatevs" }
|
207
205
|
end
|
208
206
|
|
209
207
|
context "non-existent item w/ default value generator" do
|
210
208
|
subject { repr.fetch("wat"){|key| key+"gen" } }
|
211
|
-
it {
|
209
|
+
it { is_expected.to eq "watgen" }
|
212
210
|
end
|
213
211
|
end
|
214
212
|
|
215
213
|
describe "#[]" do
|
216
214
|
context "for existent property" do
|
217
215
|
subject { repr["prop1"] }
|
218
|
-
it {
|
216
|
+
it { is_expected.to eq 1 }
|
219
217
|
end
|
220
218
|
|
221
219
|
context "for existent link" do
|
222
220
|
subject { repr["link1"] }
|
223
|
-
it {
|
224
|
-
it {
|
221
|
+
it { is_expected.to have(1).item }
|
222
|
+
it { is_expected.to include_representation_of "http://example.com/bar" }
|
225
223
|
end
|
226
224
|
|
227
225
|
context "for existent embedded" do
|
228
226
|
subject { repr["embed1"] }
|
229
|
-
it {
|
230
|
-
it {
|
227
|
+
it { is_expected.to have(1).item }
|
228
|
+
it { is_expected.to include_representation_of "http://example.com/baz" }
|
231
229
|
end
|
232
230
|
|
233
231
|
context "non-existent item w/o default" do
|
234
232
|
subject { repr["wat"] }
|
235
|
-
it {
|
233
|
+
it { is_expected.to be_nil }
|
236
234
|
end
|
237
235
|
end
|
238
236
|
|
239
237
|
describe "#related" do
|
240
238
|
context "for existent link" do
|
241
239
|
subject { repr.related "link1" }
|
242
|
-
it {
|
243
|
-
it {
|
240
|
+
it { is_expected.to have(1).item }
|
241
|
+
it { is_expected.to include_representation_of "http://example.com/bar" }
|
244
242
|
end
|
245
243
|
|
246
244
|
context "for existent compound link" do
|
247
245
|
subject { repr.related "link3" }
|
248
|
-
it {
|
249
|
-
it {
|
250
|
-
it {
|
246
|
+
it { is_expected.to have(2).item }
|
247
|
+
it { is_expected.to include_representation_of "http://example.com/link3-a" }
|
248
|
+
it { is_expected.to include_representation_of "http://example.com/link3-b" }
|
251
249
|
end
|
252
250
|
|
253
251
|
context "for existent templated link" do
|
254
252
|
subject { repr.related "templated", name: "bob" }
|
255
|
-
it {
|
256
|
-
it {
|
253
|
+
it { is_expected.to have(1).item }
|
254
|
+
it { is_expected.to include_representation_of "http://example.com/people?name=bob" }
|
257
255
|
end
|
258
256
|
|
259
257
|
context "for existent embedded" do
|
260
258
|
subject { repr.related "embed1" }
|
261
|
-
it {
|
262
|
-
it {
|
259
|
+
it { is_expected.to have(1).item }
|
260
|
+
it { is_expected.to include_representation_of "http://example.com/baz" }
|
263
261
|
end
|
264
262
|
|
265
263
|
context "non-existent item w/o default" do
|
@@ -319,17 +317,17 @@ HAL
|
|
319
317
|
|
320
318
|
describe "#related return value" do
|
321
319
|
subject(:return_val) { repr.related("http://example.com/rels/bar") }
|
322
|
-
it {
|
320
|
+
it { is_expected.to include_representation_of "http://example.com/bar" }
|
323
321
|
end
|
324
322
|
|
325
323
|
describe "#[] return value" do
|
326
324
|
subject(:return_val) { repr["http://example.com/rels/bar"] }
|
327
|
-
it {
|
325
|
+
it { is_expected.to include_representation_of "http://example.com/bar" }
|
328
326
|
end
|
329
327
|
|
330
328
|
describe "#related_hrefs return value" do
|
331
329
|
subject(:return_val) { repr.related_hrefs("http://example.com/rels/bar") }
|
332
|
-
it {
|
330
|
+
it { is_expected.to include "http://example.com/bar" }
|
333
331
|
end
|
334
332
|
end
|
335
333
|
|
@@ -347,17 +345,17 @@ HAL
|
|
347
345
|
|
348
346
|
describe "#related return value " do
|
349
347
|
subject(:return_val) { repr.related("http://example.com/rels/embed1") }
|
350
|
-
it {
|
348
|
+
it { is_expected.to include_representation_of "http://example.com/embed1" }
|
351
349
|
end
|
352
350
|
|
353
351
|
describe "#[] return value " do
|
354
352
|
subject(:return_val) { repr["http://example.com/rels/embed1"] }
|
355
|
-
it {
|
353
|
+
it { is_expected.to include_representation_of "http://example.com/embed1" }
|
356
354
|
end
|
357
355
|
|
358
356
|
describe "#related_hrefs return value " do
|
359
357
|
subject(:return_val) { repr.related_hrefs("http://example.com/rels/embed1") }
|
360
|
-
it {
|
358
|
+
it { is_expected.to include "http://example.com/embed1" }
|
361
359
|
end
|
362
360
|
end
|
363
361
|
|
@@ -409,8 +407,8 @@ HAL
|
|
409
407
|
end
|
410
408
|
|
411
409
|
context "non-collection" do
|
412
|
-
specify { expect{repr.as_enum}.to raise_error }
|
413
|
-
specify { expect{repr.to_enum}.to raise_error }
|
410
|
+
specify { expect{repr.as_enum}.to raise_error(HalClient::NotACollectionError) }
|
411
|
+
specify { expect{repr.to_enum}.to raise_error(HalClient::NotACollectionError) }
|
414
412
|
end
|
415
413
|
|
416
414
|
# Background
|
@@ -473,7 +471,7 @@ HAL
|
|
473
471
|
|
474
472
|
end
|
475
473
|
|
476
|
-
describe HalClient::Representation, "w/o hal_client" do
|
474
|
+
RSpec.describe HalClient::Representation, "w/o hal_client" do
|
477
475
|
subject(:repr) { described_class.new(parsed_json: MultiJson.load(raw_repr)) }
|
478
476
|
|
479
477
|
specify { expect(subject.href).to eq "http://example.com/foo" }
|
data/spec/hal_client_spec.rb
CHANGED
@@ -1,17 +1,17 @@
|
|
1
|
-
require_relative "./spec_helper"
|
2
1
|
require "hal_client"
|
2
|
+
require 'http'
|
3
3
|
|
4
|
-
describe HalClient do
|
4
|
+
RSpec.describe HalClient do
|
5
5
|
describe ".new()" do
|
6
6
|
subject { HalClient.new }
|
7
|
-
it {
|
7
|
+
it { is_expected.to be_kind_of HalClient }
|
8
8
|
end
|
9
9
|
|
10
10
|
subject(:client) { HalClient.new }
|
11
11
|
|
12
12
|
describe '.new w/ custom accept' do
|
13
13
|
subject { HalClient.new(accept: "application/vnd.myspecialmediatype") }
|
14
|
-
it {
|
14
|
+
it { is_expected.to be_kind_of HalClient }
|
15
15
|
end
|
16
16
|
|
17
17
|
describe "#get(<url>)" do
|
@@ -24,7 +24,7 @@ describe HalClient do
|
|
24
24
|
|
25
25
|
describe "request" do
|
26
26
|
subject { request }
|
27
|
-
it("should have been made") {
|
27
|
+
it("should have been made") { is_expected.to have_been_made }
|
28
28
|
|
29
29
|
it "sends accept header" do
|
30
30
|
expect(request.with(headers: {'Accept' => /application\/hal\+json/i})).
|
@@ -87,6 +87,43 @@ describe HalClient do
|
|
87
87
|
end
|
88
88
|
end
|
89
89
|
|
90
|
+
context "client reuse" do
|
91
|
+
let(:return_val) { nil }
|
92
|
+
let(:base_client) { instance_double('HTTP::Client') }
|
93
|
+
let(:real_client) { HTTP::Client.new }
|
94
|
+
subject(:client) { HalClient.new(base_client: base_client) }
|
95
|
+
|
96
|
+
it 'creates a base client with headers' do
|
97
|
+
expect(base_client).to receive(:with_headers) do |headers|
|
98
|
+
expect(headers.to_h).to include('Accept' => 'application/hal+json;q=0')
|
99
|
+
|
100
|
+
real_client
|
101
|
+
end
|
102
|
+
|
103
|
+
client.get "http://example.com/foo"
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'reuses base client with headers instances' do
|
107
|
+
expect(base_client).to receive(:with_headers) do |headers|
|
108
|
+
expect(headers.to_h).to include('Accept' => 'application/hal+json;q=0', 'Foo' => 'Bar')
|
109
|
+
|
110
|
+
real_client
|
111
|
+
end.once
|
112
|
+
|
113
|
+
client.get("http://example.com/foo", 'Foo' => 'Bar')
|
114
|
+
|
115
|
+
expect(base_client).to receive(:with_headers) do |headers|
|
116
|
+
expect(headers.to_h).to include('Accept' => 'application/hal+json;q=0', 'Hello' => 'World')
|
117
|
+
|
118
|
+
real_client
|
119
|
+
end.once
|
120
|
+
|
121
|
+
client.get("http://example.com/foo", 'Hello' => 'World')
|
122
|
+
|
123
|
+
client.get("http://example.com/foo", 'Foo' => 'Bar')
|
124
|
+
client.get("http://example.com/foo", 'Hello' => 'World')
|
125
|
+
end
|
126
|
+
end
|
90
127
|
end
|
91
128
|
|
92
129
|
context "server takes too long" do
|
@@ -173,7 +210,7 @@ describe HalClient do
|
|
173
210
|
|
174
211
|
describe "request" do
|
175
212
|
subject { request }
|
176
|
-
it("should have been made") {
|
213
|
+
it("should have been made") { is_expected.to have_been_made }
|
177
214
|
|
178
215
|
it "sends accept header" do
|
179
216
|
expect(request.with(headers: {'Accept' => /application\/hal\+json/})).
|
@@ -211,7 +248,7 @@ describe HalClient do
|
|
211
248
|
describe "request" do
|
212
249
|
before do return_val end
|
213
250
|
subject { post_request }
|
214
|
-
it("should have been made") {
|
251
|
+
it("should have been made") { is_expected.to have_been_made }
|
215
252
|
|
216
253
|
it "sends content type header" do
|
217
254
|
expect(post_request.with(headers: {'Content-Type' => 'application/hal+json'})).
|
@@ -223,7 +260,7 @@ describe HalClient do
|
|
223
260
|
let(:return_val) { client.post url, post_data, "Content-Type" => "text/plain" }
|
224
261
|
before do return_val end
|
225
262
|
subject { post_request }
|
226
|
-
it("should have been made") {
|
263
|
+
it("should have been made") { is_expected.to have_been_made }
|
227
264
|
|
228
265
|
it "sends content type header" do
|
229
266
|
expect(post_request.with(headers: {'Content-Type' => 'text/plain'})).
|
@@ -280,6 +317,43 @@ describe HalClient do
|
|
280
317
|
expect(logger.info_entries.first).to include "http://example.com/foo"
|
281
318
|
end
|
282
319
|
end
|
320
|
+
|
321
|
+
context "client reuse" do
|
322
|
+
let(:base_client) { instance_double('HTTP::Client') }
|
323
|
+
let(:real_client) { HTTP::Client.new }
|
324
|
+
subject(:client) { HalClient.new(base_client: base_client) }
|
325
|
+
|
326
|
+
it 'creates a base client with headers' do
|
327
|
+
expect(base_client).to receive(:with_headers) do |headers|
|
328
|
+
expect(headers.to_h).to include('Accept' => 'application/hal+json;q=0')
|
329
|
+
|
330
|
+
real_client
|
331
|
+
end
|
332
|
+
|
333
|
+
client.post(url, post_data)
|
334
|
+
end
|
335
|
+
|
336
|
+
it 'reuses base client with headers instances' do
|
337
|
+
expect(base_client).to receive(:with_headers) do |headers|
|
338
|
+
expect(headers.to_h).to include('Accept' => 'application/hal+json;q=0', 'Foo' => 'Bar')
|
339
|
+
|
340
|
+
real_client
|
341
|
+
end.once
|
342
|
+
|
343
|
+
client.post(url, post_data, 'Foo' => 'Bar')
|
344
|
+
|
345
|
+
expect(base_client).to receive(:with_headers) do |headers|
|
346
|
+
expect(headers.to_h).to include('Accept' => 'application/hal+json;q=0', 'Hello' => 'World')
|
347
|
+
|
348
|
+
real_client
|
349
|
+
end.once
|
350
|
+
|
351
|
+
client.post(url, post_data, 'Hello' => 'World')
|
352
|
+
|
353
|
+
client.post(url, post_data, 'Foo' => 'Bar')
|
354
|
+
client.post(url, post_data, 'Hello' => 'World')
|
355
|
+
end
|
356
|
+
end
|
283
357
|
end
|
284
358
|
|
285
359
|
describe ".post(<url>)" do
|
@@ -291,7 +365,7 @@ describe HalClient do
|
|
291
365
|
|
292
366
|
describe "request" do
|
293
367
|
subject { post_request }
|
294
|
-
it("should have been made") {
|
368
|
+
it("should have been made") { is_expected.to have_been_made }
|
295
369
|
|
296
370
|
it "sends accept header" do
|
297
371
|
expect(post_request.with(headers: {'Content-Type' => 'application/hal+json'})).
|
data/spec/spec_helper.rb
CHANGED
@@ -1,6 +1,78 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command.
|
2
|
+
#
|
3
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
4
|
+
RSpec.configure do |config|
|
5
|
+
config.expect_with :rspec do |expectations|
|
6
|
+
# This option will default to `true` in RSpec 4.
|
7
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
8
|
+
end
|
9
|
+
|
10
|
+
config.mock_with :rspec do |mocks|
|
11
|
+
# Prevents you from mocking or stubbing a method that does not exist on
|
12
|
+
# a real object. This is generally recommended, and will default to
|
13
|
+
# `true` in RSpec 4.
|
14
|
+
mocks.verify_partial_doubles = true
|
15
|
+
end
|
16
|
+
|
17
|
+
# This option will default to `:apply_to_host_groups` in RSpec 4 (and will
|
18
|
+
# have no way to turn it off -- the option exists only for backwards
|
19
|
+
# compatibility in RSpec 3). It causes shared context metadata to be
|
20
|
+
# inherited by the metadata hash of host groups and examples, rather than
|
21
|
+
# triggering implicit auto-inclusion in groups with matching metadata.
|
22
|
+
config.shared_context_metadata_behavior = :apply_to_host_groups
|
23
|
+
|
24
|
+
# This allows you to limit a spec run to individual examples or groups
|
25
|
+
# you care about by tagging them with `:focus` metadata. When nothing
|
26
|
+
# is tagged with `:focus`, all examples get run. RSpec also provides
|
27
|
+
# aliases for `it`, `describe`, and `context` that include `:focus`
|
28
|
+
# metadata: `fit`, `fdescribe` and `fcontext`, respectively.
|
29
|
+
config.filter_run_when_matching :focus
|
30
|
+
|
31
|
+
# Allows RSpec to persist some state between runs in order to support
|
32
|
+
# the `--only-failures` and `--next-failure` CLI options. We recommend
|
33
|
+
# you configure your source control system to ignore this file.
|
34
|
+
config.example_status_persistence_file_path = "spec/examples.txt"
|
35
|
+
|
36
|
+
# Limits the available syntax to the non-monkey patched syntax that is
|
37
|
+
# recommended.
|
38
|
+
config.disable_monkey_patching!
|
39
|
+
|
40
|
+
# This setting enables warnings. It's recommended, but in some cases may
|
41
|
+
# be too noisy due to issues in dependencies.
|
42
|
+
config.warnings = true
|
43
|
+
|
44
|
+
# Many RSpec users commonly either run the entire suite or an individual
|
45
|
+
# file, and it's useful to allow more verbose output when running an
|
46
|
+
# individual spec file.
|
47
|
+
if config.files_to_run.one?
|
48
|
+
# Use the documentation formatter for detailed output,
|
49
|
+
# unless a formatter has already been configured
|
50
|
+
# (e.g. via a command-line flag).
|
51
|
+
config.default_formatter = 'doc'
|
52
|
+
end
|
53
|
+
|
54
|
+
# Print the n slowest examples and example groups at the
|
55
|
+
# end of the spec run, to help surface which specs are running
|
56
|
+
# particularly slow.
|
57
|
+
config.profile_examples = 5
|
58
|
+
|
59
|
+
# Run specs in random order to surface order dependencies. If you find an
|
60
|
+
# order dependency and want to debug it, you can fix the order by providing
|
61
|
+
# the seed, which is printed after each run.
|
62
|
+
# --seed 1234
|
63
|
+
config.order = :random
|
64
|
+
|
65
|
+
# Seed global randomization in this process using the `--seed` CLI option.
|
66
|
+
# Setting this allows you to use `--seed` to deterministically reproduce
|
67
|
+
# test failures related to randomization by passing the same `--seed` value
|
68
|
+
# as the one that triggered the failure.
|
69
|
+
Kernel.srand config.seed
|
70
|
+
end
|
71
|
+
|
72
|
+
# hal_client-specific additions
|
73
|
+
|
1
74
|
$LOAD_PATH << Pathname(__FILE__).dirname + "../lib"
|
2
75
|
|
3
|
-
require 'rspec'
|
4
76
|
require 'webmock/rspec'
|
5
77
|
require 'multi_json'
|
6
78
|
require 'rspec/collection_matchers'
|
@@ -9,4 +81,4 @@ require 'support/custom_matchers'
|
|
9
81
|
|
10
82
|
RSpec.configure do |config|
|
11
83
|
config.include CustomMatchers
|
12
|
-
end
|
84
|
+
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: 3.
|
4
|
+
version: 3.17.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: 2016-08
|
11
|
+
date: 2016-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: http
|
@@ -86,14 +86,14 @@ dependencies:
|
|
86
86
|
requirements:
|
87
87
|
- - "~>"
|
88
88
|
- !ruby/object:Gem::Version
|
89
|
-
version: 3.
|
89
|
+
version: '3.5'
|
90
90
|
type: :development
|
91
91
|
prerelease: false
|
92
92
|
version_requirements: !ruby/object:Gem::Requirement
|
93
93
|
requirements:
|
94
94
|
- - "~>"
|
95
95
|
- !ruby/object:Gem::Version
|
96
|
-
version: 3.
|
96
|
+
version: '3.5'
|
97
97
|
- !ruby/object:Gem::Dependency
|
98
98
|
name: webmock
|
99
99
|
requirement: !ruby/object:Gem::Requirement
|
@@ -128,6 +128,20 @@ dependencies:
|
|
128
128
|
- - ">="
|
129
129
|
- !ruby/object:Gem::Version
|
130
130
|
version: '0'
|
131
|
+
- !ruby/object:Gem::Dependency
|
132
|
+
name: pry
|
133
|
+
requirement: !ruby/object:Gem::Requirement
|
134
|
+
requirements:
|
135
|
+
- - ">="
|
136
|
+
- !ruby/object:Gem::Version
|
137
|
+
version: '0'
|
138
|
+
type: :development
|
139
|
+
prerelease: false
|
140
|
+
version_requirements: !ruby/object:Gem::Requirement
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: '0'
|
131
145
|
description: An easy to use interface for REST APIs that use HAL.
|
132
146
|
email:
|
133
147
|
- pezra@barelyenough.org
|
@@ -136,6 +150,7 @@ extensions: []
|
|
136
150
|
extra_rdoc_files: []
|
137
151
|
files:
|
138
152
|
- ".gitignore"
|
153
|
+
- ".rspec"
|
139
154
|
- ".travis.yml"
|
140
155
|
- Gemfile
|
141
156
|
- LICENSE.txt
|
@@ -198,4 +213,3 @@ test_files:
|
|
198
213
|
- spec/hal_client_spec.rb
|
199
214
|
- spec/spec_helper.rb
|
200
215
|
- spec/support/custom_matchers.rb
|
201
|
-
has_rdoc:
|