flexirest 1.9.18 → 1.10.4

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
  SHA256:
3
- metadata.gz: 4a602c593b7748bb16605a196b249920ad733152fee9c7969fa56445b8c07003
4
- data.tar.gz: 1e75b70398bcc73ee2fbd68a169c9f30ed1cbdd968e2f0d74272a1ed1b254737
3
+ metadata.gz: 9a072753fe6a84d8f13ae90d26cdff777e78fc129d4555b5188ae0c0be35ad78
4
+ data.tar.gz: 7e6ecfe247cc9f021a3e35f9cf4d3b28a6743694b53a2ca32c0ea988a2113276
5
5
  SHA512:
6
- metadata.gz: 1d868df5a25277b88e0482e5cae4ba4398aa0ae4082766321988172365d7e1d955f6254f4a29eccd927f6d95d3734e81333f55760c1fbc0847f1ba6a249ae922
7
- data.tar.gz: 2710c351b4f5770a4cc177d5ca7509aff9e988ff7b89a892bf4f57c35bb5834c5f41ca193ae22023b15de71118b19799c52491682dad86d041fd21dad9773a32
6
+ metadata.gz: 561fdb72c84a9bd3d0a353f46d4761179df66f3e45967bec4b4b620c6f818dca0058388b5f83c2d2455da1f21fa90a72ec0f73ab056fbf086dab522cc8f48fd7
7
+ data.tar.gz: 95d6f2852392a23c82a5ae0e157a9ad1bc391c4846e79946eab75236c1c3b409c8193a3550e42b9e19676b94a3cccda28e6f0ddf438e47b3e77de9c66669006a
data/CHANGELOG.md CHANGED
@@ -1,5 +1,35 @@
1
1
  # Changelog
2
2
 
3
+ ## 1.10.4
4
+
5
+ Enhancement:
6
+
7
+ - Implement support for in-header Basic Auth (thanks to François Ferrandis for the PR)
8
+
9
+ ## 1.10.3
10
+
11
+ Enhancement:
12
+
13
+ - Ignore/wrap root functionality available for all routes, rather than just route specifically (thanks to Sampat Badhe for the PR)
14
+
15
+ ## 1.10.2
16
+
17
+ Bugfix:
18
+
19
+ - JSON-API calls do not include linked resources when no other parameter is passed (thanks to Stevo-S for the bug report and François Ferrandis for the PR)
20
+
21
+ ## 1.10.1
22
+
23
+ Enhancement:
24
+
25
+ - Nested objects now report their dirty/changed status up to the parent (thanks to Matthias Hähnel for the bug report)
26
+
27
+ ## 1.10.0
28
+
29
+ Enhancement:
30
+
31
+ - Add specific exceptions for the most common 5xx server-side errors
32
+
3
33
  ## 1.9.18
4
34
 
5
35
  Security:
@@ -40,6 +40,30 @@ Or if it's called from a class context:
40
40
  Person.find(id: 1234)
41
41
  ```
42
42
 
43
+ ### Basic authentication method
44
+
45
+ Flexirest provides two methods for HTTP Basic Auth. The default method is `:url`:
46
+
47
+ ```ruby
48
+ class Person < Flexirest::Base
49
+ basic_auth_method :url
50
+ end
51
+ # Includes the credentials in the URL:
52
+ # https://my_username:my_password@example.com/
53
+ ```
54
+
55
+ But you might want to keep the credentials out of your logs and use the `:header` method:
56
+
57
+ ```ruby
58
+ class Person < Flexirest::Base
59
+ basic_auth_method :header
60
+ end
61
+ # Clean URL:
62
+ # https://example.com/
63
+ # with the base64 encoded credentials:
64
+ # Authorization: Basic YXBpOmViNjkzZWMtODI1MmMtZDYzMDEtMDJmZDAtZDBmYjctYzM0ODU=
65
+ ```
66
+
43
67
  ## Api-Auth
44
68
 
45
69
  Using the [Api-Auth](https://github.com/mgomes/api_auth) integration it is very easy to sign requests. Include the Api-Auth gem in your `Gemfile` and then add it to your application. Then simply configure Api-Auth one time in your app and all requests will be signed from then on.
@@ -1,6 +1,6 @@
1
1
  # *Flexirest:* Filtering result lists
2
2
 
3
- If the API returns a JSON list of items, this is retured to you as a `Flexirest::ResultIterator` object. A `ResultIterator` sorts simple filtering of the list using a `where` method based on values matching a specified criteria (or matching using regular expressions):
3
+ If the API returns a JSON list of items, this is returned to you as a `Flexirest::ResultIterator` object. A `ResultIterator` sorts simple filtering of the list using a `where` method based on values matching a specified criteria (or matching using regular expressions):
4
4
 
5
5
  ```ruby
6
6
  class Article < Flexirest::Base
data/docs/json-api.md CHANGED
@@ -12,17 +12,26 @@ This proxy translates requests according to the JSON API specifications, parses
12
12
 
13
13
  It supports lazy loading by default. Unless a compound document is returned from the connected JSON API service, it will make another request to the service for the specified linked resource.
14
14
 
15
+
16
+ ## Including associations
17
+
15
18
  To reduce the number of requests to the service, you can ask the service to include the linked resources in the response. Such responses are called "compound documents". To do this, use the `includes` method:
16
19
 
17
20
  ```ruby
18
- # Makes a call to /articles with parameters: include=images
21
+ # Makes a call to: /articles?include=images
19
22
  Article.includes(:images).all
20
23
 
21
- # For nested resources, the include parameter becomes: include=images.tags,images.photographer
24
+ # Fetch nested resources: /articles?include=images.tags,images.photographer
22
25
  Article.includes(:images => [:tags, :photographer]).all
26
+
27
+ # Note: the `includes` method takes precedence over the passed `:include` parameter.
28
+ # This will result in query: /articles?include=images
29
+ Article.includes(:images).all(include: "author")
23
30
  ```
24
31
 
25
- For POST and PATCH requests, the proxy formats a JSON API compliant request, and adds a `Content-Type: application/vnd.api+json` header. It guesses the `type` value in the resource object from the class name, but it can be set specifically with `alias_type`:
32
+ ## Resource type
33
+
34
+ The `type` value is guessed from the class name, but it can be set specifically with `alias_type`:
26
35
 
27
36
  ```ruby
28
37
  class Photographer < Flexirest::Base
@@ -34,7 +43,10 @@ class Photographer < Flexirest::Base
34
43
  end
35
44
  ```
36
45
 
37
- NB: Updating relationships is not yet supported.
46
+
47
+ ## Notes
48
+
49
+ Updating relationships is not yet supported.
38
50
 
39
51
 
40
52
  -----
@@ -7,7 +7,7 @@ class Person < Flexirest::Base
7
7
  end
8
8
 
9
9
  people = Person._plain_request('http://api.example.com/v1/people') # Defaults to get with no parameters
10
- # people is a normal Flexirest object, implementing iteration, HAL loading, etc.
10
+ # people is a string containing the response
11
11
 
12
12
  Person._plain_request('http://api.example.com/v1/people', :post, {id:1234,name:"John"}) # Post with parameters
13
13
  ```
@@ -40,7 +40,7 @@ Article.all.first_name == "Billy"
40
40
  This example does two things:
41
41
 
42
42
  1. It rewrites the incoming URL for any requests matching "_/all_" to "/all_people"
43
- 2. It uses the `translate` method to move the "fname" attribute from the response body to be called "first_name". The translate method must return the new object at the end (either the existing object alterered, or a new object to replace it with)
43
+ 2. It uses the `translate` method to move the "fname" attribute from the response body to be called "first_name". The translate method must return the new object at the end (either the existing object altered, or a new object to replace it with)
44
44
 
45
45
  As the comment shows, you can use `url value` to set the request URL to a particular value, or you can call `gsub!` on the url to replace parts of it using more complicated regular expressions.
46
46
 
data/docs/raw-requests.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # *Flexirest:* Raw requests
2
2
 
3
- Sometimes you have have a URL that you just want to force through, but have the response handled in the same way as normal objects or you want to have the callbacks run (say for authentication). The easiest way to do that is to call `_request` on the class:
3
+ Sometimes you have a URL that you just want to force through, but have the response handled in the same way as normal objects or you want to have the callbacks run (say for authentication). The easiest way to do that is to call `_request` on the class:
4
4
 
5
5
  ```ruby
6
6
  class Person < Flexirest::Base
@@ -12,7 +12,7 @@ people = Person._request('http://api.example.com/v1/people') # Defaults to get w
12
12
  Person._request('http://api.example.com/v1/people', :post, {id:1234,name:"John"}) # Post with parameters
13
13
  ```
14
14
 
15
- When you need to specify custom headers (for example for authentication) you can do this with a fourth option to the `_request` method. If you are using the default paramaters you'll need to specify them. For example:
15
+ When you need to specify custom headers (for example for authentication) you can do this with a fourth option to the `_request` method. If you are using the default parameters you'll need to specify them. For example:
16
16
 
17
17
  ```ruby
18
18
  Person._request("http://api.example.com/v1/people", :get, {}, {headers:{"X-Something": "foo/bar"}})
@@ -2,13 +2,32 @@
2
2
 
3
3
  If your response comes back with a root node and you'd like to ignore it, you can define the mapping as:
4
4
 
5
+ ```ruby
6
+ Flexirest::Base.ignore_root = "data"
7
+ ```
8
+
9
+ Any `ignore_root` setting in specific class overrides this declared default.
10
+
5
11
  ```ruby
6
12
  class Feed < Flexirest::Base
7
- post :list, "/feed", ignore_root: "feed"
13
+ ignore_root: "feed"
14
+
15
+ post :list, "/feed"
16
+ end
17
+ ```
18
+
19
+ And any `ignore_root` setting in specific request overrides the both default and class specific setting.
20
+
21
+
22
+ ```ruby
23
+ class Feed < Flexirest::Base
24
+ ignore_root: 'feed'
25
+
26
+ post :list, "/feed", ignore_root: "result"
8
27
  end
9
28
  ```
10
29
 
11
- This also works if you'd want to remove a tree of root nodes:
30
+ You can also assign an array to `ignore_root` if you'd want to remove a tree of root nodes.
12
31
 
13
32
  ```ruby
14
33
  class Feed < Flexirest::Base
@@ -26,16 +45,32 @@ Alternatively if you want to wrap your JSON request body in a root element, e.g.
26
45
  }
27
46
  ```
28
47
 
29
- You can do it like this:
48
+ You can do it using `wrap_root`:
49
+
50
+ ```ruby
51
+ Flexirest::Base.wrap_root = "data"
52
+ ```
53
+
54
+ Any `wrap_root` setting in specific class overrides this declared default.
30
55
 
31
56
  ```ruby
32
57
  class Feed < Flexirest::Base
33
- post :list, "/feed", wrap_root: "feed"
34
- end
58
+ wrap_root: "feed"
35
59
 
36
- Feed.list(id: 1)
60
+ post :list, "/feed"
61
+ end
37
62
  ```
38
63
 
64
+ And any `wrap_root` setting in specific request overrides the both default and class specific setting.
65
+
66
+
67
+ ```ruby
68
+ class Feed < Flexirest::Base
69
+ wrap_root: 'feed'
70
+
71
+ post :list, "/feed", wrap_root: "data"
72
+ end
73
+ ```
39
74
 
40
75
  -----
41
76
 
@@ -66,6 +66,7 @@ After callbacks work in exactly the same way:
66
66
  ```ruby
67
67
  class Person < Flexirest::Base
68
68
  get :all, "/people"
69
+ get :all, "/people"
69
70
 
70
71
  after_request :fix_empty_content
71
72
  after_request :cache_all_people
@@ -88,6 +89,32 @@ end
88
89
 
89
90
  **Note:** since v1.3.21 the empty response trick above isn't necessary, empty responses for 204 are accepted normally (the method returns `true`), but this is here to show an example of an `after_request` callback adjusting the body. The `cache_all_people` example shows how to cache a response even if the server doesn't send the correct headers.
90
91
 
92
+ If you manually set caching responses like the above, you may want to invalidate that cache when you make a create, update, delete etc request for the resource, for example:
93
+
94
+ ```ruby
95
+ class Animal < Flexirest::Base
96
+ after_request :cache
97
+ before_request :cache_cleanup
98
+
99
+ get :get, '/animals/:id'
100
+ post :update, '/animals/:id'
101
+ delete :delete, '/animals/:id'
102
+
103
+ def cache_cleanup(name, request)
104
+ if name == :update || name == :delete
105
+ Flexirest::Logger.info(" \033[1;4;32m#{Flexirest.name}\033[0m Invalidating cache for #{self.class.name} #{request.url}")
106
+ Rails.cache.delete("#{self.class.name}:#{request.url}")
107
+ end
108
+ end
109
+
110
+ def cache(name, response)
111
+ if name == :get
112
+ response.response_headers["Expires"] = 1.hour.from_now.iso8601
113
+ end
114
+ end
115
+ end
116
+ ```
117
+
91
118
  If you want to trap an error in an `after_request` callback and retry the request, this can be done - but retries will only happen once for each request (so we'd recommend checking all conditions in a single `after_request` and then retrying after fixing them all). You achieve this by raising a `Flexirest::CallbackRetryRequestException` from the callback.
92
119
 
93
120
  ```ruby
@@ -100,7 +127,7 @@ class Person < Flexirest::Base
100
127
 
101
128
  def fix_invalid_request(name, response)
102
129
  if response.status == 401
103
- # Do something to fix the state of caches/variables used in the
130
+ # Do something to fix the state of caches/variables used in the
104
131
  # before_request, etc
105
132
  raise Flexirest::CallbackRetryRequestException.new
106
133
  end
data/flexirest.gemspec CHANGED
@@ -39,7 +39,7 @@ Gem::Specification.new do |spec|
39
39
  spec.add_development_dependency "api-auth", ">= 1.3.1", "< 2.4"
40
40
  spec.add_development_dependency 'typhoeus'
41
41
  spec.add_development_dependency 'activemodel'
42
- spec.add_development_dependency 'rest-client', ">= 1.8.0"
42
+ spec.add_development_dependency 'rest-client'
43
43
 
44
44
  spec.add_runtime_dependency "mime-types"
45
45
  spec.add_runtime_dependency "multi_json"
@@ -53,12 +53,4 @@ Gem::Specification.new do |spec|
53
53
  else
54
54
  spec.add_runtime_dependency "activesupport", "< 5.0.0"
55
55
  end
56
- # JSON is an implicit dependency of something, but JSON v2+ requires Ruby 2+
57
- # Same with "tins" which is a dependency of coveralls
58
- if Gem::Version.new(RUBY_VERSION) < Gem::Version.new('2.0.0')
59
- spec.add_runtime_dependency "json", "< 2.0.0"
60
- spec.add_runtime_dependency "tins", "~> 1.6.0"
61
- spec.add_runtime_dependency "term-ansicolor", "~> 1.3.2"
62
- spec.add_runtime_dependency "public_suffix", "~> 1.4.6"
63
- end
64
56
  end
@@ -11,6 +11,8 @@ module Flexirest
11
11
  attr_accessor :_status
12
12
  attr_accessor :_etag
13
13
  attr_accessor :_headers
14
+ attr_accessor :_parent
15
+ attr_accessor :_parent_attribute_name
14
16
 
15
17
  instance_methods.each do |m|
16
18
  next unless %w{display presence load require untrust trust freeze method enable_warnings with_warnings suppress capture silence quietly debugger breakpoint}.map(&:to_sym).include? m
@@ -41,6 +43,13 @@ module Flexirest
41
43
  def _copy_from(result)
42
44
  @attributes = result._attributes
43
45
  @_status = result._status
46
+ self._parent = result._parent
47
+ self._parent_attribute_name = result._parent_attribute_name
48
+ @attributes.each do |k,v|
49
+ if v.respond_to?(:_parent) && v._parent.present?
50
+ @attributes[k]._parent = self
51
+ end
52
+ end
44
53
  _clean!
45
54
  end
46
55
 
@@ -184,6 +193,10 @@ module Flexirest
184
193
  output.to_json
185
194
  end
186
195
 
196
+ def _set_dirty(key)
197
+ @dirty_attributes[key.to_sym] = true
198
+ end
199
+
187
200
  private
188
201
 
189
202
  def _set_attribute(key, value)
@@ -191,6 +204,9 @@ module Flexirest
191
204
  old_value = @attributes[key.to_sym] unless old_value
192
205
  old_value = old_value[0] if old_value and old_value.is_a? Array
193
206
  @dirty_attributes[key.to_sym] = [old_value, value] if old_value != value
207
+ if _parent
208
+ _parent._set_dirty(_parent_attribute_name)
209
+ end
194
210
  @attributes[key.to_sym] = value
195
211
  end
196
212
 
@@ -13,6 +13,32 @@ module Flexirest
13
13
  @api_auth_access_id = nil
14
14
  @api_auth_secret_key = nil
15
15
  @api_auth_options = {}
16
+ @ignore_root = nil
17
+ @wrap_root = nil
18
+
19
+ def ignore_root(value=nil)
20
+ if value.nil?
21
+ value = if @ignore_root.nil? && superclass.respond_to?(:ignore_root)
22
+ superclass.ignore_root
23
+ else
24
+ @ignore_root
25
+ end
26
+ else
27
+ @ignore_root = value
28
+ end
29
+ end
30
+
31
+ def wrap_root(value=nil)
32
+ if value.nil?
33
+ value = if @wrap_root.nil? && superclass.respond_to?(:wrap_root)
34
+ superclass.wrap_root
35
+ else
36
+ @wrap_root
37
+ end
38
+ else
39
+ @wrap_root = value
40
+ end
41
+ end
16
42
 
17
43
  def base_url(value = nil)
18
44
  @base_url ||= nil
@@ -109,6 +135,23 @@ module Flexirest
109
135
  @@password = value
110
136
  end
111
137
 
138
+ DEFAULT_BASIC_URL_METHOD = :url
139
+
140
+ def basic_auth_method(value = nil)
141
+ if value.nil? # Used as a getter method
142
+ if @basic_auth_method.nil? && superclass.respond_to?(:basic_auth_method)
143
+ superclass.basic_auth_method
144
+ else
145
+ @basic_auth_method || DEFAULT_BASIC_URL_METHOD
146
+ end
147
+ else # Used as a setter method
148
+ unless [:header, :url].include?(value)
149
+ raise %(Invalid basic_auth_method #{value.inspect}. Valid methods are :url (default) and :header.)
150
+ end
151
+ @basic_auth_method = value
152
+ end
153
+ end
154
+
112
155
  def alias_type(value = nil)
113
156
  @alias_type ||= nil
114
157
  if value.nil?
@@ -285,6 +328,7 @@ module Flexirest
285
328
  @adapter = Faraday.default_adapter
286
329
  @api_auth_access_id = nil
287
330
  @api_auth_secret_key = nil
331
+ @basic_auth_method = :url
288
332
  end
289
333
 
290
334
  private
@@ -50,11 +50,8 @@ module Flexirest
50
50
  end
51
51
 
52
52
  def translate(params, include_associations)
53
- # Return to caller if nothing is to be done
54
- return params unless params.present? && include_associations.present?
55
-
56
53
  # Format the linked resources array, and assign to include key
57
- params[:include] = format_include_params(include_associations)
54
+ params[:include] = format_include_params(include_associations) if include_associations.present?
58
55
  end
59
56
 
60
57
  private
@@ -94,6 +94,10 @@ module Flexirest
94
94
  request = Flexirest::Request.new(method, @request.object)
95
95
  request.url = request.forced_url = @url
96
96
  @object = request.call
97
+ if @object.respond_to?(:_parent=)
98
+ @object._parent = @options[:parent]
99
+ @object._parent_attribute_name = @options[:parent_attribute_name]
100
+ end
97
101
  end
98
102
  end
99
103
  end
@@ -32,6 +32,10 @@ module Flexirest
32
32
  !@object.respond_to?(:dirty?)
33
33
  end
34
34
 
35
+ def model_class
36
+ object_is_class? ? @object : @object.class
37
+ end
38
+
35
39
  def class_name
36
40
  if object_is_class?
37
41
  @object.name
@@ -124,6 +128,18 @@ module Flexirest
124
128
  ret
125
129
  end
126
130
 
131
+ def inject_basic_auth_in_url(url)
132
+ url.gsub!(%r{//(.)}, "//#{username}:#{password}@\\1") if !url[%r{//[^/]*:[^/]*@}]
133
+ end
134
+
135
+ def using_basic_auth?
136
+ !!username
137
+ end
138
+
139
+ def basic_auth_digest
140
+ Base64.strict_encode64("#{username}:#{password}")
141
+ end
142
+
127
143
  def request_body_type
128
144
  if @method[:options][:request_body_type]
129
145
  @method[:options][:request_body_type]
@@ -136,6 +152,30 @@ module Flexirest
136
152
  end
137
153
  end
138
154
 
155
+ def ignore_root
156
+ if @method[:options][:ignore_root]
157
+ @method[:options][:ignore_root]
158
+ elsif @object.nil?
159
+ nil
160
+ elsif object_is_class?
161
+ @object.ignore_root
162
+ else
163
+ @object.class.ignore_root
164
+ end
165
+ end
166
+
167
+ def wrap_root
168
+ if @method[:options][:wrap_root]
169
+ @method[:options][:wrap_root]
170
+ elsif @object.nil?
171
+ nil
172
+ elsif object_is_class?
173
+ @object.wrap_root
174
+ else
175
+ @object.class.wrap_root
176
+ end
177
+ end
178
+
139
179
  def verbose?
140
180
  if object_is_class?
141
181
  @object.verbose
@@ -438,8 +478,8 @@ module Flexirest
438
478
  @post_params
439
479
  else
440
480
  p = (params || @post_params || {})
441
- if @method[:options][:wrap_root].present?
442
- p = {@method[:options][:wrap_root] => p}
481
+ if wrap_root.present?
482
+ p = {wrap_root => p}
443
483
  end
444
484
  p.to_query
445
485
  end
@@ -452,8 +492,8 @@ module Flexirest
452
492
  @post_params
453
493
  else
454
494
  p = (params || @post_params || {})
455
- if @method[:options][:wrap_root].present?
456
- p = {@method[:options][:wrap_root] => p}
495
+ if wrap_root.present?
496
+ p = {wrap_root => p}
457
497
  end
458
498
  data, mp_headers = Flexirest::Multipart::Post.prepare_query(p)
459
499
  mp_headers.each do |k,v|
@@ -467,8 +507,8 @@ module Flexirest
467
507
  elsif @post_params.is_a?(String)
468
508
  @post_params
469
509
  else
470
- if @method[:options][:wrap_root].present?
471
- {@method[:options][:wrap_root] => (params || @post_params || {})}.to_json
510
+ if wrap_root.present?
511
+ {wrap_root => (params || @post_params || {})}.to_json
472
512
  else
473
513
  (params || @post_params || {}).to_json
474
514
  end
@@ -503,7 +543,9 @@ module Flexirest
503
543
  else
504
544
  _, @base_url, @url = parts
505
545
  end
506
- base_url.gsub!(%r{//(.)}, "//#{username}:#{password}@\\1") if username && !base_url[%r{//[^/]*:[^/]*@}]
546
+ if using_basic_auth? && model_class.basic_auth_method == :url
547
+ inject_basic_auth_in_url(base_url)
548
+ end
507
549
  connection = Flexirest::ConnectionManager.get_connection(base_url)
508
550
  end
509
551
  else
@@ -516,7 +558,9 @@ module Flexirest
516
558
  else
517
559
  base_url = parts[0]
518
560
  end
519
- base_url.gsub!(%r{//(.)}, "//#{username}:#{password}@\\1") if username && !base_url[%r{//[^/]*:[^/]*@}]
561
+ if using_basic_auth? && model_class.basic_auth_method == :url
562
+ inject_basic_auth_in_url(base_url)
563
+ end
520
564
  connection = Flexirest::ConnectionManager.get_connection(base_url)
521
565
  end
522
566
  if @method[:options][:direct]
@@ -542,6 +586,8 @@ module Flexirest
542
586
  :api_auth_secret_key => api_auth_secret_key,
543
587
  :api_auth_options => api_auth_options
544
588
  }
589
+ elsif using_basic_auth? && model_class.basic_auth_method == :header
590
+ http_headers["Authorization"] = "Basic #{basic_auth_digest}"
545
591
  end
546
592
  if @method[:options][:timeout]
547
593
  request_options[:timeout] = @method[:options][:timeout]
@@ -601,7 +647,7 @@ module Flexirest
601
647
  else
602
648
  Flexirest::Logger.debug " \033[1;4;32m#{Flexirest.name}\033[0m #{@instrumentation_name} - Response received #{@response.body.size} bytes"
603
649
  end
604
- result = generate_new_object(ignore_root: @method[:options][:ignore_root], ignore_xml_root: @method[:options][:ignore_xml_root])
650
+ result = generate_new_object(ignore_root: ignore_root, ignore_xml_root: @method[:options][:ignore_xml_root])
605
651
  # TODO: Cleanup when ignore_xml_root is removed
606
652
  else
607
653
  raise ResponseParseException.new(status:status, body:@response.body, headers: @response.headers)
@@ -630,6 +676,16 @@ module Flexirest
630
676
  raise HTTPConflictClientException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
631
677
  elsif status == 429
632
678
  raise HTTPTooManyRequestsClientException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
679
+ elsif status == 500
680
+ raise HTTPInternalServerException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
681
+ elsif status == 501
682
+ raise HTTPNotImplementedServerException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
683
+ elsif status == 502
684
+ raise HTTPBadGatewayServerException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
685
+ elsif status == 503
686
+ raise HTTPServiceUnavailableServerException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
687
+ elsif status == 504
688
+ raise HTTPGatewayTimeoutServerException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
633
689
  elsif (400..499).include? status
634
690
  raise HTTPClientException.new(status:status, result:error_response, raw_response: @response.body, url:@url, method: http_method)
635
691
  elsif (500..599).include? status
@@ -641,7 +697,7 @@ module Flexirest
641
697
  result
642
698
  end
643
699
 
644
- def new_object(attributes, name = nil)
700
+ def new_object(attributes, name = nil, parent = nil, parent_attribute_name = nil)
645
701
  @method[:options][:has_many] ||= {}
646
702
  name = name.to_sym rescue nil
647
703
  if @method[:options][:has_many][name]
@@ -654,6 +710,9 @@ module Flexirest
654
710
  object = create_object_instance
655
711
  end
656
712
 
713
+ object._parent = parent
714
+ object._parent_attribute_name = parent_attribute_name
715
+
657
716
  if hal_response? && name.nil?
658
717
  attributes = handle_hal_links_embedded(object, attributes)
659
718
  end
@@ -681,9 +740,9 @@ module Flexirest
681
740
  v = value
682
741
  assignable_hash = value_from_object ? object._attributes : {}
683
742
  if value_from_object && @method[:options][:lazy].include?(k)
684
- assignable_hash[k] = Flexirest::LazyAssociationLoader.new(overridden_name, v, self, overridden_name:(overridden_name))
743
+ assignable_hash[k] = Flexirest::LazyAssociationLoader.new(overridden_name, v, self, overridden_name:(overridden_name), parent: object, parent_attribute_name: k)
685
744
  elsif v.is_a? Hash
686
- assignable_hash[k] = new_object(v, overridden_name )
745
+ assignable_hash[k] = new_object(v, overridden_name, object, k)
687
746
  elsif v.is_a? Array
688
747
  if @method[:options][:array].include?(k)
689
748
  assignable_hash[k] = Array.new
@@ -801,15 +860,15 @@ module Flexirest
801
860
  body = JsonAPIProxy::Response.parse(body, @object)
802
861
  end
803
862
 
804
- if options[:ignore_root]
805
- [options[:ignore_root]].flatten.each do |key|
863
+ if ignore_root
864
+ [ignore_root].flatten.each do |key|
806
865
  body = body[key.to_s]
807
866
  end
808
867
  end
809
868
  elsif is_xml_response?
810
869
  body = @response.body.blank? ? {} : Crack::XML.parse(@response.body)
811
- if options[:ignore_root]
812
- [options[:ignore_root]].flatten.each do |key|
870
+ if ignore_root
871
+ [ignore_root].flatten.each do |key|
813
872
  body = body[key.to_s]
814
873
  end
815
874
  elsif options[:ignore_xml_root]
@@ -901,5 +960,9 @@ module Flexirest
901
960
  class HTTPNotFoundClientException < HTTPClientException ; end
902
961
  class HTTPTooManyRequestsClientException < HTTPClientException ; end
903
962
  class HTTPServerException < HTTPException ; end
904
-
963
+ class HTTPInternalServerException < HTTPServerException ; end
964
+ class HTTPNotImplementedServerException < HTTPServerException ; end
965
+ class HTTPBadGatewayServerException < HTTPServerException ; end
966
+ class HTTPServiceUnavailableServerException < HTTPServerException ; end
967
+ class HTTPGatewayTimeoutServerException < HTTPServerException ; end
905
968
  end
@@ -4,6 +4,8 @@ module Flexirest
4
4
 
5
5
  attr_accessor :_status, :items
6
6
  attr_reader :_headers
7
+ attr_accessor :_parent
8
+ attr_accessor :_parent_attribute_name
7
9
 
8
10
  def initialize(response = nil)
9
11
  @_status = response.try :status
@@ -1,3 +1,3 @@
1
1
  module Flexirest
2
- VERSION = "1.9.18"
2
+ VERSION = "1.10.4"
3
3
  end
@@ -12,6 +12,11 @@ class TranslatorExample
12
12
  end
13
13
  end
14
14
 
15
+ class NestedExample < Flexirest::BaseWithoutValidation
16
+ get :all, "/all", fake:"{\"person\":{\"name\": \"Billy\"}}"
17
+ end
18
+
19
+
15
20
  class AlteringClientExample < Flexirest::BaseWithoutValidation
16
21
  translator TranslatorExample
17
22
  base_url "http://www.example.com"
@@ -140,6 +145,31 @@ describe Flexirest::BaseWithoutValidation do
140
145
  expect(client).to be_dirty
141
146
  end
142
147
 
148
+ it "should store attribute changes on nested objects and mark them as dirty in the parent" do
149
+ client = NestedExample.all
150
+ client.person.name = "John"
151
+ expect(client.person.name.to_s).to eq("John")
152
+
153
+ expect(client).to be_dirty
154
+ expect(client.changes.keys).to include(:person)
155
+
156
+ expect(client.person).to be_dirty
157
+ expect(client.person.changes.keys).to include(:name)
158
+ end
159
+
160
+ it "should store attribute changes on nested objects loaded via instance methods and mark them as dirty in the parent" do
161
+ client = NestedExample.new()
162
+ client.all
163
+ client.person.name = "John"
164
+ expect(client.person.name.to_s).to eq("John")
165
+
166
+ expect(client).to be_dirty
167
+ expect(client.changes.keys).to include(:person)
168
+
169
+ expect(client.person).to be_dirty
170
+ expect(client.person.changes.keys).to include(:name)
171
+ end
172
+
143
173
  it "should track changed attributes and provide access to previous values (similar to ActiveRecord/Mongoid)" do
144
174
  client = EmptyExample.new()
145
175
  client["test"] = "Something"
@@ -303,7 +303,7 @@ describe 'JSON API' do
303
303
  let(:tags) { JsonAPIExample::Tag }
304
304
  let(:author) { JsonAPIExample::Author }
305
305
 
306
- context 'responses' do
306
+ describe 'responses' do
307
307
  it 'should return the data object if the response contains only one data instance' do
308
308
  expect(subject.find(1)).to be_an_instance_of(JsonAPIExampleArticle)
309
309
  end
@@ -370,17 +370,17 @@ describe 'JSON API' do
370
370
  end
371
371
  end
372
372
 
373
- context 'attributes' do
373
+ describe 'attributes' do
374
374
  it 'should return the attributes as part of the data instance' do
375
- expect(subject.find(1).item).to_not be_nil
375
+ expect(subject.find(1).item).to eq("item one")
376
376
  end
377
377
 
378
378
  it 'should return the association\'s attributes as part of the association instance' do
379
- expect(subject.includes(:author).find_single_author(1).author.item).to_not be_nil
379
+ expect(subject.includes(:author).find_single_author(1).author.item).to eq("item two")
380
380
  end
381
381
  end
382
382
 
383
- context 'associations' do
383
+ describe 'associations' do
384
384
  it 'should retrieve the resource\'s associations via its relationships object' do
385
385
  expect(subject.includes(:tags).find(1).tags.size).to eq(2)
386
386
  end
@@ -415,6 +415,40 @@ describe 'JSON API' do
415
415
  end
416
416
  end
417
417
 
418
+ describe 'requests' do
419
+ describe 'the `include=` parameter' do
420
+ before { stub_request(:get, %r{example\.com/articles}) }
421
+
422
+ context 'when using `.includes(:tags)`' do
423
+ it 'equal "tags"' do
424
+ JsonAPIExample::Article.includes(:tags).real_index
425
+ expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?include=tags')
426
+ end
427
+ end
428
+
429
+ context 'when using `.includes(tags: [:authors, :articles])`' do
430
+ it 'equal "tags.authors,tags.articles"' do
431
+ JsonAPIExample::Article.includes(tags: [:authors, :articles]).real_index
432
+ expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?include=tags.authors,tags.articles')
433
+ end
434
+ end
435
+
436
+ context 'when using both `.includes(:tags)` and other params in the final call' do
437
+ it 'uses the values passed to the `includes() method`' do
438
+ JsonAPIExample::Article.includes(:tags).real_index(filter: { author_id: 4 })
439
+ expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?filter%5Bauthor_id%5D=4&include=tags')
440
+ end
441
+ end
442
+
443
+ context 'when using both `.includes(:tags)` and the :include param in final call' do
444
+ it 'uses the values passed to the `includes() method`' do
445
+ JsonAPIExample::Article.includes(:tags).real_index(include: "author")
446
+ expect(WebMock).to have_requested(:get, 'http://www.example.com/articles?include=tags')
447
+ end
448
+ end
449
+ end
450
+ end
451
+
418
452
  context 'lazy loading' do
419
453
  it 'should fetch association lazily' do
420
454
  stub_request(:get, /www.example.com\/articles\/1\/tags/)
@@ -434,7 +468,7 @@ describe 'JSON API' do
434
468
  end
435
469
  end
436
470
 
437
- context 'client' do
471
+ describe 'client' do
438
472
  it 'should request with json api format, and expect a json api response' do
439
473
  expect_any_instance_of(Flexirest::Connection).to receive(:post) { |_, _, _, options|
440
474
  expect(options[:headers]).to include('Content-Type' => 'application/vnd.api+json')
@@ -81,6 +81,26 @@ describe Flexirest::Request do
81
81
  get :all, "/"
82
82
  end
83
83
 
84
+ class AuthenticatedBasicHeaderExampleClient < Flexirest::Base
85
+ base_url "http://www.example.com"
86
+ username "john"
87
+ password "smith"
88
+ basic_auth_method :header
89
+ get :all, "/"
90
+ end
91
+
92
+ class AuthenticatedBasicHeaderExampleClientChildClass < AuthenticatedBasicHeaderExampleClient
93
+ get :child_method, "/"
94
+ end
95
+
96
+ class AuthenticatedBasicUrlExampleClient < Flexirest::Base
97
+ base_url "http://www.example.com"
98
+ username "john"
99
+ password "smith"
100
+ basic_auth_method :url
101
+ get :all, "/"
102
+ end
103
+
84
104
  class AuthenticatedProcExampleClient < Flexirest::Base
85
105
  base_url "http://www.example.com"
86
106
  username Proc.new { |obj| obj ? "bill-#{obj.id}" : "bill" }
@@ -199,6 +219,89 @@ describe Flexirest::Request do
199
219
  }
200
220
  end
201
221
 
222
+ class LocalIgnoredRootExampleClient < ExampleClient
223
+ ignore_root "feed"
224
+
225
+ get :root, "/root", fake: %Q{
226
+ {
227
+ "feed": {
228
+ "title": "Example Feed"
229
+ }
230
+ }
231
+ }
232
+ end
233
+
234
+ class LocalIgnoredMultiLevelRootExampleClient < ExampleClient
235
+ ignore_root [:response, "data", "object"]
236
+
237
+ get :multi_level_root, "/multi-level-root", fake: %Q{
238
+ {
239
+ "response": {
240
+ "data": {
241
+ "object": {
242
+ "title": "Example Multi Level Feed"
243
+ }
244
+ }
245
+ }
246
+ }
247
+ }
248
+ end
249
+
250
+ class BaseIgnoredRootExampleClient < Flexirest::Base
251
+ base_url "http://www.example.com"
252
+ ignore_root "feed"
253
+ end
254
+
255
+ class GlobalIgnoredRootExampleClient < BaseIgnoredRootExampleClient
256
+ get :root, "/root", fake: %Q{
257
+ {
258
+ "feed": {
259
+ "title": "Example Feed"
260
+ }
261
+ }
262
+ }
263
+ end
264
+
265
+ class OverrideGlobalIgnoredRootForFileExampleClient < BaseIgnoredRootExampleClient
266
+ ignore_root "data"
267
+
268
+ get :root, "/root", fake: %Q{
269
+ {
270
+ "data": {
271
+ "title": "Example Feed"
272
+ }
273
+ }
274
+ }
275
+ end
276
+
277
+ class OverrideGlobalIgnoredRootForRequestExampleClient < BaseIgnoredRootExampleClient
278
+ get :root, "/root", ignore_root: "data", fake: %Q{
279
+ {
280
+ "data": {
281
+ "title": "Example Feed"
282
+ }
283
+ }
284
+ }
285
+ end
286
+
287
+ class BaseWrappedRootExampleClient < Flexirest::Base
288
+ base_url "http://www.example.com"
289
+ wrap_root "base_data"
290
+ end
291
+
292
+ class GlobalWrappedRootExampleClient < BaseWrappedRootExampleClient
293
+ put :wrapped, "/put/:id"
294
+ end
295
+
296
+ class OverrideGlobalWrappedRootForFileExampleClient < BaseWrappedRootExampleClient
297
+ wrap_root "class_specific_data"
298
+ put :wrapped, "/put/:id"
299
+ end
300
+
301
+ class OverrideGlobalWrappedRootForRequestExampleClient < BaseWrappedRootExampleClient
302
+ put :wrapped, "/put/:id", wrap_root: "request_specific_data"
303
+ end
304
+
202
305
  class WhitelistedDateClient < Flexirest::Base
203
306
  base_url "http://www.example.com"
204
307
  put :conversion, "/put/:id"
@@ -231,13 +334,53 @@ describe Flexirest::Request do
231
334
  expect(servers.uniq.count).to eq(2)
232
335
  end
233
336
 
234
- it "should get an HTTP connection with authentication when called" do
337
+ it "should use the URL method for Basic HTTP Auth when no basic_auth_method is set" do
338
+ mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
339
+
235
340
  connection = double(Flexirest::Connection).as_null_object
236
341
  expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://john:smith@www.example.com").and_return(connection)
237
- expect(connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{})))
342
+ expect(connection).to receive(:get).with("/", an_instance_of(Hash)).and_return(mocked_response)
238
343
  AuthenticatedExampleClient.all
239
344
  end
240
345
 
346
+ it "should use the headers method for Basic auth when basic_auth_method is set to :header" do
347
+ mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
348
+ headers_including_auth = hash_including({ "Authorization" => "Basic am9objpzbWl0aA==" })
349
+
350
+ connection = double(Flexirest::Connection).as_null_object
351
+ expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://www.example.com").and_return(connection)
352
+ expect(connection).to receive(:get).with("/", hash_including(headers: headers_including_auth)).and_return(mocked_response)
353
+ AuthenticatedBasicHeaderExampleClient.all
354
+ end
355
+
356
+ it "should raise an error if Basic HTTP method is not :header or :url" do
357
+ expect do
358
+ AuthenticatedExampleClient.class_eval do
359
+ basic_auth_method :some_invalid_value
360
+ end
361
+ end.to raise_error(RuntimeError, "Invalid basic_auth_method :some_invalid_value. Valid methods are :url (default) and :header.")
362
+ end
363
+
364
+ it "should use the setting set on the parent class" do
365
+ mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
366
+ headers_including_auth = hash_including({ "Authorization" => "Basic am9objpzbWl0aA==" })
367
+
368
+ connection = double(Flexirest::Connection).as_null_object
369
+ expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://www.example.com").and_return(connection)
370
+ expect(connection).to receive(:get).with("/", hash_including(headers: headers_including_auth)).and_return(mocked_response)
371
+ AuthenticatedBasicHeaderExampleClientChildClass.child_method
372
+ end
373
+
374
+ it "should use the URL method for Basic auth when basic_auth_method is set to :url (and not include Authorization header)" do
375
+ mocked_response = ::FaradayResponseMock.new(OpenStruct.new(body:'{"result":true}', response_headers:{}))
376
+ headers_not_including_auth = hash_excluding("Authorization")
377
+
378
+ connection = double(Flexirest::Connection).as_null_object
379
+ expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://john:smith@www.example.com").and_return(connection)
380
+ expect(connection).to receive(:get).with("/", headers: headers_not_including_auth).and_return(mocked_response)
381
+ AuthenticatedBasicUrlExampleClient.all
382
+ end
383
+
241
384
  it "should get an HTTP connection with basic authentication using procs when called in a class context" do
242
385
  connection = double(Flexirest::Connection).as_null_object
243
386
  expect(Flexirest::ConnectionManager).to receive(:get_connection).with("http://bill:jones@www.example.com").and_return(connection)
@@ -1005,7 +1148,7 @@ describe Flexirest::Request do
1005
1148
  rescue Flexirest::HTTPServerException => e
1006
1149
  e
1007
1150
  end
1008
- expect(e).to be_instance_of(Flexirest::HTTPServerException)
1151
+ expect(e).to be_instance_of(Flexirest::HTTPInternalServerException)
1009
1152
  expect(e.status).to eq(500)
1010
1153
  expect(e.result.first_name).to eq("John")
1011
1154
  end
@@ -1021,7 +1164,7 @@ describe Flexirest::Request do
1021
1164
  rescue Flexirest::HTTPServerException => e
1022
1165
  e
1023
1166
  end
1024
- expect(e.message).to eq(%q{The POST to '/create' returned a 500 status, which raised a Flexirest::HTTPServerException with a body of: \{"first_name":"John", "id":1234\}})
1167
+ expect(e.message).to eq(%q{The POST to '/create' returned a 500 status, which raised a Flexirest::HTTPInternalServerException with a body of: \{"first_name":"John", "id":1234\}})
1025
1168
  end
1026
1169
 
1027
1170
  it "should raise a parse exception for invalid JSON returns" do
@@ -1036,7 +1179,7 @@ describe Flexirest::Request do
1036
1179
  rescue => e
1037
1180
  e
1038
1181
  end
1039
- expect(e).to be_instance_of(Flexirest::HTTPServerException)
1182
+ expect(e).to be_instance_of(Flexirest::HTTPInternalServerException)
1040
1183
  expect(e.status).to eq(500)
1041
1184
  expect(e.result).to eq(error_content)
1042
1185
  end
@@ -1355,6 +1498,62 @@ describe Flexirest::Request do
1355
1498
  expect(IgnoredMultiLevelRootExampleClient.multi_level_root.title).to eq("Example Multi Level Feed")
1356
1499
  end
1357
1500
 
1501
+ it "should ignore a specified root element" do
1502
+ expect(LocalIgnoredRootExampleClient.root.title).to eq("Example Feed")
1503
+ end
1504
+
1505
+ it "should ignore a specified multi-level root element" do
1506
+ expect(LocalIgnoredMultiLevelRootExampleClient.multi_level_root.title).to eq("Example Multi Level Feed")
1507
+ end
1508
+
1509
+ it "should ignore a specified root element" do
1510
+ expect(GlobalIgnoredRootExampleClient.root.title).to eq("Example Feed")
1511
+ end
1512
+
1513
+ it "should ignore a specified root element" do
1514
+ expect(OverrideGlobalIgnoredRootForFileExampleClient.root.title).to eq("Example Feed")
1515
+ end
1516
+
1517
+ it "should ignore a specified root element" do
1518
+ expect(OverrideGlobalIgnoredRootForRequestExampleClient.root.title).to eq("Example Feed")
1519
+ end
1520
+
1521
+ it "should wrap elements if specified, in form-encoded format" do
1522
+ expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q(base_data%5Bdebug%5D=true&base_data%5Btest%5D=foo), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
1523
+ GlobalWrappedRootExampleClient.request_body_type :form_encoded
1524
+ GlobalWrappedRootExampleClient.wrapped id:1234, debug:true, test:'foo'
1525
+ end
1526
+
1527
+ it "should wrap elements if specified, in form-encoded format" do
1528
+ expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q(class_specific_data%5Bdebug%5D=true&class_specific_data%5Btest%5D=foo), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
1529
+ OverrideGlobalWrappedRootForFileExampleClient.request_body_type :form_encoded
1530
+ OverrideGlobalWrappedRootForFileExampleClient.wrapped id:1234, debug:true, test:'foo'
1531
+ end
1532
+
1533
+ it "should wrap elements if specified, in form-encoded format" do
1534
+ expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q(request_specific_data%5Bdebug%5D=true&request_specific_data%5Btest%5D=foo), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
1535
+ OverrideGlobalWrappedRootForRequestExampleClient.request_body_type :form_encoded
1536
+ OverrideGlobalWrappedRootForRequestExampleClient.wrapped id:1234, debug:true, test:'foo'
1537
+ end
1538
+
1539
+ it "should encode the body wrapped in a root element in a JSON format if specified" do
1540
+ expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q({"base_data":{"debug":true,"test":"foo"}}), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
1541
+ GlobalWrappedRootExampleClient.request_body_type :json
1542
+ GlobalWrappedRootExampleClient.wrapped id:1234, debug:true, test:'foo'
1543
+ end
1544
+
1545
+ it "should encode the body wrapped in a root element in a JSON format if specified" do
1546
+ expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q({"class_specific_data":{"debug":true,"test":"foo"}}), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
1547
+ OverrideGlobalWrappedRootForFileExampleClient.request_body_type :json
1548
+ OverrideGlobalWrappedRootForFileExampleClient.wrapped id:1234, debug:true, test:'foo'
1549
+ end
1550
+
1551
+ it "should encode the body wrapped in a root element in a JSON format if specified" do
1552
+ expect_any_instance_of(Flexirest::Connection).to receive(:put).with("/put/1234", %q({"request_specific_data":{"debug":true,"test":"foo"}}), an_instance_of(Hash)).and_return(::FaradayResponseMock.new(OpenStruct.new(body:"{\"result\":true}", response_headers:{})))
1553
+ OverrideGlobalWrappedRootForRequestExampleClient.request_body_type :json
1554
+ OverrideGlobalWrappedRootForRequestExampleClient.wrapped id:1234, debug:true, test:'foo'
1555
+ end
1556
+
1358
1557
  context "Parameter preparation" do
1359
1558
  method = {url: "http://www.example.com", method: :get}
1360
1559
  object = nil
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: flexirest
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.18
4
+ version: 1.10.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Jeffries
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-08-24 00:00:00.000000000 Z
11
+ date: 2021-03-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -176,14 +176,14 @@ dependencies:
176
176
  requirements:
177
177
  - - ">="
178
178
  - !ruby/object:Gem::Version
179
- version: 1.8.0
179
+ version: '0'
180
180
  type: :development
181
181
  prerelease: false
182
182
  version_requirements: !ruby/object:Gem::Requirement
183
183
  requirements:
184
184
  - - ">="
185
185
  - !ruby/object:Gem::Version
186
- version: 1.8.0
186
+ version: '0'
187
187
  - !ruby/object:Gem::Dependency
188
188
  name: mime-types
189
189
  requirement: !ruby/object:Gem::Requirement