restfulie 0.8.0 → 0.8.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (102) hide show
  1. data/Gemfile +10 -5
  2. data/Rakefile +5 -2
  3. data/lib/restfulie.rb +10 -5
  4. data/lib/restfulie/client.rb +13 -9
  5. data/lib/restfulie/client/base.rb +24 -65
  6. data/lib/restfulie/client/configuration.rb +62 -64
  7. data/lib/restfulie/client/entry_point.rb +36 -0
  8. data/lib/restfulie/client/ext/atom_ext.rb +12 -0
  9. data/lib/restfulie/client/ext/http_ext.rb +22 -0
  10. data/lib/restfulie/client/ext/json_ext.rb +12 -0
  11. data/lib/restfulie/client/ext/xml_ext.rb +4 -0
  12. data/lib/restfulie/client/http.rb +25 -13
  13. data/lib/restfulie/client/http/cache.rb +22 -22
  14. data/lib/restfulie/client/http/error.rb +70 -70
  15. data/lib/restfulie/client/http/link_request_builder.rb +15 -0
  16. data/lib/restfulie/client/http/request_adapter.rb +209 -0
  17. data/lib/restfulie/client/http/request_builder.rb +107 -0
  18. data/lib/restfulie/client/http/request_builder_executor.rb +24 -0
  19. data/lib/restfulie/client/http/request_executor.rb +17 -0
  20. data/lib/restfulie/client/http/request_follow.rb +42 -0
  21. data/lib/restfulie/client/http/request_follow_executor.rb +10 -0
  22. data/lib/restfulie/client/http/request_history.rb +69 -0
  23. data/lib/restfulie/client/http/request_history_executor.rb +10 -0
  24. data/lib/restfulie/client/http/request_marshaller.rb +127 -0
  25. data/lib/restfulie/client/http/request_marshaller_executor.rb +10 -0
  26. data/lib/restfulie/client/http/response.rb +23 -0
  27. data/lib/restfulie/client/http/response_handler.rb +67 -0
  28. data/lib/restfulie/client/http/response_holder.rb +9 -0
  29. data/lib/restfulie/client/mikyung.rb +17 -14
  30. data/lib/restfulie/client/mikyung/concatenator.rb +15 -12
  31. data/lib/restfulie/client/mikyung/core.rb +65 -39
  32. data/lib/restfulie/client/mikyung/languages.rb +8 -26
  33. data/lib/restfulie/client/mikyung/languages/german.rb +24 -0
  34. data/lib/restfulie/client/mikyung/languages/portuguese.rb +23 -0
  35. data/lib/restfulie/client/mikyung/rest_process_model.rb +184 -107
  36. data/lib/restfulie/client/mikyung/steady_state_walker.rb +34 -28
  37. data/lib/restfulie/client/mikyung/then_condition.rb +33 -27
  38. data/lib/restfulie/client/mikyung/when_condition.rb +53 -49
  39. data/lib/restfulie/common.rb +7 -12
  40. data/lib/restfulie/common/converter.rb +20 -9
  41. data/lib/restfulie/common/converter/atom.rb +8 -83
  42. data/lib/restfulie/common/converter/atom/base.rb +89 -0
  43. data/lib/restfulie/common/converter/atom/builder.rb +101 -99
  44. data/lib/restfulie/common/converter/atom/helpers.rb +16 -8
  45. data/lib/restfulie/common/converter/json.rb +12 -0
  46. data/lib/restfulie/common/converter/json/base.rb +84 -0
  47. data/lib/restfulie/common/converter/json/builder.rb +102 -0
  48. data/lib/restfulie/common/converter/json/helpers.rb +17 -0
  49. data/lib/restfulie/common/converter/values.rb +30 -26
  50. data/lib/restfulie/common/converter/xml.rb +14 -0
  51. data/lib/restfulie/common/converter/xml/base.rb +61 -0
  52. data/lib/restfulie/common/converter/xml/builder.rb +112 -0
  53. data/lib/restfulie/common/converter/xml/helpers.rb +17 -0
  54. data/lib/restfulie/common/converter/xml/link.rb +25 -0
  55. data/lib/restfulie/common/converter/xml/links.rb +25 -0
  56. data/lib/restfulie/common/core_ext.rb +1 -5
  57. data/lib/restfulie/common/core_ext/hash.rb +12 -0
  58. data/lib/restfulie/common/error.rb +19 -0
  59. data/lib/restfulie/common/logger.rb +17 -9
  60. data/lib/restfulie/common/representation.rb +9 -10
  61. data/lib/restfulie/common/representation/atom.rb +15 -47
  62. data/lib/restfulie/common/representation/atom/base.rb +122 -365
  63. data/lib/restfulie/common/representation/atom/category.rb +41 -0
  64. data/lib/restfulie/common/representation/atom/entry.rb +52 -100
  65. data/lib/restfulie/common/representation/atom/factory.rb +43 -0
  66. data/lib/restfulie/common/representation/atom/feed.rb +103 -99
  67. data/lib/restfulie/common/representation/atom/link.rb +68 -0
  68. data/lib/restfulie/common/representation/atom/person.rb +48 -0
  69. data/lib/restfulie/common/representation/atom/source.rb +59 -0
  70. data/lib/restfulie/common/representation/atom/tag_collection.rb +38 -0
  71. data/lib/restfulie/common/representation/atom/xml.rb +95 -0
  72. data/lib/restfulie/common/representation/generic.rb +30 -29
  73. data/lib/restfulie/common/representation/json.rb +10 -22
  74. data/lib/restfulie/common/representation/json/base.rb +27 -0
  75. data/lib/restfulie/common/representation/json/keys_as_methods.rb +72 -0
  76. data/lib/restfulie/common/representation/json/link.rb +29 -0
  77. data/lib/restfulie/common/representation/json/link_collection.rb +23 -0
  78. data/lib/restfulie/common/representation/xml.rb +18 -227
  79. data/lib/restfulie/server.rb +9 -10
  80. data/lib/restfulie/server/action_controller.rb +10 -12
  81. data/lib/restfulie/server/action_controller/base.rb +18 -15
  82. data/lib/restfulie/server/action_controller/{routing/patch.rb → patch.rb} +0 -0
  83. data/lib/restfulie/server/action_controller/restful_responder.rb +43 -35
  84. data/lib/restfulie/server/action_view.rb +8 -6
  85. data/lib/restfulie/server/action_view/helpers.rb +47 -41
  86. data/lib/restfulie/server/action_view/template_handlers.rb +24 -12
  87. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +17 -12
  88. data/lib/restfulie/server/configuration.rb +22 -19
  89. data/lib/restfulie/server/{restfulie_controller.rb → controller.rb} +1 -10
  90. data/lib/restfulie/server/core_ext.rb +1 -1
  91. data/lib/restfulie/version.rb +14 -0
  92. metadata +52 -16
  93. data/lib/restfulie/client/http/adapter.rb +0 -502
  94. data/lib/restfulie/client/http/atom_ext.rb +0 -4
  95. data/lib/restfulie/client/http/core_ext.rb +0 -6
  96. data/lib/restfulie/client/http/core_ext/http.rb +0 -19
  97. data/lib/restfulie/client/http/marshal.rb +0 -145
  98. data/lib/restfulie/client/http/xml_ext.rb +0 -7
  99. data/lib/restfulie/common/core_ext/proc.rb +0 -48
  100. data/lib/restfulie/common/errors.rb +0 -15
  101. data/lib/restfulie/server/action_controller/routing.rb +0 -12
  102. data/lib/restfulie/server/action_controller/routing/restful_route.rb +0 -14
@@ -1,28 +1,28 @@
1
- module Restfulie::Client::HTTP
2
-
3
- module Cache
4
-
5
- def store
6
- @store || @store = ::ActiveSupport::Cache::MemoryStore.new
7
- end
8
-
9
- def get
10
- store.fetch(@uri) do
11
- request(:get, @uri, @headers)
1
+ module Restfulie
2
+ module Client
3
+ module HTTP
4
+ module Cache
5
+ def store
6
+ @store || @store = ::ActiveSupport::Cache::MemoryStore.new
7
+ end
8
+
9
+ def get
10
+ store.fetch(@uri) do
11
+ request(:get, @uri, @headers)
12
+ end
13
+ end
14
+
15
+ def head
16
+ store.fetch(@uri) do
17
+ request(:head, @uri, @headers)
18
+ end
19
+ end
12
20
  end
13
- end
14
-
15
- def head
16
- store.fetch(@uri) do
17
- request(:head, @uri, @headers)
21
+
22
+ class RequestBuilderExecutorWithCache < RequestBuilderExecutor
23
+ include Cache
18
24
  end
19
25
  end
20
-
21
26
  end
22
-
23
- class RequestBuilderExecutorWithCache < RequestBuilderExecutor
24
- include Cache
25
- end
26
-
27
27
  end
28
28
 
@@ -1,77 +1,77 @@
1
- module Restfulie::Client::HTTP#:nodoc:
2
-
3
- #Client errors
4
- module Error
5
-
1
+ module Restfulie
2
+ module Client
3
+ module HTTP#:nodoc:
4
+ #Client errors
5
+ module Error
6
6
  # Standard error thrown on major client exceptions
7
- class RESTError < StandardError
8
-
9
- attr_reader :response
10
- attr_reader :request
11
-
12
- def initialize(request, response)
13
- @request = request
14
- @response = response
15
- end
16
-
17
- def to_s
18
- "HTTP error #{@response.code} when invoking #{@request.host} via #{@response.method}. " +
19
- ((@response.body.blank?) ? "No additional data was sent." : "The complete response was:\n" + @response.body)
20
- rescue
21
- super
7
+ class RESTError < StandardError
8
+ attr_reader :response
9
+ attr_reader :request
10
+
11
+ def initialize(request, response)
12
+ @request = request
13
+ @response = response
14
+ end
15
+
16
+ def to_s
17
+ "HTTP error #{@response.code} when invoking #{@request.host} via #{@response.method}. " +
18
+ ((@response.body.blank?) ? "No additional data was sent." : "The complete response was:\n" + @response.body)
19
+ rescue
20
+ super
21
+ end
22
22
  end
23
-
24
- end
25
-
26
- class AutoFollowWithoutLocationError < RESTError; end
27
-
28
- #Represents the HTTP code 503
29
- class ServerNotAvailableError < RESTError
30
- def initialize(request, response, exception)
31
- super(request, response)
32
- set_backtrace(exception.backtrace)
23
+
24
+ class AutoFollowWithoutLocationError < RESTError; end
25
+
26
+ # Represents the HTTP code 503
27
+ class ServerNotAvailableError < RESTError
28
+ def initialize(request, response, exception)
29
+ super(request, response)
30
+ set_backtrace(exception.backtrace)
31
+ end
33
32
  end
33
+
34
+ class UnknownError < RESTError; end
35
+
36
+ # Represents the HTTP code 300 range
37
+ class Redirection < RESTError; end
38
+
39
+ class ClientError < RESTError; end
40
+
41
+ # Represents the HTTP code 400
42
+ class BadRequest < ClientError; end
43
+
44
+ # Represents the HTTP code 401
45
+ class Unauthorized < ClientError; end
46
+
47
+ # Represents the HTTP code 403
48
+ class Forbidden < ClientError; end
49
+
50
+ # Represents the HTTP code 404
51
+ class NotFound < ClientError; end
52
+
53
+ # Represents the HTTP code 405
54
+ class MethodNotAllowed < ClientError; end
55
+
56
+ # Represents the HTTP code 412
57
+ class PreconditionFailed < ClientError; end
58
+
59
+ # Represents the HTTP code 407
60
+ class ProxyAuthenticationRequired < ClientError; end
61
+
62
+ # Represents the HTTP code 409
63
+ class Conflict < ClientError; end
64
+
65
+ # Represents the HTTP code 410
66
+ class Gone < ClientError; end
67
+
68
+ # Represents the HTTP code 500
69
+ class ServerError < RESTError; end
70
+
71
+ # Represents the HTTP code 501
72
+ class NotImplemented < ServerError; end
34
73
  end
35
-
36
- class UnknownError < RESTError; end
37
-
38
- #Represents the HTTP code 300 range
39
- class Redirection < RESTError; end
40
-
41
- class ClientError < RESTError; end
42
-
43
- #Represents the HTTP code 400
44
- class BadRequest < ClientError; end
45
-
46
- #Represents the HTTP code 401
47
- class Unauthorized < ClientError; end
48
-
49
- #Represents the HTTP code 403
50
- class Forbidden < ClientError; end
51
-
52
- #Represents the HTTP code 404
53
- class NotFound < ClientError; end
54
-
55
- #Represents the HTTP code 405
56
- class MethodNotAllowed < ClientError; end
57
-
58
- #Represents the HTTP code 412
59
- class PreconditionFailed < ClientError; end
60
-
61
- #Represents the HTTP code 407
62
- class ProxyAuthenticationRequired < ClientError; end
63
-
64
- #Represents the HTTP code 409
65
- class Conflict < ClientError; end
66
-
67
- #Represents the HTTP code 410
68
- class Gone < ClientError; end
69
-
70
- #Represents the HTTP code 500
71
- class ServerError < RESTError; end
72
-
73
- #Represents the HTTP code 501
74
- class NotImplemented < ServerError; end
75
74
  end
75
+ end
76
76
  end
77
77
 
@@ -0,0 +1,15 @@
1
+ module Restfulie
2
+ module Client
3
+ module HTTP
4
+ module LinkRequestBuilder
5
+ include RequestMarshaller
6
+
7
+ def path#:nodoc:
8
+ at(href)
9
+ as(type) if type
10
+ super
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,209 @@
1
+ module Restfulie
2
+ module Client
3
+ module HTTP #:nodoc:
4
+ # Request Adapter provides a minimal interface to exchange information between server over HTTP protocol through simple adapters.
5
+ #
6
+ # All the concrete adapters follow the interface laid down in this module.
7
+ # Default connection provider is net/http
8
+ #
9
+ #==Example
10
+ #
11
+ # @re = ::Restfulie::Client::HTTP::RequestExecutor.new('http://restfulie.com') #this class includes RequestAdapter module.
12
+ # puts @re.as('application/atom+xml').get!('/posts').title #=> 'Hello World!'
13
+ #
14
+ module RequestAdapter
15
+ attr_reader :host
16
+ attr_accessor :cookies
17
+ attr_writer :default_headers
18
+
19
+ def host=(host)
20
+ if host.is_a?(::URI)
21
+ @host = host
22
+ else
23
+ @host = ::URI.parse(host)
24
+ end
25
+ end
26
+
27
+ def default_headers
28
+ @default_headers ||= {}
29
+ end
30
+
31
+ # GET HTTP verb without {Error}
32
+ # * <tt>path: '/posts'</tt>
33
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
34
+ def get(path, *args)
35
+ request(:get, path, *args)
36
+ end
37
+
38
+ # HEAD HTTP verb without {Error}
39
+ # * <tt>path: '/posts'</tt>
40
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
41
+ def head(path, *args)
42
+ request(:head, path, *args)
43
+ end
44
+
45
+ # POST HTTP verb without {Error}
46
+ # * <tt>path: '/posts'</tt>
47
+ # * <tt>payload: 'some text'</tt>
48
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
49
+ def post(path, payload, *args)
50
+ request(:post, path, payload, *args)
51
+ end
52
+
53
+ # PATCH HTTP verb without {Error}
54
+ # * <tt>path: '/posts'</tt>
55
+ # * <tt>payload: 'some text'</tt>
56
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
57
+ def patch(path, payload, *args)
58
+ request(:patch, path, payload, *args)
59
+ end
60
+
61
+ # PUT HTTP verb without {Error}
62
+ # * <tt>path: '/posts'</tt>
63
+ # * <tt>payload: 'some text'</tt>
64
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
65
+ def put(path, payload, *args)
66
+ request(:put, path, payload, *args)
67
+ end
68
+
69
+ # DELETE HTTP verb without {Error}
70
+ # * <tt>path: '/posts'</tt>
71
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
72
+ def delete(path, *args)
73
+ request(:delete, path, *args)
74
+ end
75
+
76
+ # GET HTTP verb {Error}
77
+ # * <tt>path: '/posts'</tt>
78
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
79
+ def get!(path, *args)
80
+ request!(:get, path, *args)
81
+ end
82
+
83
+ # HEAD HTTP verb {Error}
84
+ # * <tt>path: '/posts'</tt>
85
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
86
+ def head!(path, *args)
87
+ request!(:head, path, *args)
88
+ end
89
+
90
+ # POST HTTP verb {Error}
91
+ # * <tt>path: '/posts'</tt>
92
+ # * <tt>payload: 'some text'</tt>
93
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
94
+ def post!(path, payload, *args)
95
+ request!(:post, path, payload, *args)
96
+ end
97
+
98
+ # PATCH HTTP verb {Error}
99
+ # * <tt>path: '/posts'</tt>
100
+ # * <tt>payload: 'some text'</tt>
101
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
102
+ def patch!(path, payload, *args)
103
+ request!(:patch, path, payload, *args)
104
+ end
105
+
106
+ # PUT HTTP verb {Error}
107
+ # * <tt>path: '/posts'</tt>
108
+ # * <tt>payload: 'some text'</tt>
109
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
110
+ def put!(path, payload, *args)
111
+ request!(:put, path, payload, *args)
112
+ end
113
+
114
+ # DELETE HTTP verb {Error}
115
+ # * <tt>path: '/posts'</tt>
116
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
117
+ def delete!(path, *args)
118
+ request!(:delete, path, *args)
119
+ end
120
+
121
+ # Executes a request against your server and return a response instance without {Error}
122
+ # * <tt>method: :get,:post,:delete,:head,:put</tt>
123
+ # * <tt>path: '/posts'</tt>
124
+ # * <tt>args: payload: 'some text' and/or headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
125
+ def request(method, path, *args)
126
+ request!(method, path, *args)
127
+ rescue Error::RESTError => se
128
+ se.response
129
+ end
130
+
131
+ # Executes a request against your server and return a response instance.
132
+ # * <tt>method: :get,:post,:delete,:head,:put</tt>
133
+ # * <tt>path: '/posts'</tt>
134
+ # * <tt>args: payload: 'some text' and/or headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
135
+ def request!(method, path, *args)
136
+ headers = default_headers.merge(args.extract_options!)
137
+ unless @host.user.blank? && @host.password.blank?
138
+ headers["Authorization"] = "Basic " + ["#{@host.user}:#{@host.password}"].pack("m").delete("\r\n")
139
+ end
140
+ headers['cookie'] = @cookies if @cookies
141
+ args << headers
142
+
143
+ ::Restfulie::Common::Logger.logger.info(request_to_s(method, path, *args)) if ::Restfulie::Common::Logger.logger
144
+ begin
145
+ response = ResponseHandler.handle(method, path, get_connection_provider.send(method, path, *args))
146
+ rescue Exception => e
147
+ raise Error::ServerNotAvailableError.new(self, Response.new(method, path, 503, nil, {}), e )
148
+ end
149
+
150
+ case response.code
151
+ when 100..299
152
+ response
153
+ when 300..399
154
+ raise Error::Redirection.new(self, response)
155
+ when 400
156
+ raise Error::BadRequest.new(self, response)
157
+ when 401
158
+ raise Error::Unauthorized.new(self, response)
159
+ when 403
160
+ raise Error::Forbidden.new(self, response)
161
+ when 404
162
+ raise Error::NotFound.new(self, response)
163
+ when 405
164
+ raise Error::MethodNotAllowed.new(self, response)
165
+ when 407
166
+ raise Error::ProxyAuthenticationRequired.new(self, response)
167
+ when 409
168
+ raise Error::Conflict.new(self, response)
169
+ when 410
170
+ raise Error::Gone.new(self, response)
171
+ when 412
172
+ raise Error::PreconditionFailed.new(self, response)
173
+ when 402, 406, 408, 411, 413..499
174
+ raise Error::ClientError.new(self, response)
175
+ when 501
176
+ raise Error::NotImplemented.new(self, response)
177
+ when 500, 502..599
178
+ raise Error::ServerError.new(self, response)
179
+ else
180
+ raise Error::UnknownError.new(self, response)
181
+ end
182
+ end
183
+
184
+ private
185
+
186
+ def get_connection_provider
187
+ @connection ||= ::Net::HTTP.new(@host.host, @host.port)
188
+ end
189
+
190
+ protected
191
+
192
+ def request_to_s(method, path, *args)
193
+ result = ["#{method.to_s.upcase} #{path}"]
194
+
195
+ arguments = args.dup
196
+ headers = arguments.extract_options!
197
+
198
+ if [:post, :put].include?(method)
199
+ body = arguments.shift
200
+ end
201
+
202
+ result << headers.collect { |key, value| "#{key}: #{value}" }.join("\n")
203
+
204
+ (result + [body ? (body.inspect + "\n") : nil]).compact.join("\n") << "\n"
205
+ end
206
+ end
207
+ end
208
+ end
209
+ end
@@ -0,0 +1,107 @@
1
+ module Restfulie
2
+ module Client
3
+ module HTTP #:nodoc:
4
+ # ==== RequestBuilder
5
+ # Uses RequestAdapater to create a HTTP Request DSL
6
+ #
7
+ # ==== Example:
8
+ #
9
+ # @builder = ::Restfulie::Client::HTTP::RequestBuilderExecutor.new("http://restfulie.com") #this class includes RequestBuilder module.
10
+ # @builder.at('/posts').as('application/xml').accepts('application/atom+xml').with('Accept-Language' => 'en').get.code #=> 200
11
+ #
12
+ module RequestBuilder
13
+ include RequestAdapter
14
+
15
+ #Set host
16
+ def at(url)
17
+ self.host = url
18
+ self
19
+ end
20
+
21
+ #Set Content-Type and Accept headers
22
+ def as(content_type)
23
+ headers['Content-Type'] = content_type
24
+ accepts(content_type)
25
+ end
26
+
27
+ #Set Accept headers
28
+ def accepts(content_type)
29
+ headers['Accept'] = content_type
30
+ self
31
+ end
32
+
33
+ # Merge internal header
34
+ #
35
+ # * <tt>headers (e.g. {'Cache-control' => 'no-cache'})</tt>
36
+ #
37
+ def with(headers)
38
+ self.headers.merge!(headers)
39
+ self
40
+ end
41
+
42
+ def headers
43
+ @headers ||= {}
44
+ end
45
+
46
+ # Path (e.g. http://restfulie.com/posts => /posts)
47
+ def path
48
+ host.path
49
+ end
50
+
51
+ def get
52
+ request(:get, path, headers)
53
+ end
54
+
55
+ def head
56
+ request(:head, path, headers)
57
+ end
58
+
59
+ def post(payload)
60
+ request(:post, path, payload, headers)
61
+ end
62
+
63
+ def patch(payload)
64
+ request(:patch, path, payload, headers)
65
+ end
66
+
67
+ def put(payload)
68
+ request(:put, path, payload, headers)
69
+ end
70
+
71
+ def delete
72
+ request(:delete, path, headers)
73
+ end
74
+
75
+ def get!
76
+ request!(:get, path, headers)
77
+ end
78
+
79
+ def head!
80
+ request!(:head, path, headers)
81
+ end
82
+
83
+ def post!(payload)
84
+ request!(:post, path, payload, headers)
85
+ end
86
+
87
+ def patch!(payload)
88
+ request!(:patch, path, payload, headers)
89
+ end
90
+
91
+ def put!(payload)
92
+ request!(:put, path, payload, headers)
93
+ end
94
+
95
+ def delete!
96
+ request!(:delete, path, headers)
97
+ end
98
+
99
+ protected
100
+
101
+ def headers=(h)
102
+ @headers = h
103
+ end
104
+ end
105
+ end
106
+ end
107
+ end