ddy_remote_resource 0.4.11 → 1.0.0.rc1

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.
Files changed (48) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile +2 -0
  3. data/Guardfile +3 -0
  4. data/lib/remote_resource.rb +77 -34
  5. data/lib/remote_resource/base.rb +20 -8
  6. data/lib/remote_resource/connection.rb +26 -5
  7. data/lib/remote_resource/connection_options.rb +5 -3
  8. data/lib/remote_resource/querying/finder_methods.rb +3 -3
  9. data/lib/remote_resource/querying/persistence_methods.rb +17 -12
  10. data/lib/remote_resource/request.rb +96 -62
  11. data/lib/remote_resource/response.rb +5 -1
  12. data/lib/remote_resource/rest.rb +13 -17
  13. data/lib/remote_resource/url_naming.rb +4 -10
  14. data/lib/remote_resource/url_naming_determination.rb +1 -3
  15. data/lib/remote_resource/util.rb +64 -0
  16. data/lib/remote_resource/version.rb +1 -1
  17. data/remote_resource.gemspec +2 -2
  18. data/spec/fixtures/text_file.txt +1 -0
  19. data/spec/integration/all_spec.rb +166 -0
  20. data/spec/integration/collection_prefix_spec.rb +99 -0
  21. data/spec/integration/create_spec.rb +181 -0
  22. data/spec/integration/destroy_spec.rb +252 -0
  23. data/spec/integration/find_by_spec.rb +168 -0
  24. data/spec/integration/find_spec.rb +139 -0
  25. data/spec/integration/headers_spec.rb +222 -0
  26. data/spec/integration/naming_spec.rb +138 -0
  27. data/spec/integration/save_spec.rb +320 -0
  28. data/spec/integration/update_attributes_spec.rb +221 -0
  29. data/spec/integration/where_spec.rb +152 -0
  30. data/spec/lib/extensions/ethon/easy/queryable_spec.rb +4 -4
  31. data/spec/lib/remote_resource/base_spec.rb +54 -110
  32. data/spec/lib/remote_resource/builder_spec.rb +1 -1
  33. data/spec/lib/remote_resource/collection_spec.rb +1 -1
  34. data/spec/lib/remote_resource/connection_options_spec.rb +20 -17
  35. data/spec/lib/remote_resource/connection_spec.rb +36 -27
  36. data/spec/lib/remote_resource/querying/finder_methods_spec.rb +199 -72
  37. data/spec/lib/remote_resource/querying/persistence_methods_spec.rb +228 -220
  38. data/spec/lib/remote_resource/request_spec.rb +313 -342
  39. data/spec/lib/remote_resource/response_spec.rb +9 -3
  40. data/spec/lib/remote_resource/rest_spec.rb +11 -11
  41. data/spec/lib/remote_resource/url_naming_determination_spec.rb +1 -1
  42. data/spec/lib/remote_resource/url_naming_spec.rb +7 -22
  43. data/spec/lib/remote_resource/util_spec.rb +56 -0
  44. data/spec/lib/remote_resource/version_spec.rb +2 -3
  45. data/spec/spec_helper.rb +37 -0
  46. metadata +33 -22
  47. data/lib/remote_resource/http_errors.rb +0 -33
  48. data/lib/remote_resource/response_handeling.rb +0 -48
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae92e08ce0a95cfc8253c09f3106087caf9ba636
4
- data.tar.gz: 0e675db4069759cb3bf185c616821c78f55b1cad
3
+ metadata.gz: e3d2576b744b3dafd66aff8fca6d991f709fa10d
4
+ data.tar.gz: b32d6edb8af70dccdfe2b83cf4da340969b7f8b9
5
5
  SHA512:
6
- metadata.gz: 2b829236979e4f246503864b810da68b9939e84e2fdab2c288131a20bbde39fed70660b1a708d9390818e4d408579cf94db7508300c5cc1a3d1dc777cc84aeff
7
- data.tar.gz: d8ed2d8f09246377321acb6a2a0cd1a889e2090a2504509346d209f52cb6f541b3f7e30e890cbc72e06d778c36bd10c1071c74abf2adf909e48fb737b1f14796
6
+ metadata.gz: 3934a8a1d740a88e3cae6e8dc726c6af2bbb99bc35c4d8a25faf8ac6993fedcf5cdf67cf9093c9f6cf299b14eba9be50feb89a3527418720b0a8dc5f6e5f264f
7
+ data.tar.gz: 99b67f28cb4284c6100d69340e3f68020f4e13e3a5abedc99d62242858864b4846e9b207b6c1e79fc0834781e5e04a782cc6372bda5558aa06e29ee7a07d601e
data/Gemfile CHANGED
@@ -2,3 +2,5 @@ source 'https://rubygems.org'
2
2
 
3
3
  # Specify your gem's dependencies in remote_resource.gemspec
4
4
  gemspec
5
+
6
+ gem 'webmock', github: 'JanDintel/webmock', branch: ' feature/ignore-json-keys-order'
data/Guardfile CHANGED
@@ -40,6 +40,9 @@ guard :rspec, cmd: 'bundle exec rspec', notification: true do
40
40
  ruby = dsl.ruby
41
41
  dsl.watch_spec_files_for(ruby.lib_files)
42
42
 
43
+ # Integration specs
44
+ watch(ruby.lib_files) { 'spec/integration' }
45
+
43
46
  # Notification (See: https://github.com/Codaisseur/terminal-notifier-guard)
44
47
  notification :terminal_notifier, app_name: 'RemoteResource', activate: 'com.googlecode.iTerm2' if `uname` =~ /Darwin/
45
48
  end
@@ -17,52 +17,95 @@ require 'remote_resource/rest'
17
17
  require 'remote_resource/response'
18
18
  require 'remote_resource/querying/finder_methods'
19
19
  require 'remote_resource/querying/persistence_methods'
20
- require 'remote_resource/http_errors'
21
20
  require 'remote_resource/request'
22
-
21
+ require 'remote_resource/util'
23
22
 
24
23
  module RemoteResource
25
- RemoteResourceError = Class.new StandardError
24
+ RemoteResourceError = Class.new(StandardError)
26
25
 
27
26
  IdMissingError = Class.new(RemoteResourceError)
28
-
27
+
29
28
  CollectionOptionKeyError = Class.new(RemoteResourceError)
30
29
 
31
- RESTActionUnknown = Class.new RemoteResourceError # REST action
30
+ HTTPMethodUnsupported = Class.new(RemoteResourceError) # REST action
32
31
 
33
32
  class HTTPError < RemoteResourceError # HTTP errors
34
33
 
35
- def initialize(response)
36
- if response.try(:response_code)
37
- super "for url: #{response.try(:effective_url)} with HTTP response status: #{response.response_code} and response: #{response.inspect}"
38
- else
39
- super "for url: #{response.try(:effective_url)} with HTTP response: #{response.inspect}"
40
- end
34
+ def initialize(request, response)
35
+ @request = request
36
+ @response = response
37
+ end
38
+
39
+ def resource_klass
40
+ @request.resource_klass
41
+ end
42
+
43
+ def http_action
44
+ @request.http_action
45
+ end
46
+
47
+ def request_url
48
+ @request.request_url
49
+ end
50
+
51
+ def request_query
52
+ @request.query
53
+ end
54
+
55
+ def request_body
56
+ @request.body # TODO: Filter sensitive information using: RemoteResource::Util.filter_params
57
+ end
58
+
59
+ def request_headers
60
+ @request.headers
61
+ end
62
+
63
+ def response_code
64
+ @response.response_code
65
+ end
66
+
67
+ def response_body
68
+ @response.response_body # TODO: Filter sensitive information using: RemoteResource::Util.filter_params
69
+ end
70
+
71
+ def response_headers
72
+ @response.response_headers
73
+ end
74
+
75
+ def to_s
76
+ message = "HTTP request failed for #{resource_klass}"
77
+ message << " with response_code=#{response_code}" if response_code.present?
78
+ message << " with http_action=#{http_action}"
79
+ message << " with request_url=#{request_url}"
80
+ # message << " with request_query=#{request_query}" if request_query.present? # TODO: Test usability of error message whether to include this
81
+ # message << " with request_body=#{request_body}" if request_body.present? # TODO: Test usability of error message whether to include this
82
+ # message << " with response_body=#{response_body}" if response_body.present? # TODO: Test usability of error message whether to include this
83
+ message
41
84
  end
42
85
  end
43
86
 
44
- HTTPRedirectionError = Class.new HTTPError # HTTP 3xx
45
- HTTPClientError = Class.new HTTPError # HTTP 4xx
46
- HTTPServerError = Class.new HTTPError # HTTP 5xx
47
-
48
- HTTPBadRequest = Class.new HTTPClientError # HTTP 400
49
- HTTPUnauthorized = Class.new HTTPClientError # HTTP 401
50
- HTTPForbidden = Class.new HTTPClientError # HTTP 403
51
- HTTPNotFound = Class.new HTTPClientError # HTTP 404
52
- HTTPMethodNotAllowed = Class.new HTTPClientError # HTTP 405
53
- HTTPNotAcceptable = Class.new HTTPClientError # HTTP 406
54
- HTTPRequestTimeout = Class.new HTTPClientError # HTTP 408
55
- HTTPConflict = Class.new HTTPClientError # HTTP 409
56
- HTTPGone = Class.new HTTPClientError # HTTP 410
57
- HTTPTeapot = Class.new HTTPClientError # HTTP 418
58
-
59
- NginxClientError = Class.new HTTPClientError # HTTP errors used in Nginx
60
-
61
- HTTPNoResponse = Class.new NginxClientError # HTTP 444
62
- HTTPRequestHeaderTooLarge = Class.new NginxClientError # HTTP 494
63
- HTTPCertError = Class.new NginxClientError # HTTP 495
64
- HTTPNoCert = Class.new NginxClientError # HTTP 496
65
- HTTPToHTTPS = Class.new NginxClientError # HTTP 497
66
- HTTPClientClosedRequest = Class.new NginxClientError # HTTP 499
87
+ HTTPRedirectionError = Class.new(HTTPError) # HTTP 3xx
88
+ HTTPClientError = Class.new(HTTPError) # HTTP 4xx
89
+ HTTPServerError = Class.new(HTTPError) # HTTP 5xx
90
+
91
+ HTTPBadRequest = Class.new(HTTPClientError) # HTTP 400
92
+ HTTPUnauthorized = Class.new(HTTPClientError) # HTTP 401
93
+ HTTPForbidden = Class.new(HTTPClientError) # HTTP 403
94
+ HTTPNotFound = Class.new(HTTPClientError) # HTTP 404
95
+ HTTPMethodNotAllowed = Class.new(HTTPClientError) # HTTP 405
96
+ HTTPNotAcceptable = Class.new(HTTPClientError) # HTTP 406
97
+ HTTPRequestTimeout = Class.new(HTTPClientError) # HTTP 408
98
+ HTTPConflict = Class.new(HTTPClientError) # HTTP 409
99
+ HTTPGone = Class.new(HTTPClientError) # HTTP 410
100
+ HTTPTeapot = Class.new(HTTPClientError) # HTTP 418
101
+
102
+ NginxClientError = Class.new(HTTPClientError) # HTTP errors used in Nginx
103
+
104
+ HTTPNoResponse = Class.new(NginxClientError) # HTTP 444
105
+ HTTPRequestHeaderTooLarge = Class.new(NginxClientError) # HTTP 494
106
+ HTTPCertError = Class.new(NginxClientError) # HTTP 495
107
+ HTTPNoCert = Class.new(NginxClientError) # HTTP 496
108
+ HTTPToHTTPS = Class.new(NginxClientError) # HTTP 497
109
+ HTTPClientClosedRequest = Class.new(NginxClientError) # HTTP 499
67
110
 
68
111
  end
@@ -2,8 +2,6 @@ module RemoteResource
2
2
  module Base
3
3
  extend ActiveSupport::Concern
4
4
 
5
- OPTIONS = [:base_url, :site, :headers, :version, :path_prefix, :path_postfix, :collection_prefix, :content_type, :collection, :collection_name, :root_element]
6
-
7
5
  included do
8
6
  include Virtus.model
9
7
  extend ActiveModel::Naming
@@ -14,12 +12,15 @@ module RemoteResource
14
12
  include RemoteResource::Builder
15
13
  include RemoteResource::UrlNaming
16
14
  include RemoteResource::Connection
15
+
16
+ extend RemoteResource::REST
17
17
  include RemoteResource::REST
18
18
 
19
19
  include RemoteResource::Querying::FinderMethods
20
20
  include RemoteResource::Querying::PersistenceMethods
21
21
 
22
22
  attr_accessor :_response
23
+ attr_accessor :destroyed
23
24
 
24
25
  attribute :id
25
26
  class_attribute :root_element, instance_accessor: false
@@ -45,8 +46,7 @@ module RemoteResource
45
46
 
46
47
  def with_connection_options(connection_options = {})
47
48
  begin
48
- threaded_connection_options
49
- Thread.current[threaded_connection_options_thread_name].merge! connection_options
49
+ Thread.current[threaded_connection_options_thread_name] = threaded_connection_options.merge(connection_options)
50
50
  yield
51
51
  ensure
52
52
  Thread.current[threaded_connection_options_thread_name] = nil
@@ -68,8 +68,16 @@ module RemoteResource
68
68
  @connection_options ||= RemoteResource::ConnectionOptions.new(self.class)
69
69
  end
70
70
 
71
+ def persistence
72
+ self if persisted?
73
+ end
74
+
71
75
  def persisted?
72
- id.present?
76
+ if destroyed
77
+ false
78
+ else
79
+ id.present?
80
+ end
73
81
  end
74
82
 
75
83
  def new_record?
@@ -105,11 +113,15 @@ module RemoteResource
105
113
  private
106
114
 
107
115
  def assign_errors(error_messages)
108
- return unless error_messages.respond_to? :each
116
+ return unless error_messages.respond_to?(:each)
109
117
 
110
118
  error_messages.each do |attribute, attribute_errors|
111
- attribute_errors.each do |error|
112
- self.errors.add attribute, error
119
+ attribute_errors.each do |attribute_error|
120
+ if respond_to?(attribute)
121
+ self.errors.add(attribute, attribute_error)
122
+ else
123
+ self.errors.add(:base, attribute_error)
124
+ end
113
125
  end
114
126
  end
115
127
  end
@@ -3,10 +3,9 @@ module RemoteResource
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- class_attribute :content_type, :default_headers, :extra_headers, instance_accessor: false
6
+ class_attribute :extension, :default_headers, instance_accessor: false
7
7
 
8
- self.content_type = '.json'
9
- self.default_headers = { "Accept" => "application/json" }
8
+ self.default_headers = {}
10
9
  end
11
10
 
12
11
  module ClassMethods
@@ -15,10 +14,32 @@ module RemoteResource
15
14
  Typhoeus::Request
16
15
  end
17
16
 
17
+ def content_type=(content_type)
18
+ warn '[DEPRECATION] `.content_type=` is deprecated. Please use `.extension=` instead.'
19
+ self.extension = content_type
20
+ end
21
+
22
+ def content_type
23
+ warn '[DEPRECATION] `.content_type` is deprecated. Please use `.extension` instead.'
24
+ self.extension
25
+ end
26
+
27
+ def extra_headers=(_)
28
+ warn '[DEPRECATION] `.extra_headers=` is deprecated. Please overwrite the .headers method to set custom headers.'
29
+ end
30
+
31
+ def extra_headers
32
+ warn '[DEPRECATION] `.extra_headers` is deprecated. Please overwrite the .headers method to set custom headers.'
33
+ end
34
+
35
+ def headers=(_)
36
+ warn '[WARNING] `.headers=` can not be used to set custom headers. Please overwrite the .headers method to set custom headers.'
37
+ end
38
+
18
39
  def headers
19
- self.default_headers.merge self.extra_headers || {}
40
+ {}
20
41
  end
21
42
 
22
43
  end
23
44
  end
24
- end
45
+ end
@@ -1,6 +1,8 @@
1
1
  module RemoteResource
2
2
  class ConnectionOptions
3
3
 
4
+ AVAILABLE_OPTIONS = [:site, :headers, :default_headers, :version, :path_prefix, :path_postfix, :collection_prefix, :extension, :collection, :collection_name, :root_element].freeze
5
+
4
6
  attr_reader :base_class
5
7
 
6
8
  def initialize(base_class)
@@ -15,7 +17,7 @@ module RemoteResource
15
17
  end
16
18
 
17
19
  def to_hash
18
- RemoteResource::Base::OPTIONS.each_with_object(Hash.new) do |option, hash|
20
+ AVAILABLE_OPTIONS.each_with_object(Hash.new) do |option, hash|
19
21
  hash[option] = self.public_send option
20
22
  end
21
23
  end
@@ -31,11 +33,11 @@ module RemoteResource
31
33
  private
32
34
 
33
35
  def initialize_connection_options
34
- RemoteResource::Base::OPTIONS.each do |option|
36
+ AVAILABLE_OPTIONS.each do |option|
35
37
  self.class.send :attr_accessor, option
36
38
  self.public_send "#{option}=", base_class.public_send(option)
37
39
  end
38
40
  end
39
41
 
40
42
  end
41
- end
43
+ end
@@ -6,12 +6,12 @@ module RemoteResource
6
6
  module ClassMethods
7
7
 
8
8
  def find(id, connection_options = {})
9
- response = RemoteResource::Request.new(self, :get, { id: id }, connection_options.merge(no_attributes: true)).perform
9
+ response = RemoteResource::Request.new(self, :get, {}, connection_options.merge(id: id)).perform
10
10
  build_resource_from_response(response)
11
11
  end
12
12
 
13
13
  def find_by(params, connection_options = {})
14
- response = RemoteResource::Request.new(self, :get, params, connection_options).perform
14
+ response = RemoteResource::Request.new(self, :get, {}, connection_options.deep_merge(id: params[:id], params: params.except(:id))).perform
15
15
  build_resource_from_response(response)
16
16
  end
17
17
 
@@ -21,7 +21,7 @@ module RemoteResource
21
21
  end
22
22
 
23
23
  def where(params, connection_options = {})
24
- response = RemoteResource::Request.new(self, :get, params, connection_options.merge(collection: true)).perform
24
+ response = RemoteResource::Request.new(self, :get, {}, connection_options.deep_merge(collection: true, params: params)).perform
25
25
  build_collection_from_response(response)
26
26
  end
27
27
  end
@@ -12,9 +12,11 @@ module RemoteResource
12
12
  end
13
13
 
14
14
  def destroy(id, connection_options = {})
15
- resource = new
16
- response = RemoteResource::Request.new(self, :delete, { id: id }, connection_options.reverse_merge(no_attributes: true)).perform
15
+ resource = new(id: id)
16
+ response = RemoteResource::Request.new(self, :delete, {}, connection_options.merge(id: id)).perform
17
17
  resource.handle_response(response)
18
+ resource.destroyed = resource.success?
19
+ resource
18
20
  end
19
21
  end
20
22
 
@@ -29,22 +31,25 @@ module RemoteResource
29
31
  success? ? self : false
30
32
  end
31
33
 
32
- def create_or_update(attributes = {}, connection_options = {})
33
- if attributes.has_key?(:id)
34
- response = RemoteResource::Request.new(self, :patch, attributes, connection_options).perform
35
- else
36
- response = RemoteResource::Request.new(self, :post, attributes, connection_options).perform
37
- end
38
- handle_response(response)
39
- end
40
-
41
34
  def destroy(connection_options = {})
42
35
  id.present? || raise(RemoteResource::IdMissingError.new("`id` is missing from resource"))
43
- response = RemoteResource::Request.new(self, :delete, { id: id }, connection_options.reverse_merge(no_attributes: true)).perform
36
+ response = RemoteResource::Request.new(self, :delete, {}, connection_options.merge(id: id)).perform
44
37
  handle_response(response)
38
+ self.destroyed = success?
45
39
  success? ? self : false
46
40
  end
47
41
 
42
+ private
43
+
44
+ def create_or_update(attributes = {}, connection_options = {})
45
+ if attributes.has_key?(:id) && attributes[:id].present?
46
+ response = RemoteResource::Request.new(self, :patch, attributes.except(:id), connection_options.merge(id: attributes[:id])).perform
47
+ else
48
+ response = RemoteResource::Request.new(self, :post, attributes.except(:id), connection_options).perform
49
+ end
50
+ handle_response(response)
51
+ end
52
+
48
53
  end
49
54
  end
50
55
  end
@@ -1,15 +1,27 @@
1
1
  module RemoteResource
2
2
  class Request
3
- include RemoteResource::HTTPErrors
4
3
 
5
- attr_reader :resource, :rest_action, :attributes
4
+ SUPPORTED_HTTP_METHODS = [:get, :put, :patch, :post, :delete].freeze
6
5
 
7
- def initialize(resource, rest_action, attributes = {}, connection_options = {})
6
+ DEFAULT_HEADERS = {
7
+ 'Accept' => 'application/json',
8
+ 'User-Agent' => "RemoteResource #{RemoteResource::VERSION}"
9
+ }.freeze
10
+
11
+ DEFAULT_CONTENT_TYPE = {
12
+ 'Content-Type' => 'application/json'
13
+ }.freeze
14
+
15
+ DEFAULT_EXTENSION = '.json'.freeze
16
+
17
+ attr_reader :resource, :resource_klass, :http_action, :attributes
18
+
19
+ def initialize(resource, http_action, attributes = {}, connection_options = {})
8
20
  @resource = resource
9
- @rest_action = rest_action.to_sym
21
+ @resource_klass = resource.is_a?(Class) ? resource : resource.class
22
+ @http_action = http_action.to_sym
10
23
  @attributes = attributes
11
- @connection_options = connection_options
12
- @original_connection_options = connection_options.dup
24
+ @connection_options = connection_options.dup
13
25
  end
14
26
 
15
27
  def connection
@@ -17,90 +29,112 @@ module RemoteResource
17
29
  end
18
30
 
19
31
  def connection_options
20
- @connection_options.reverse_merge(threaded_connection_options).reverse_merge(resource.connection_options.to_hash)
21
- end
32
+ @combined_connection_options ||= begin
33
+ default = resource.connection_options.to_hash # Defined on the resource (klass).
34
+ block = resource.try(:threaded_connection_options) || {} # Given as arguments in the .with_connection_options block.
35
+ local = @connection_options # Given as arguments directly.
22
36
 
23
- def original_connection_options
24
- @original_connection_options.reverse_merge(threaded_connection_options)
37
+ default.deep_merge(block).deep_merge(local)
38
+ end
25
39
  end
26
40
 
27
41
  def perform
28
- case rest_action
29
- when :get
30
- response = connection.public_send rest_action, determined_request_url, params: determined_params, headers: determined_headers
31
- when :put, :patch, :post
32
- response = connection.public_send rest_action, determined_request_url, body: determined_attributes, headers: determined_headers
33
- when :delete
34
- response = connection.public_send rest_action, determined_request_url, params: determined_params, headers: determined_headers
35
- else
36
- raise RemoteResource::RESTActionUnknown, "for action: '#{rest_action}'"
37
- end
42
+ SUPPORTED_HTTP_METHODS.include?(http_action) || raise(RemoteResource::HTTPMethodUnsupported, "Requested HTTP method=#{http_action.to_s} is NOT supported, the HTTP action MUST be a supported HTTP action=#{SUPPORTED_HTTP_METHODS.join(', ')}")
43
+
44
+ connection_response = connection.public_send(http_action, request_url, params: query, body: body, headers: headers)
45
+ response = RemoteResource::Response.new(connection_response, connection_options)
38
46
 
39
- if response.success? || response.response_code == 422
40
- RemoteResource::Response.new response, connection_options
47
+ if response.success? || response.unprocessable_entity?
48
+ response
41
49
  else
42
- raise_http_errors response
50
+ raise_http_error(self, response)
43
51
  end
44
52
  end
45
53
 
46
- def determined_request_url
47
- id = attributes[:id].presence
48
- base_url = original_connection_options[:base_url].presence || determined_url_naming.base_url(id, check_collection_options: true)
49
- content_type = connection_options[:content_type]
54
+ def request_url
55
+ @request_url ||= begin
56
+ id = @attributes[:id].presence || connection_options[:id]
57
+ base_url = connection_options[:base_url].presence || RemoteResource::UrlNamingDetermination.new(resource_klass, connection_options).base_url(id, check_collection_options: true)
58
+ extension = connection_options[:extension] || DEFAULT_EXTENSION
50
59
 
51
- "#{base_url}#{content_type}"
60
+ "#{base_url}#{extension}"
61
+ end
52
62
  end
53
63
 
54
- def determined_params
55
- no_params = connection_options[:no_params].eql? true
56
- no_attributes = connection_options[:no_attributes].eql? true
57
- params = connection_options[:params].presence || {}
64
+ def query
65
+ @query ||= begin
66
+ params = connection_options[:params]
58
67
 
59
- if no_params
60
- nil
61
- elsif no_attributes
62
- params
63
- else
64
- attributes.merge! params
68
+ if params.present?
69
+ RemoteResource::Util.encode_params_to_query(params)
70
+ else
71
+ nil
72
+ end
65
73
  end
66
74
  end
67
75
 
68
- def determined_attributes
69
- no_attributes = connection_options[:no_attributes].eql? true
70
- root_element = connection_options[:root_element].presence
71
-
72
- if no_attributes
73
- {}
74
- elsif root_element
75
- pack_up_attributes attributes, root_element
76
- else
77
- attributes
76
+ def body
77
+ @body ||= begin
78
+ if [:put, :patch, :post].include?(http_action)
79
+ JSON.generate(attributes)
80
+ else
81
+ nil
82
+ end
78
83
  end
79
84
  end
80
85
 
81
- def determined_headers
82
- headers = original_connection_options[:headers].presence || {}
86
+ def attributes
87
+ root_element = connection_options[:root_element]
83
88
 
84
- (connection_options[:default_headers].presence ||
85
- resource.connection_options.headers.merge(headers)).reverse_merge RemoteResource::Base.global_headers
89
+ if root_element.present?
90
+ { root_element => @attributes }
91
+ else
92
+ @attributes || {}
93
+ end
86
94
  end
87
95
 
88
- private
96
+ def headers
97
+ @headers ||= begin
98
+ default_headers = connection_options[:default_headers].presence || DEFAULT_HEADERS
99
+ global_headers = RemoteResource::Base.global_headers.presence || {}
100
+ headers = connection_options[:headers].presence || {}
89
101
 
90
- def threaded_connection_options
91
- resource.try(:threaded_connection_options) || {}
102
+ default_headers.merge(global_headers).merge(headers).merge(conditional_headers)
103
+ end
92
104
  end
93
105
 
94
- def determined_url_naming
95
- RemoteResource::UrlNamingDetermination.new resource_klass, original_connection_options
106
+ def conditional_headers
107
+ headers = {}
108
+ headers = headers.merge(DEFAULT_CONTENT_TYPE) if body.present?
109
+ headers
96
110
  end
97
111
 
98
- def resource_klass
99
- resource.is_a?(Class) ? resource : resource.class
100
- end
112
+ private
101
113
 
102
- def pack_up_attributes(attributes, root_element)
103
- Hash[root_element.to_s, attributes]
114
+ def raise_http_error(request, response)
115
+ case response.try(:response_code)
116
+ when 301, 302, 303, 307 then raise RemoteResource::HTTPRedirectionError.new(request, response)
117
+ when 400 then raise RemoteResource::HTTPBadRequest.new(request, response)
118
+ when 401 then raise RemoteResource::HTTPUnauthorized.new(request, response)
119
+ when 403 then raise RemoteResource::HTTPForbidden.new(request, response)
120
+ when 404 then raise RemoteResource::HTTPNotFound.new(request, response)
121
+ when 405 then raise RemoteResource::HTTPMethodNotAllowed.new(request, response)
122
+ when 406 then raise RemoteResource::HTTPNotAcceptable.new(request, response)
123
+ when 408 then raise RemoteResource::HTTPRequestTimeout.new(request, response)
124
+ when 409 then raise RemoteResource::HTTPConflict.new(request, response)
125
+ when 410 then raise RemoteResource::HTTPGone.new(request, response)
126
+ when 418 then raise RemoteResource::HTTPTeapot.new(request, response)
127
+ when 444 then raise RemoteResource::HTTPNoResponse.new(request, response)
128
+ when 494 then raise RemoteResource::HTTPRequestHeaderTooLarge.new(request, response)
129
+ when 495 then raise RemoteResource::HTTPCertError.new(request, response)
130
+ when 496 then raise RemoteResource::HTTPNoCert.new(request, response)
131
+ when 497 then raise RemoteResource::HTTPToHTTPS.new(request, response)
132
+ when 499 then raise RemoteResource::HTTPClientClosedRequest.new(request, response)
133
+ when 400..499 then raise RemoteResource::HTTPClientError.new(request, response)
134
+ when 500..599 then raise RemoteResource::HTTPServerError.new(request, response)
135
+ else
136
+ raise RemoteResource::HTTPError.new(request, response)
137
+ end
104
138
  end
105
139
 
106
140
  end