hal-client 3.1.2 → 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: b01e2f92e2ff7241a7b3b9af4e040792ce9254ef
4
+ data.tar.gz: 70adee990ffa32582f0e40836353746066cf3478
5
+ SHA512:
6
+ metadata.gz: 2ae965fff453c3252769221d653689da092c984fa2e30c47c1696b09ab9504ea13e8cde54a82d265e601a03248f44fe85b5d12245380a4795eff685bf1aa8cf3
7
+ data.tar.gz: 1466db8f6c04ed59b314b15c996c6c118646989819a98bdac069d3e15bcf0a037052c1655156b8ce1479b317e052670d9e98bcaca652ab3427a406d1321a7b23
data/README.md CHANGED
@@ -31,7 +31,7 @@ In the example above `item` is the link rel. The `#related` method extracts embe
31
31
  all_the_authors.first.property("name")
32
32
  # => "Bob Smith"
33
33
 
34
- #### Request timing
34
+ #### Request evaluation order
35
35
 
36
36
  If the `author` relationship was a regular link (that is, not embedded) 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.
37
37
 
@@ -74,15 +74,6 @@ All `HalClient::Representation`s exposed an `#href` attribute which is its ident
74
74
  blog['title'] # => "Some Person's Blog"
75
75
  blog['item'] # => #<RepresentationSet:...>
76
76
 
77
- ### POST requests
78
-
79
- HalClient supports POST requests to remote resources via it's `#post` method.
80
-
81
- blog.post(new_article_as_hal_json_str)
82
- #=> #<Representation: http://blog.me>
83
-
84
- The argument to post may be `String` or any object that responds to `#to_hal`. Additional options may be passed to change the content type of the post, etc.
85
-
86
77
  ### Paged collections
87
78
 
88
79
  HalClient provides a high level abstraction for paged collections encoded using [standard `item`, `next` and `prev` link relations](http://tools.ietf.org/html/rfc6573).
@@ -94,6 +85,51 @@ HalClient provides a high level abstraction for paged collections encoded using
94
85
 
95
86
  If the collection is paged this will navigate to the next page after yielding all the items on the current page. `HalClient::Collection` is `Enumerable` so all your favorite collection methods are available.
96
87
 
88
+ ### PUT/POST/PATCH requests
89
+
90
+ HalClient supports PUT/POST/PATCH requests to remote resources via it's `#put`, `#post` and `#patch` methods, respectively.
91
+
92
+ blog.put(update_article_as_hal_json_str)
93
+ #=> #<Representation: http://blog.me>
94
+
95
+ blog.post(new_article_as_hal_json_str)
96
+ #=> #<Representation: http://blog.me>
97
+
98
+ blog.patch(diffs_of_article_as_hal_json_str)
99
+ #=> #<Representation: http://blog.me>
100
+
101
+ The first argument to `#put`, `#post` and `#patch` may be a `String` or any object that responds to `#to_hal`. Additional options may be passed to change the content type of the post, etc.
102
+
103
+ ### PUT requests
104
+
105
+ HalClient supports PUT requests to remote resources via it's `#put` method.
106
+
107
+ blog.put(new_article_as_hal_json_str)
108
+ #=> #<Representation: http://blog.me>
109
+
110
+ The argument to post may be `String` or any object that responds to `#to_hal`. Additional options may be passed to change the content type of the post, etc.
111
+
112
+ ### Editing representation
113
+
114
+ HalClient supports editing of representations. This is useful when
115
+ creating resources from a template or updating resources. For example,
116
+ consider a resource whose "author" relationship we want to update to
117
+ point the author's new profile page.
118
+
119
+
120
+ ```ruby
121
+ doc = HalClient.get("http://example.com/somedoc")
122
+ improved_doc =
123
+ HalClient::RepresentationEditor.new(doc) # create an editor
124
+ .reject_related("author") { |it| it.property("name") == "John Doe"} # unlink Johe Doe's old page
125
+ .add_link("author", "http://example.com/john-doe") # add link to his new page
126
+
127
+ doc.put(improved_doc) # save changes to server
128
+
129
+ ```
130
+
131
+ This removes "John Plagerist" from the documents list of authors and then performs an HTTP PUT request with the updated document.
132
+
97
133
  ### Custom media types
98
134
 
99
135
  If the API uses one or more a custom mime types we can specify that they be included in the `Accept` header field of each request.
@@ -38,6 +38,22 @@ class HalClient
38
38
  @hal_client.post(href, data, options)
39
39
  end
40
40
 
41
+ # Puts a `Representation` or `String` to this resource.
42
+ #
43
+ # data - a `String` or an object that responds to `#to_hal`
44
+ # options - set of options to pass to `HalClient#put`
45
+ def put(data, options={})
46
+ @hal_client.put(href, data, options)
47
+ end
48
+
49
+ # Patchs a `Representation` or `String` to this resource.
50
+ #
51
+ # data - a `String` or an object that responds to `#to_hal`
52
+ # options - set of options to pass to `HalClient#patch`
53
+ def patch(data, options={})
54
+ @hal_client.patch(href, data, options)
55
+ end
56
+
41
57
  # Returns true if this representation contains the specified
42
58
  # property.
43
59
  #
@@ -191,12 +207,9 @@ class HalClient
191
207
  def to_json
192
208
  raw.to_json
193
209
  end
210
+ alias_method :to_hal, :to_json
194
211
 
195
- protected
196
- attr_reader :hal_client
197
-
198
- MISSING = Object.new
199
-
212
+ # Internal: Returns parsed json document
200
213
  def raw
201
214
  if @raw.nil? && @href
202
215
  (fail "unable to make requests due to missing hal client") unless hal_client
@@ -206,6 +219,15 @@ class HalClient
206
219
  @raw
207
220
  end
208
221
 
222
+ # Internal: Returns the HalClient used to retrieve this
223
+ # representation
224
+ attr_reader :hal_client
225
+
226
+ protected
227
+
228
+ MISSING = Object.new
229
+
230
+
209
231
  def links
210
232
  @links ||= LinksSection.new raw.fetch("_links"){{}}
211
233
  end
@@ -0,0 +1,138 @@
1
+ require 'hal_client'
2
+ require 'forwardable'
3
+
4
+ class HalClient
5
+
6
+ # Provides ability to edit a representation. Editing a
7
+ # representation is useful in writable APIs as a way to update
8
+ # resources.
9
+ #
10
+ # This class will not actually modify the underlying representation
11
+ # in any way.
12
+ #
13
+ # Example:
14
+ #
15
+ # ```ruby
16
+ # altered_doc = HalClient::RepresentationEditor.new(some_doc)
17
+ # .reject_relate("author") { |it| it["name"] = "John Plagiarist" }
18
+ # ```
19
+ class RepresentationEditor
20
+ extend Forwardable
21
+
22
+ # Initialize a new representation editor.
23
+ #
24
+ # a_representation - The representation from which you want to
25
+ # start. This object will *not* be modified!
26
+ # raw - Not for public use! Used internally for handling multi-
27
+ # staged changes.
28
+ def initialize(a_representation, raw = a_representation.raw)
29
+ @orig_repr = a_representation
30
+ @raw = raw
31
+ end
32
+
33
+ # Returns the raw json representation of this representation
34
+ def to_json
35
+ raw.to_json
36
+ end
37
+ alias_method :to_hal, :to_json
38
+
39
+ # Returns a RepresentationEditor for a representation like the
40
+ # current one but without the specified links and/or embeddeds.
41
+ #
42
+ # rel - The relationship type to remove or filter
43
+ # blk - When given only linked and embedded resource for whom
44
+ # the block returns true will be rejected.
45
+ #
46
+ # Yields Representation of the target for each link/embedded.
47
+ def reject_related(rel, &blk)
48
+ reject_links(rel, &blk).reject_embedded(rel, &blk)
49
+ end
50
+
51
+ # Returns a RepresentationEditor for a representation like the
52
+ # current one but without the specified links.
53
+ #
54
+ # rel - The relationship type to remove or filter
55
+ # blk - When given only links to resources for whom
56
+ # the block returns true will be rejected.
57
+ #
58
+ # Yields Representation of the target for each link.
59
+ def reject_links(rel, &blk)
60
+ reject_from_section("_links",
61
+ rel,
62
+ ->(l) {Representation.new(href: l["href"],
63
+ hal_client: hal_client)},
64
+ blk)
65
+ end
66
+
67
+ # Returns a RepresentationEditor for a representation like the
68
+ # current one but without the specified embedded resources.
69
+ #
70
+ # rel - The relationship type to remove or filter
71
+ # blk - When given only embedded resources for whom
72
+ # the block returns true will be rejected.
73
+ #
74
+ # Yields Representation of the target for each embedded.
75
+ def reject_embedded(rel, &blk)
76
+ reject_from_section("_embedded",
77
+ rel,
78
+ ->(e) {Representation.new(parsed_json: e,
79
+ hal_client: hal_client)},
80
+ blk)
81
+ end
82
+
83
+ # Returns a RepresentationEditor exactly like this one except that
84
+ # is has an additional link to the specified target with the
85
+ # specified rel.
86
+ #
87
+ # rel - The type of relationship this link represents
88
+ # target - URL of the target of the link
89
+ # opts
90
+ # :templated - is this link templated? Default: false
91
+ def add_link(rel, target, opts={})
92
+ templated = opts.fetch(:templated, false)
93
+
94
+ link_obj = { "href" => target.to_s }
95
+ link_obj = link_obj.merge("templated" => true) if templated
96
+
97
+ with_new_link = Array(raw.fetch("_links", {}).fetch(rel, [])) + [link_obj]
98
+ updated_links_section = raw.fetch("_links", {}).merge(rel => with_new_link)
99
+
100
+ self.class.new(orig_repr, raw.merge("_links" => updated_links_section))
101
+ end
102
+
103
+ protected
104
+
105
+ attr_reader :orig_repr, :raw
106
+
107
+ def Array(thing)
108
+ if Hash === thing
109
+ [thing]
110
+ else
111
+ Kernel.Array(thing)
112
+ end
113
+ end
114
+
115
+ def hal_client
116
+ orig_repr.hal_client
117
+ end
118
+
119
+ def reject_from_section(name, rel, coercion, filter=nil)
120
+ return self unless raw.fetch(name, {}).has_key?(rel)
121
+
122
+ filtered_rel = if filter
123
+ [raw[name].fetch(rel,[])].flatten
124
+ .reject{|it| filter.call(coercion.call(it)) }
125
+ else
126
+ []
127
+ end
128
+
129
+ new_sec = if filtered_rel.empty?
130
+ raw[name].reject{|k,_| rel == k}
131
+ else
132
+ raw[name].merge(rel => filtered_rel )
133
+ end
134
+
135
+ self.class.new(orig_repr, raw.merge(name => new_sec))
136
+ end
137
+ end
138
+ end
@@ -49,6 +49,28 @@ class HalClient
49
49
  first.post(data, options)
50
50
  end
51
51
 
52
+ # Put a `Representation` or `String` to the resource.
53
+ #
54
+ # NOTE: This only works for a single representation.
55
+ #
56
+ # data - a `String` or an object that responds to `#to_hal`
57
+ # options - set of options to pass to `HalClient#put`
58
+ def put(data, options={})
59
+ raise NotImplementedError, "We only puts to singular resources." if count > 1
60
+ first.put(data, options)
61
+ end
62
+
63
+ # Patch a `Representation` or `String` to the resource.
64
+ #
65
+ # NOTE: This only works for a single representation.
66
+ #
67
+ # data - a `String` or an object that responds to `#to_hal`
68
+ # options - set of options to pass to `HalClient#patch`
69
+ def patch(data, options={})
70
+ raise NotImplementedError, "We only patchs to singular resources." if count > 1
71
+ first.patch(data, options)
72
+ end
73
+
52
74
  protected
53
75
 
54
76
  attr_reader :reprs
@@ -1,3 +1,3 @@
1
1
  class HalClient
2
- VERSION = "3.1.2"
2
+ VERSION = "3.2.0"
3
3
  end
data/lib/hal_client.rb CHANGED
@@ -15,6 +15,8 @@ class HalClient
15
15
  autoload :HttpClientError, 'hal_client/errors'
16
16
  autoload :HttpServerError, 'hal_client/errors'
17
17
 
18
+ autoload :RepresentationEditor, 'hal_client/representation_editor'
19
+
18
20
  # Initializes a new client instance
19
21
  #
20
22
  # options - hash of configuration options
@@ -79,6 +81,36 @@ class HalClient
79
81
  interpret_response client_for_post(override_headers: headers).post(url, body: req_body)
80
82
  end
81
83
 
84
+ # Put a `Representation` or `String` to the resource identified at `url`.
85
+ #
86
+ # url - The URL of the resource of interest.
87
+ # data - a `String` or an object that responds to `#to_hal`
88
+ # headers - custom header fields to use for this request
89
+ def put(url, data, headers={})
90
+ req_body = if data.respond_to? :to_hal
91
+ data.to_hal
92
+ else
93
+ data
94
+ end
95
+
96
+ interpret_response client_for_post(override_headers: headers).put(url, body: req_body)
97
+ end
98
+
99
+ # Patch a `Representation` or `String` to the resource identified at `url`.
100
+ #
101
+ # url - The URL of the resource of interest.
102
+ # data - a `String` or an object that responds to `#to_hal`
103
+ # headers - custom header fields to use for this request
104
+ def patch(url, data, headers={})
105
+ req_body = if data.respond_to? :to_hal
106
+ data.to_hal
107
+ else
108
+ data
109
+ end
110
+
111
+ interpret_response client_for_post(override_headers: headers).patch(url, body: req_body)
112
+ end
113
+
82
114
  protected
83
115
 
84
116
  attr_reader :headers
@@ -0,0 +1,163 @@
1
+ require_relative "../spec_helper"
2
+ require "hal_client/representation_editor"
3
+
4
+ RSpec.describe HalClient::RepresentationEditor do
5
+ describe "creation" do
6
+ it "take a representation" do
7
+ expect(described_class.new(a_repr)).to be_kind_of described_class
8
+ end
9
+ end
10
+
11
+ subject { described_class.new(a_repr) }
12
+
13
+ specify { expect(subject.to_hal).to be_equivalent_json_to raw_hal }
14
+ specify { expect(subject.to_json).to be_equivalent_json_to raw_hal }
15
+
16
+ describe "#reject_links" do
17
+ specify { expect(subject.reject_links("up")).not_to have_link "up" }
18
+
19
+ it "removes links matching block but not others" do
20
+ altered = subject.reject_links("up") {|repr| %r|/c1$| === repr.href }
21
+
22
+ expect(altered).not_to have_link "up", with_href("http://example.com/c1")
23
+ expect(altered).to have_link "up", with_href("http://example.com/c2")
24
+ end
25
+
26
+ specify { expect(subject.reject_links("absent-rel")).to be_equivalent_json_to raw_hal }
27
+ specify { expect(subject.reject_links("about") {|repr| %r|/another$| === repr.href })
28
+ .not_to have_link "about" }
29
+ end
30
+
31
+ describe "#reject_embedded" do
32
+ specify { expect(subject.reject_embedded("replies"))
33
+ .not_to have_embedded "replies" }
34
+ specify { expect(subject.reject_embedded("absent-rel"))
35
+ .to be_equivalent_json_to raw_hal }
36
+
37
+ it "removes links matching block but not others" do
38
+ altered = subject.reject_embedded("replies") {|repr| "+1" == repr.property("value") }
39
+
40
+ expect(altered).not_to have_embedded "replies", hash_including("value" => "+1")
41
+ expect(altered).to have_embedded "replies", hash_including("value" => "-1")
42
+ end
43
+ end
44
+
45
+ describe "#reject_related" do
46
+ it "rejects from links section" do
47
+ altered = subject.reject_related("up")
48
+
49
+ expect(altered).not_to have_link("up")
50
+ expect(altered).not_to have_embedded("up")
51
+ end
52
+
53
+ it "rejects from links section matching block" do
54
+ altered = subject.reject_related("up") { |it| %r|/c1$| === it.href }
55
+
56
+ expect(altered).not_to have_link "up", with_href("http://example.com/c1")
57
+ expect(altered).to have_link "up", with_href("http://example.com/c2")
58
+ expect(altered).not_to have_embedded("up")
59
+ end
60
+
61
+
62
+ it "rejects from embedded section" do
63
+ altered = subject.reject_related("replies")
64
+
65
+ expect(altered).not_to have_link("replies")
66
+ expect(altered).not_to have_embedded("replies")
67
+ end
68
+
69
+ it "rejects from embedded section matching block" do
70
+ altered = subject.reject_related("replies") {|it| it["value"] == "+1" }
71
+
72
+ expect(altered).not_to have_link("replies", hash_including("value" => "+1"))
73
+ expect(altered).not_to have_embedded("replies", hash_including("value" => "+1"))
74
+
75
+ expect(altered).to have_link("replies", hash_including("value" => "-1"))
76
+ .or(have_embedded("replies", hash_including("value" => "-1")))
77
+
78
+ end
79
+
80
+ specify { expect(subject.reject_related("absent-rel"))
81
+ .to be_equivalent_json_to raw_hal }
82
+
83
+ end
84
+
85
+ describe "#add_link" do
86
+ it "adds brand new link rel" do
87
+ expect(subject.add_link("related", "http://example.com/third"))
88
+ .to have_link("related", with_href("http://example.com/third")
89
+ .and(not_templated))
90
+ end
91
+
92
+ it "adds without replacing existing links" do
93
+ expect(subject.add_link("about", "http://example.com/third"))
94
+ .to have_link("about", with_href("http://example.com/third"))
95
+ .and have_link("about", with_href("http://example.com/another"))
96
+ end
97
+
98
+ it "adds templated links" do
99
+ expect(subject.add_link("related", "http://example.com/third{?wat}", templated: true))
100
+ .to have_link "related", with_href("http://example.com/third{?wat}")
101
+ .and(be_templated)
102
+ end
103
+ end
104
+
105
+ # Background
106
+
107
+ let(:a_repr) { HalClient::Representation
108
+ .new(parsed_json: MultiJson.load(raw_hal)) }
109
+
110
+ let(:raw_hal) { <<-HAL }
111
+ { "_links": {
112
+ "self" : { "href": "http://example.com/a_repr" }
113
+ ,"up" : [{ "href": "http://example.com/c1" },
114
+ { "href": "http://example.com/c2" }]
115
+ ,"about": { "href": "http://example.com/another" }
116
+ }
117
+ ,"_embedded": {
118
+ "replies": [
119
+ { "value": "+1" }
120
+ ,{"value": "-1" }
121
+ ]
122
+ }
123
+ }
124
+ HAL
125
+
126
+ ANYTHING = ->(_) { true }
127
+
128
+ matcher :be_templated do
129
+ match do |actual|
130
+ true == actual["templated"]
131
+ end
132
+ end
133
+
134
+ matcher :not_templated do
135
+ match do |actual|
136
+ true != actual["templated"]
137
+ end
138
+ end
139
+
140
+ matcher :with_href do |expected_url|
141
+ match do |actual|
142
+ expected_url === actual["href"]
143
+ end
144
+ end
145
+
146
+ matcher :have_link do |expected_rel, expected_target=ANYTHING|
147
+ match do |actual_json|
148
+ parsed = MultiJson.load(actual_json.to_hal)
149
+
150
+ [parsed["_links"].fetch(expected_rel, [])].flatten
151
+ .any?{|l| expected_target === l }
152
+ end
153
+ end
154
+
155
+ matcher :have_embedded do |expected_rel, expected_target=ANYTHING|
156
+ match do |actual_json|
157
+ parsed = MultiJson.load(actual_json.to_hal)
158
+
159
+ [parsed["_embedded"].fetch(expected_rel, [])].flatten
160
+ .any?{|e| expected_target === e }
161
+ end
162
+ end
163
+ end
@@ -81,6 +81,42 @@ describe HalClient::RepresentationSet do
81
81
  end
82
82
  end
83
83
 
84
+ describe "#put" do
85
+ context "with a single representation" do
86
+ subject(:repr_single_set) { described_class.new([foo_repr]) }
87
+ let!(:put_request) { stub_request(:put, "example.com/foo") }
88
+
89
+ before(:each) do
90
+ repr_single_set.put("abc")
91
+ end
92
+
93
+ it "makes an HTTP PUT with the data within the representation" do
94
+ expect(
95
+ put_request.
96
+ with(:body => "abc", :headers => {'Content-Type' => 'application/hal+json'})
97
+ ).to have_been_made
98
+ end
99
+ end
100
+ end
101
+
102
+ describe "#patch" do
103
+ context "with a single representation" do
104
+ subject(:repr_single_set) { described_class.new([foo_repr]) }
105
+ let!(:patch_request) { stub_request(:patch, "example.com/foo") }
106
+
107
+ before(:each) do
108
+ repr_single_set.patch("abc")
109
+ end
110
+
111
+ it "makes an HTTP PATCH with the data within the representation" do
112
+ expect(
113
+ patch_request.
114
+ with(:body => "abc", :headers => {'Content-Type' => 'application/hal+json'})
115
+ ).to have_been_made
116
+ end
117
+ end
118
+ end
119
+
84
120
  let(:a_client) { HalClient.new }
85
121
 
86
122
  let(:foo_repr) { HalClient::Representation.new hal_client: a_client, parsed_json: MultiJson.load(foo_hal)}
@@ -25,11 +25,11 @@ HAL
25
25
 
26
26
  describe "#post" do
27
27
  let!(:post_request) {
28
- stub_request(:post, "example.com/bar")
28
+ stub_request(:post, repr.href)
29
29
  }
30
30
 
31
31
  before(:each) do
32
- repr.related("link1").post("abc")
32
+ repr.post("abc")
33
33
  end
34
34
 
35
35
  specify("makes request") {
@@ -39,6 +39,38 @@ HAL
39
39
  }
40
40
  end
41
41
 
42
+ describe "#put" do
43
+ let!(:put_request) {
44
+ stub_request(:put, repr.href)
45
+ }
46
+
47
+ before(:each) do
48
+ repr.put("abc")
49
+ end
50
+
51
+ specify("makes request") {
52
+ expect(put_request.with(:body => "abc",
53
+ :headers => {'Content-Type' => 'application/hal+json'}))
54
+ .to have_been_made
55
+ }
56
+ end
57
+
58
+ describe "#patch" do
59
+ let!(:patch_request) {
60
+ stub_request(:patch, repr.href)
61
+ }
62
+
63
+ before(:each) do
64
+ repr.patch("abc")
65
+ end
66
+
67
+ specify("makes request") {
68
+ expect(patch_request.with(:body => "abc",
69
+ :headers => {'Content-Type' => 'application/hal+json'}))
70
+ .to have_been_made
71
+ }
72
+ end
73
+
42
74
  describe "#to_s" do
43
75
  subject(:return_val) { repr.to_s }
44
76
 
@@ -173,6 +205,10 @@ HAL
173
205
  specify { expect(subject.has_related? "no-such-link-or-embed").to be false }
174
206
  specify { expect(subject.related? "no-such-link-or-embed").to be false }
175
207
 
208
+ specify { expect(subject.to_json).to be_equivalent_json_to raw_repr }
209
+ specify { expect(subject.to_hal).to be_equivalent_json_to raw_repr }
210
+
211
+
176
212
  context "curie links" do
177
213
  let(:raw_repr) { <<-HAL }
178
214
  { "_links": {
@@ -270,6 +306,7 @@ HAL
270
306
  "Expected representation of <#{url}> but found only #{repr_set.map(&:href)}"
271
307
  }
272
308
  end
309
+
273
310
  end
274
311
 
275
312
  describe HalClient::Representation, "w/o hal_client" do
@@ -294,4 +331,6 @@ describe HalClient::Representation, "w/o hal_client" do
294
331
  }
295
332
  }
296
333
  HAL
334
+
335
+
297
336
  end
data/spec/spec_helper.rb CHANGED
@@ -4,3 +4,9 @@ require 'rspec'
4
4
  require 'webmock/rspec'
5
5
  require 'multi_json'
6
6
  require 'rspec/collection_matchers'
7
+
8
+ require 'support/custom_matchers'
9
+
10
+ RSpec.configure do |config|
11
+ config.include CustomMatchers
12
+ end
@@ -0,0 +1,19 @@
1
+ module CustomMatchers
2
+ extend RSpec::Matchers::DSL
3
+
4
+ matcher :be_equivalent_json_to do |expected_json|
5
+ match do |actual_json|
6
+ MultiJson.load(json(expected_json)) == MultiJson.load(json(actual_json))
7
+ end
8
+
9
+ protected
10
+
11
+ def json(jsonish)
12
+ if String === jsonish
13
+ jsonish
14
+ else
15
+ jsonish.to_json
16
+ end
17
+ end
18
+ end
19
+ end
metadata CHANGED
@@ -1,148 +1,131 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hal-client
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.1.2
5
- prerelease:
4
+ version: 3.2.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Peter Williams
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2014-09-19 00:00:00.000000000 Z
11
+ date: 2014-11-17 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: http
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ~>
17
+ - - "~>"
20
18
  - !ruby/object:Gem::Version
21
19
  version: 0.6.1
22
20
  type: :runtime
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ~>
24
+ - - "~>"
28
25
  - !ruby/object:Gem::Version
29
26
  version: 0.6.1
30
27
  - !ruby/object:Gem::Dependency
31
28
  name: addressable
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ~>
31
+ - - "~>"
36
32
  - !ruby/object:Gem::Version
37
33
  version: '2.3'
38
34
  type: :runtime
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ~>
38
+ - - "~>"
44
39
  - !ruby/object:Gem::Version
45
40
  version: '2.3'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: multi_json
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ~>
45
+ - - "~>"
52
46
  - !ruby/object:Gem::Version
53
47
  version: '1.9'
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ~>
52
+ - - "~>"
60
53
  - !ruby/object:Gem::Version
61
54
  version: '1.9'
62
55
  - !ruby/object:Gem::Dependency
63
56
  name: bundler
64
57
  requirement: !ruby/object:Gem::Requirement
65
- none: false
66
58
  requirements:
67
- - - ~>
59
+ - - "~>"
68
60
  - !ruby/object:Gem::Version
69
61
  version: '1.5'
70
62
  type: :development
71
63
  prerelease: false
72
64
  version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
65
  requirements:
75
- - - ~>
66
+ - - "~>"
76
67
  - !ruby/object:Gem::Version
77
68
  version: '1.5'
78
69
  - !ruby/object:Gem::Dependency
79
70
  name: rake
80
71
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
72
  requirements:
83
- - - ~>
73
+ - - "~>"
84
74
  - !ruby/object:Gem::Version
85
75
  version: '10.1'
86
76
  type: :development
87
77
  prerelease: false
88
78
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
79
  requirements:
91
- - - ~>
80
+ - - "~>"
92
81
  - !ruby/object:Gem::Version
93
82
  version: '10.1'
94
83
  - !ruby/object:Gem::Dependency
95
84
  name: rspec
96
85
  requirement: !ruby/object:Gem::Requirement
97
- none: false
98
86
  requirements:
99
- - - ~>
87
+ - - "~>"
100
88
  - !ruby/object:Gem::Version
101
89
  version: 3.0.0.beta
102
90
  type: :development
103
91
  prerelease: false
104
92
  version_requirements: !ruby/object:Gem::Requirement
105
- none: false
106
93
  requirements:
107
- - - ~>
94
+ - - "~>"
108
95
  - !ruby/object:Gem::Version
109
96
  version: 3.0.0.beta
110
97
  - !ruby/object:Gem::Dependency
111
98
  name: webmock
112
99
  requirement: !ruby/object:Gem::Requirement
113
- none: false
114
100
  requirements:
115
- - - ~>
101
+ - - "~>"
116
102
  - !ruby/object:Gem::Version
117
103
  version: '1.17'
118
- - - ! '>='
104
+ - - ">="
119
105
  - !ruby/object:Gem::Version
120
106
  version: 1.17.4
121
107
  type: :development
122
108
  prerelease: false
123
109
  version_requirements: !ruby/object:Gem::Requirement
124
- none: false
125
110
  requirements:
126
- - - ~>
111
+ - - "~>"
127
112
  - !ruby/object:Gem::Version
128
113
  version: '1.17'
129
- - - ! '>='
114
+ - - ">="
130
115
  - !ruby/object:Gem::Version
131
116
  version: 1.17.4
132
117
  - !ruby/object:Gem::Dependency
133
118
  name: rspec-collection_matchers
134
119
  requirement: !ruby/object:Gem::Requirement
135
- none: false
136
120
  requirements:
137
- - - ! '>='
121
+ - - ">="
138
122
  - !ruby/object:Gem::Version
139
123
  version: '0'
140
124
  type: :development
141
125
  prerelease: false
142
126
  version_requirements: !ruby/object:Gem::Requirement
143
- none: false
144
127
  requirements:
145
- - - ! '>='
128
+ - - ">="
146
129
  - !ruby/object:Gem::Version
147
130
  version: '0'
148
131
  description: An easy to use interface for REST APIs that use HAL.
@@ -152,8 +135,8 @@ executables: []
152
135
  extensions: []
153
136
  extra_rdoc_files: []
154
137
  files:
155
- - .gitignore
156
- - .travis.yml
138
+ - ".gitignore"
139
+ - ".travis.yml"
157
140
  - Gemfile
158
141
  - LICENSE.txt
159
142
  - README.md
@@ -166,51 +149,50 @@ files:
166
149
  - lib/hal_client/errors.rb
167
150
  - lib/hal_client/links_section.rb
168
151
  - lib/hal_client/representation.rb
152
+ - lib/hal_client/representation_editor.rb
169
153
  - lib/hal_client/representation_set.rb
170
154
  - lib/hal_client/version.rb
171
155
  - spec/hal_client/collection_spec.rb
172
156
  - spec/hal_client/curie_resolver_spec.rb
173
157
  - spec/hal_client/links_section_spec.rb
158
+ - spec/hal_client/representation_editor_spec.rb
174
159
  - spec/hal_client/representation_set_spec.rb
175
160
  - spec/hal_client/representation_spec.rb
176
161
  - spec/hal_client_spec.rb
177
162
  - spec/spec_helper.rb
163
+ - spec/support/custom_matchers.rb
178
164
  homepage: https://github.com/pezra/hal-client
179
165
  licenses:
180
166
  - MIT
167
+ metadata: {}
181
168
  post_install_message:
182
169
  rdoc_options: []
183
170
  require_paths:
184
171
  - lib
185
172
  required_ruby_version: !ruby/object:Gem::Requirement
186
- none: false
187
173
  requirements:
188
- - - ! '>='
174
+ - - ">="
189
175
  - !ruby/object:Gem::Version
190
176
  version: '0'
191
- segments:
192
- - 0
193
- hash: 916239915633512664
194
177
  required_rubygems_version: !ruby/object:Gem::Requirement
195
- none: false
196
178
  requirements:
197
- - - ! '>='
179
+ - - ">="
198
180
  - !ruby/object:Gem::Version
199
181
  version: '0'
200
- segments:
201
- - 0
202
- hash: 916239915633512664
203
182
  requirements: []
204
183
  rubyforge_project:
205
- rubygems_version: 1.8.23
184
+ rubygems_version: 2.2.2
206
185
  signing_key:
207
- specification_version: 3
186
+ specification_version: 4
208
187
  summary: Use HAL APIs easily
209
188
  test_files:
210
189
  - spec/hal_client/collection_spec.rb
211
190
  - spec/hal_client/curie_resolver_spec.rb
212
191
  - spec/hal_client/links_section_spec.rb
192
+ - spec/hal_client/representation_editor_spec.rb
213
193
  - spec/hal_client/representation_set_spec.rb
214
194
  - spec/hal_client/representation_spec.rb
215
195
  - spec/hal_client_spec.rb
216
196
  - spec/spec_helper.rb
197
+ - spec/support/custom_matchers.rb
198
+ has_rdoc: