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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 035b9a77a60897b009604c5b84b767f6870e9da7
4
- data.tar.gz: 453668c1af155925f62572cfb8988b79cf9f302c
3
+ metadata.gz: b0358df2e93e1a3ea4df131e23c87ff76871877f
4
+ data.tar.gz: 50eeadae4660c967681e88ba235b0c5b34af3e02
5
5
  SHA512:
6
- metadata.gz: 39f9c20f48fdf12774fa26ed087dd6a725d3c555b0d3f6741c5e23f65237f98414fea058c0113309105d017065edc257e28cebf88542acc1706e764160ebff1e
7
- data.tar.gz: 0a2b994966d7427b4167934ca553264ce1a008d4a63b7385cc23d0f50340a52e7b32a035a39aa082ba0c05a0cb27dc7405c0ee3c1f79ce0eedf2e0d639489d72
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 )
@@ -0,0 +1,4 @@
1
+ puts "ERRORS"
2
+ class HalClient
3
+ InvalidRepresentationError = Class.new(StandardError)
4
+ end
@@ -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
- # Signature
22
- #
23
- # initialize(hal_client, parsed_json)
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
- @raw = args.find {|it| (it.respond_to? :has_key?) && (it.respond_to? :fetch) }
53
- @hal_client = args.find {|it| HalClient === it }
25
+ (fail ArgumentError, "Either parsed_json or href must be provided") if
26
+ @raw.nil? && href.nil?
54
27
 
55
- if @raw.nil?
56
- @href = args.find {|it| it.respond_to? :downcase }
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 ||= hal_client.get(href)
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
- end
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 Hash === list_hash_or_nil
209
+ if hashish? list_hash_or_nil
223
210
  [list_hash_or_nil]
224
- else
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
@@ -1,3 +1,3 @@
1
1
  class HalClient
2
- VERSION = "1.5.0"
2
+ VERSION = "2.0.0"
3
3
  end
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, MultiJson.load(raw_repr)) }
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
- RSpec::Matchers.define(:include_representation_of) do |url|
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: 1.5.0
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-10 00:00:00.000000000 Z
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