hal-client 1.3.1 → 1.4.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 2feba4ea1ae2adc4762239ce875c4d4db3dad541
4
- data.tar.gz: d0854b133f4ca25cb6ee21d10e2e7ba8e87d1480
3
+ metadata.gz: b2ff485e8014f90b3dff0a1dfce149d179dd9cd1
4
+ data.tar.gz: 52d3c6654272fbca9b80e69c4506182c524a1f46
5
5
  SHA512:
6
- metadata.gz: 2ac5423a12091b050f6e27b93994b4a4914ab65a1702565b22ab724b45f73baa30a1896402ade0e62c024b1b2cbfacfde689143d41f9246d6900ddf6b723e4fa
7
- data.tar.gz: be45454510e90beb073b2b9c8852e59718727ca91ff89cd1da6ef8ccb26d593b9d5a71d604fc02f7f2dad7453515340e8754dab217743bd79729763676ce52a9
6
+ metadata.gz: 5ab224fd14a959818ce357dc71926fee813f90cc1f583d94c547e0842fabffad307021f285924d9193056b29e3a2b2670f89e55b56626688fbe488a9fc2edbd5
7
+ data.tar.gz: 31932812f8c8472d4dfd55515e8781c3407627709daf6ce6a25a01c0d5a1064069986bc428c64bfeb85e54addc73911215e15d7035976f7b1da384c0be710f36
data/README.md CHANGED
@@ -39,14 +39,16 @@ Once we have a representation we will want to navigate its links. This can be ac
39
39
  articles = blog.related("item")
40
40
  # => #<RepresentationSet:...>
41
41
 
42
- In the example above `item` is the link rel. The `#related` method extracts embedded representations and dereferences links with the specified rel. The resulting representations and packaged into a `HalClient::RepresentationSet`. `HalClient` always returns `RepresentationSet`s when following links, even when there is only one result as doing so tends to result in simpler client code.
42
+ In the example above `item` is the link rel. The `#related` method extracts embedded representations and link hrefs with the specified rel. The resulting representations are packaged into a `HalClient::RepresentationSet`. `HalClient` always returns `RepresentationSet`s when following links, even when there is only one result. `RepresentationSet`s are `Enumerable` so they expose all your favorite methods like `#each`, `#map`, `#any?`, etc. `RepresentationSet`s expose a `#related` method which calls `#related` on each member of the set and then merges the results into a new representation set.
43
43
 
44
- `RepresentationSet`s are `Enumerable` so they expose all your favorite methods like `#each`, `#map`, `#any?`, etc. `RepresentationSet`s expose a `#related` method which calls `#related` on each member of the set and then merges the results into a new representation set.
45
-
46
- authors = blog.related("author").related("item")
47
- authors.first.property("name")
44
+ all_the_authors = blog.related("author").related("item")
45
+ all_the_authors.first.property("name")
48
46
  # => "Bob Smith"
49
47
 
48
+ #### Request timing
49
+
50
+ If the `author` relationship was a link in the above example the HTTP GET to retrieve Bob's representation from the server does not happen until the `#property` method is called. This lazy dereferencing allows for working with efficiently with larger relationship sets.
51
+
50
52
  #### CURIEs
51
53
 
52
54
  Links specified using a compact URI (or CURIE) as the rel are fully supported. They are accessed using the fully expanded version of the curie. For example, given a representations of an author:
@@ -94,6 +96,16 @@ If the API uses one or more a custom mime types we can specify that they be incl
94
96
  my_client.get("http://blog.me/")
95
97
  # => #<Representation: http://blog.me/>
96
98
 
99
+ ### Parsing presentations from clients
100
+
101
+ HalClient can be used by servers of HAL APIs to interpret the bodies of requests. For example,
102
+
103
+ new_post_repr = HalClient::Representation.new(JSON.load(request.raw_post))
104
+ author = Author.by_href(new_post_repr.related('author').first.href)
105
+ new_post = Post.new title: new_post_repr['title'], author: author, #...
106
+
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
+
97
109
  ## Contributing
98
110
 
99
111
  1. Fork it ( http://github.com/pezra/hal-client/fork )
@@ -13,12 +13,48 @@ class HalClient
13
13
 
14
14
  # Create a new Representation
15
15
  #
16
- # hal_client - The HalClient instance to use when navigating.
17
16
  # parsed_json - A hash structure representing a single HAL
18
17
  # document.
19
- def initialize(hal_client, parsed_json)
20
- @hal_client = hal_client
21
- @raw = parsed_json
18
+ # href - The href of this representation.
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
51
+
52
+ @raw = args.find {|it| (it.respond_to? :has_key?) && (it.respond_to? :fetch) }
53
+ @hal_client = args.find {|it| HalClient === it }
54
+
55
+ if @raw.nil?
56
+ @href = args.find {|it| it.respond_to? :downcase }
57
+ end
22
58
  end
23
59
 
24
60
  # Returns The value of the specified property or the specified
@@ -41,7 +77,7 @@ class HalClient
41
77
 
42
78
  # Returns the URL of the resource this representation represents.
43
79
  def href
44
- link_section.fetch("self").fetch("href")
80
+ @href ||= link_section.fetch("self").fetch("href")
45
81
  end
46
82
 
47
83
  # Returns the value of the specified property or representations
@@ -92,8 +128,8 @@ class HalClient
92
128
  raise KeyError, "No resources are related via `#{link_rel}`"
93
129
  }
94
130
 
95
- embedded = embedded(link_rel) rescue nil
96
- linked = linked(link_rel, options) rescue nil
131
+ embedded = embedded_or_nil(link_rel)
132
+ linked = linked_or_nil(link_rel, options)
97
133
 
98
134
  if !embedded.nil? or !linked.nil?
99
135
  RepresentationSet.new (Array(embedded) + Array(linked))
@@ -115,20 +151,8 @@ class HalClient
115
151
  # Raises KeyError if the specified link does not exist
116
152
  # and no default_proc is provided.
117
153
  def related_hrefs(link_rel, options={}, &default_proc)
118
- default_proc ||= ->(link_rel){
119
- raise KeyError, "No resources are related via `#{link_rel}`"
120
- }
121
-
122
- embedded = boxed embedded_section.fetch(link_rel, nil)
123
- linked = boxed link_section.fetch(link_rel, nil)
124
-
125
- if !embedded.nil? or !linked.nil?
126
- Array(embedded).map{|it| it.fetch("_links").fetch("self").fetch("href") rescue nil} +
127
- Array(linked).map{|it| it.fetch("href", nil) }.
128
- compact
129
- else
130
- default_proc.call link_rel
131
- end
154
+ related(link_rel, options, &default_proc).
155
+ map(&:href)
132
156
  end
133
157
 
134
158
  # Returns a short human readable description of this
@@ -138,10 +162,14 @@ class HalClient
138
162
  end
139
163
 
140
164
  protected
141
- attr_reader :raw, :hal_client
165
+ attr_reader :hal_client
142
166
 
143
167
  MISSING = Object.new
144
168
 
169
+ def raw
170
+ @raw ||= hal_client.get(href)
171
+ end
172
+
145
173
  def link_section
146
174
  @link_section ||= fully_qualified raw.fetch("_links", {})
147
175
  end
@@ -156,12 +184,26 @@ class HalClient
156
184
  relations.map{|it| Representation.new hal_client, it}
157
185
  end
158
186
 
187
+ def embedded_or_nil(link_rel)
188
+ embedded link_rel
189
+
190
+ rescue KeyError
191
+ nil
192
+ end
193
+
159
194
  def linked(link_rel, options)
160
195
  relations = boxed link_section.fetch(link_rel)
161
196
 
162
197
  relations.
163
198
  map {|link| href_from link, options }.
164
- map {|href| hal_client.get href }
199
+ map {|href| Representation.new href, hal_client }
200
+ end
201
+
202
+ def linked_or_nil(link_rel, options)
203
+ linked link_rel, options
204
+
205
+ rescue KeyError
206
+ nil
165
207
  end
166
208
 
167
209
 
@@ -1,3 +1,3 @@
1
1
  class HalClient
2
- VERSION = "1.3.1"
2
+ VERSION = "1.4.0"
3
3
  end
@@ -3,12 +3,11 @@ require_relative "../spec_helper"
3
3
  require "hal_client/representation"
4
4
 
5
5
  describe HalClient::Representation do
6
- describe ".new" do
6
+ describe ".new(a_hal_client, a_parsed_json_doc)" do
7
7
  let!(:return_val) { described_class.new(a_client, MultiJson.load(raw_repr)) }
8
8
  describe "return_val" do
9
9
  subject { return_val }
10
10
  it { should be_kind_of described_class }
11
-
12
11
  end
13
12
  end
14
13
 
@@ -231,3 +230,27 @@ HAL
231
230
  }
232
231
  end
233
232
  end
233
+
234
+ describe HalClient::Representation, "w/o hal_client" do
235
+ subject(:repr) { described_class.new(MultiJson.load(raw_repr)) }
236
+
237
+ specify { expect(subject.href).to eq "http://example.com/foo" }
238
+ specify { expect(subject.related_hrefs "link1").to include "http://example.com/bar" }
239
+ specify { expect(subject.related("link1").first.href).to eq "http://example.com/bar" }
240
+ specify { expect(subject.related("embed1").first.href).to eq "http://example.com/baz" }
241
+
242
+
243
+ let(:raw_repr) { <<-HAL }
244
+ { "prop1": 1
245
+ ,"_links": {
246
+ "self": { "href": "http://example.com/foo" }
247
+ ,"link1": { "href": "http://example.com/bar" }
248
+ }
249
+ ,"_embedded": {
250
+ "embed1": {
251
+ "_links": { "self": { "href": "http://example.com/baz" }}
252
+ }
253
+ }
254
+ }
255
+ HAL
256
+ 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.3.1
4
+ version: 1.4.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-02-14 00:00:00.000000000 Z
11
+ date: 2014-03-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rest-client