restfulie 0.7.2 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Gemfile +21 -0
- data/README.textile +10 -9
- data/Rakefile +12 -5
- data/lib/restfulie/client/base.rb +10 -6
- data/lib/restfulie/client/http/adapter.rb +48 -33
- data/lib/restfulie/client/http/atom_ext.rb +3 -68
- data/lib/restfulie/client/http/core_ext/http.rb +19 -0
- data/lib/restfulie/client/http/core_ext.rb +6 -0
- data/lib/restfulie/client/http/error.rb +3 -6
- data/lib/restfulie/client/http/marshal.rb +35 -49
- data/lib/restfulie/client/http/xml_ext.rb +7 -0
- data/lib/restfulie/client/http.rb +2 -2
- data/lib/restfulie/client/mikyung/concatenator.rb +15 -0
- data/lib/restfulie/client/mikyung/core.rb +44 -0
- data/lib/restfulie/client/mikyung/languages.rb +29 -0
- data/lib/restfulie/client/mikyung/rest_process_model.rb +114 -0
- data/lib/restfulie/client/mikyung/steady_state_walker.rb +32 -0
- data/lib/restfulie/client/mikyung/then_condition.rb +33 -0
- data/lib/restfulie/client/mikyung/when_condition.rb +53 -0
- data/lib/restfulie/client/mikyung.rb +19 -0
- data/lib/restfulie/client.rb +1 -0
- data/lib/restfulie/common/converter/atom/builder.rb +109 -0
- data/lib/restfulie/common/converter/atom/helpers.rb +9 -0
- data/lib/restfulie/common/converter/atom.rb +87 -0
- data/lib/restfulie/common/converter/values.rb +29 -0
- data/lib/restfulie/common/converter.rb +11 -0
- data/lib/restfulie/common/core_ext/proc.rb +48 -0
- data/lib/restfulie/common/core_ext.rb +5 -0
- data/lib/restfulie/common/errors.rb +6 -0
- data/lib/restfulie/common/representation/atom/atom.rng +597 -0
- data/lib/restfulie/common/representation/atom/base.rb +375 -0
- data/lib/restfulie/common/representation/atom/entry.rb +107 -0
- data/lib/restfulie/common/representation/atom/feed.rb +106 -0
- data/lib/restfulie/common/representation/atom.rb +43 -33
- data/lib/restfulie/common/representation/json.rb +1 -2
- data/lib/restfulie/common/representation/xml.rb +209 -23
- data/lib/restfulie/common/representation.rb +0 -1
- data/lib/restfulie/common.rb +2 -3
- data/lib/restfulie/server/action_controller/base.rb +21 -2
- data/lib/restfulie/server/action_controller/params_parser.rb +16 -16
- data/lib/restfulie/server/action_controller/restful_responder.rb +3 -3
- data/lib/restfulie/server/action_controller/routing/patch.rb +6 -0
- data/lib/restfulie/server/action_view/helpers.rb +8 -8
- data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +3 -2
- data/lib/restfulie/server/core_ext/array.rb +13 -12
- metadata +51 -34
- data/lib/restfulie/client/http/link.rb +0 -39
- data/lib/restfulie/client/http/xml.rb +0 -4
- data/lib/restfulie/common/builder/builder_base.rb +0 -73
- data/lib/restfulie/common/builder/helpers.rb +0 -22
- data/lib/restfulie/common/builder/marshalling/atom.rb +0 -197
- data/lib/restfulie/common/builder/marshalling/base.rb +0 -12
- data/lib/restfulie/common/builder/marshalling/json.rb +0 -2
- data/lib/restfulie/common/builder/marshalling/xml.rb +0 -183
- data/lib/restfulie/common/builder/marshalling.rb +0 -16
- data/lib/restfulie/common/builder/rules/collection_rule.rb +0 -10
- data/lib/restfulie/common/builder/rules/custom_attributes.rb +0 -24
- data/lib/restfulie/common/builder/rules/link.rb +0 -20
- data/lib/restfulie/common/builder/rules/links.rb +0 -9
- data/lib/restfulie/common/builder/rules/member_rule.rb +0 -8
- data/lib/restfulie/common/builder/rules/namespace.rb +0 -35
- data/lib/restfulie/common/builder/rules/rules_base.rb +0 -77
- data/lib/restfulie/common/builder.rb +0 -17
- data/lib/vendor/atom/configuration.rb +0 -24
- data/lib/vendor/atom/pub.rb +0 -250
- data/lib/vendor/atom/xml/parser.rb +0 -373
- data/lib/vendor/atom.rb +0 -771
data/Gemfile
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# A sample Gemfile
|
2
|
+
source :gemcutter
|
3
|
+
#
|
4
|
+
gem "rails"
|
5
|
+
gem "libxml-ruby"
|
6
|
+
|
7
|
+
|
8
|
+
gem "rack-conneg"
|
9
|
+
gem "responders_backport"
|
10
|
+
gem "json_pure"
|
11
|
+
gem "sqlite3-ruby"
|
12
|
+
gem "yard"
|
13
|
+
gem "ruby-debug"
|
14
|
+
|
15
|
+
group :test do
|
16
|
+
gem "nokogiri"
|
17
|
+
gem "rspec-rails"
|
18
|
+
gem "rcov"
|
19
|
+
gem "sinatra"
|
20
|
+
end
|
21
|
+
|
data/README.textile
CHANGED
@@ -50,10 +50,13 @@ In the server side, all you need to do is notify inherited_resources which media
|
|
50
50
|
That's it. Restfulie will take care of rendering a valid representation according to content negotiation. You can configure the rendering process through a custom tokamak view:
|
51
51
|
|
52
52
|
<pre>
|
53
|
-
|
54
|
-
collection.
|
55
|
-
|
56
|
-
|
53
|
+
collection(@orders) do |collection|
|
54
|
+
collection.values do |value|
|
55
|
+
value.id = orders_url
|
56
|
+
end
|
57
|
+
|
58
|
+
collection.link("create", orders_url)
|
59
|
+
collection.members
|
57
60
|
end
|
58
61
|
</pre>
|
59
62
|
|
@@ -95,13 +98,11 @@ gem install restfulie
|
|
95
98
|
|
96
99
|
h2. Building the project
|
97
100
|
|
98
|
-
If you want to build the project and run its tests, remember to install all (client and server) required
|
101
|
+
If you want to build the project and run its tests, remember to install all (client and server) required gem.
|
102
|
+
"Bundler":http://gembundler.com/ is required to easily manage dependencies
|
99
103
|
|
100
104
|
<pre>
|
101
|
-
|
102
|
-
gem install responders_backport
|
103
|
-
gem install json_pure
|
104
|
-
gem install sqlite3-ruby
|
105
|
+
bundle install
|
105
106
|
</pre>
|
106
107
|
|
107
108
|
<script type="text/javascript">
|
data/Rakefile
CHANGED
@@ -6,19 +6,21 @@ require 'spec/rake/spectask'
|
|
6
6
|
require 'rake/rdoctask'
|
7
7
|
|
8
8
|
GEM = "restfulie"
|
9
|
-
GEM_VERSION = "0.
|
9
|
+
GEM_VERSION = "0.8.0"
|
10
10
|
SUMMARY = "Hypermedia aware resource based library in ruby (client side) and ruby on rails (server side)."
|
11
|
-
AUTHOR = "Guilherme Silveira, Caue Guerra"
|
11
|
+
AUTHOR = "Guilherme Silveira, Caue Guerra, Luis Cipriani, Éverton Ribeiro, George Guimarães, Paulo Ahagon"
|
12
12
|
EMAIL = "guilherme.silveira@caelum.com.br"
|
13
13
|
HOMEPAGE = "http://restfulie.caelumobjects.com"
|
14
14
|
|
15
|
+
|
15
16
|
spec = Gem::Specification.new do |s|
|
16
17
|
s.name = GEM
|
17
18
|
s.version = GEM_VERSION
|
18
19
|
s.platform = Gem::Platform::RUBY
|
19
20
|
s.summary = SUMMARY
|
20
21
|
s.require_paths = ['lib']
|
21
|
-
s.files = FileList['lib/**/*.rb', '[A-Z]*'].to_a
|
22
|
+
s.files = FileList['lib/**/*.rb', '[A-Z]*', 'lib/**/*.rng'].to_a
|
23
|
+
s.add_dependency("nokogiri", [">= 1.4.2"])
|
22
24
|
s.add_dependency("actionpack", [">= 2.3.2"])
|
23
25
|
s.add_dependency("activesupport", [">= 2.3.2"])
|
24
26
|
s.add_dependency("responders_backport", ["~> 0.1.0"])
|
@@ -31,7 +33,8 @@ end
|
|
31
33
|
|
32
34
|
namespace :test do
|
33
35
|
def execute_process(name)
|
34
|
-
sh "ruby ./spec/units/client/#{name}.rb &"
|
36
|
+
sh "ruby ./spec/units/client/#{name}.rb &"
|
37
|
+
sleep 15
|
35
38
|
%x(ps -ef | grep #{name}).split[1]
|
36
39
|
end
|
37
40
|
def process(name)
|
@@ -82,6 +85,10 @@ namespace :test do
|
|
82
85
|
t.rcov = true
|
83
86
|
t.rcov_opts = ["-e", "/Library*", "-e", "~/.rvm", "-e", "spec", "-i", "bin"]
|
84
87
|
end
|
88
|
+
desc 'Run coverage test with fake server'
|
89
|
+
task :run do
|
90
|
+
start_server_and_invoke_test('test:rcov:rcov')
|
91
|
+
end
|
85
92
|
end
|
86
93
|
|
87
94
|
namespace :run do
|
@@ -120,7 +127,7 @@ begin
|
|
120
127
|
t.files = ['lib/restfulie/**/*.rb', 'README.textile'] # optional
|
121
128
|
# t.options = ['--any', '--extra', '--opts'] # optional
|
122
129
|
end
|
123
|
-
rescue; end
|
130
|
+
rescue LoadError; end
|
124
131
|
|
125
132
|
desc "Install the gem locally"
|
126
133
|
task :install => [:package] do
|
@@ -4,6 +4,12 @@ module Restfulie::Client#:nodoc
|
|
4
4
|
include HTTP::RequestMarshaller
|
5
5
|
extend self
|
6
6
|
|
7
|
+
def recipe(converter_sym, options={}, &block)
|
8
|
+
raise 'Undefined block' unless block_given?
|
9
|
+
converter = "Restfulie::Common::Converter::#{converter_sym.to_s.camelize}".constantize
|
10
|
+
converter.describe_recipe(options[:name], &block)
|
11
|
+
end
|
12
|
+
|
7
13
|
@resources_configurations = {}
|
8
14
|
def configuration_of(resource_name)
|
9
15
|
@resources_configurations[resource_name]
|
@@ -16,16 +22,12 @@ module Restfulie::Client#:nodoc
|
|
16
22
|
|
17
23
|
def retrieve(resource_name)
|
18
24
|
returning Object.new do |resource|
|
19
|
-
|
25
|
+
resource.extend(Base)
|
20
26
|
resource.configure
|
21
27
|
end
|
22
28
|
end
|
23
29
|
|
24
30
|
end
|
25
|
-
class NilEntryPoint
|
26
|
-
include Restfulie::Client::EntryPoint
|
27
|
-
# extend self
|
28
|
-
end
|
29
31
|
|
30
32
|
module Base
|
31
33
|
include HTTP::RequestMarshaller
|
@@ -59,8 +61,10 @@ end
|
|
59
61
|
|
60
62
|
# Shortcut to Restfulie::Client::EntryPoint
|
61
63
|
module Restfulie
|
64
|
+
extend Restfulie::Client::EntryPoint
|
65
|
+
|
62
66
|
def self.at(uri)
|
63
|
-
Client::
|
67
|
+
Object.new.send(:extend, Restfulie::Client::EntryPoint).at(uri)
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
@@ -9,21 +9,15 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
9
9
|
attr_reader :code
|
10
10
|
attr_reader :body
|
11
11
|
attr_reader :headers
|
12
|
-
attr_reader :request
|
13
12
|
|
14
|
-
def initialize(method, path, code, body, headers
|
13
|
+
def initialize(method, path, code, body, headers)
|
15
14
|
@method = method
|
16
15
|
@path = path
|
17
16
|
@code = code
|
18
17
|
@body = body
|
19
18
|
@headers = headers
|
20
|
-
@request = request
|
21
19
|
end
|
22
20
|
|
23
|
-
def parse
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
21
|
end
|
28
22
|
|
29
23
|
#=ResponseHandler
|
@@ -81,11 +75,11 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
81
75
|
# *<tt>path: '/posts'</tt>
|
82
76
|
# *<tt>http_response</tt>
|
83
77
|
#
|
84
|
-
def self.handle(method, path, http_response
|
78
|
+
def self.handle(method, path, http_response)
|
85
79
|
response_class = @@response_handlers[http_response.code.to_i] || Response
|
86
80
|
headers = {}
|
87
81
|
http_response.header.each { |k, v| headers[k] = v }
|
88
|
-
response_class.new( method, path, http_response.code.to_i, http_response.body, headers
|
82
|
+
response_class.new( method, path, http_response.code.to_i, http_response.body, headers)
|
89
83
|
end
|
90
84
|
|
91
85
|
end
|
@@ -121,14 +115,14 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
121
115
|
|
122
116
|
#GET HTTP verb without {Error}
|
123
117
|
# * <tt>path: '/posts'</tt>
|
124
|
-
# * <tt>headers: {'
|
118
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
125
119
|
def get(path, *args)
|
126
120
|
request(:get, path, *args)
|
127
121
|
end
|
128
122
|
|
129
123
|
#HEAD HTTP verb without {Error}
|
130
124
|
# * <tt>path: '/posts'</tt>
|
131
|
-
# * <tt>headers: {'
|
125
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
132
126
|
def head(path, *args)
|
133
127
|
request(:head, path, *args)
|
134
128
|
end
|
@@ -136,36 +130,44 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
136
130
|
#POST HTTP verb without {Error}
|
137
131
|
# * <tt>path: '/posts'</tt>
|
138
132
|
# * <tt>payload: 'some text'</tt>
|
139
|
-
# * <tt>headers: {'
|
133
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
140
134
|
def post(path, payload, *args)
|
141
135
|
request(:post, path, payload, *args)
|
142
136
|
end
|
137
|
+
|
138
|
+
#PATCH HTTP verb without {Error}
|
139
|
+
# * <tt>path: '/posts'</tt>
|
140
|
+
# * <tt>payload: 'some text'</tt>
|
141
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
142
|
+
def patch(path, payload, *args)
|
143
|
+
request(:patch, path, payload, *args)
|
144
|
+
end
|
143
145
|
|
144
146
|
#PUT HTTP verb without {Error}
|
145
147
|
# * <tt>path: '/posts'</tt>
|
146
148
|
# * <tt>payload: 'some text'</tt>
|
147
|
-
# * <tt>headers: {'
|
149
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
148
150
|
def put(path, payload, *args)
|
149
151
|
request(:put, path, payload, *args)
|
150
152
|
end
|
151
153
|
|
152
154
|
#DELETE HTTP verb without {Error}
|
153
155
|
# * <tt>path: '/posts'</tt>
|
154
|
-
# * <tt>headers: {'
|
156
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
155
157
|
def delete(path, *args)
|
156
158
|
request(:delete, path, *args)
|
157
159
|
end
|
158
160
|
|
159
161
|
#GET HTTP verb {Error}
|
160
162
|
# * <tt>path: '/posts'</tt>
|
161
|
-
# * <tt>headers: {'
|
163
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
162
164
|
def get!(path, *args)
|
163
165
|
request!(:get, path, *args)
|
164
166
|
end
|
165
167
|
|
166
168
|
#HEAD HTTP verb {Error}
|
167
169
|
# * <tt>path: '/posts'</tt>
|
168
|
-
# * <tt>headers: {'
|
170
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
169
171
|
def head!(path, *args)
|
170
172
|
request!(:head, path, *args)
|
171
173
|
end
|
@@ -173,22 +175,30 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
173
175
|
#POST HTTP verb {Error}
|
174
176
|
# * <tt>path: '/posts'</tt>
|
175
177
|
# * <tt>payload: 'some text'</tt>
|
176
|
-
# * <tt>headers: {'
|
178
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
177
179
|
def post!(path, payload, *args)
|
178
180
|
request!(:post, path, payload, *args)
|
179
181
|
end
|
182
|
+
|
183
|
+
#PATCH HTTP verb {Error}
|
184
|
+
# * <tt>path: '/posts'</tt>
|
185
|
+
# * <tt>payload: 'some text'</tt>
|
186
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
187
|
+
def patch!(path, payload, *args)
|
188
|
+
request!(:patch, path, payload, *args)
|
189
|
+
end
|
180
190
|
|
181
191
|
#PUT HTTP verb {Error}
|
182
192
|
# * <tt>path: '/posts'</tt>
|
183
193
|
# * <tt>payload: 'some text'</tt>
|
184
|
-
# * <tt>headers: {'
|
194
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
185
195
|
def put!(path, payload, *args)
|
186
196
|
request!(:put, path, payload, *args)
|
187
197
|
end
|
188
198
|
|
189
199
|
#DELETE HTTP verb {Error}
|
190
200
|
# * <tt>path: '/posts'</tt>
|
191
|
-
# * <tt>headers: {'
|
201
|
+
# * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
192
202
|
def delete!(path, *args)
|
193
203
|
request!(:delete, path, *args)
|
194
204
|
end
|
@@ -196,7 +206,7 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
196
206
|
#Executes a request against your server and return a response instance without {Error}
|
197
207
|
# * <tt>method: :get,:post,:delete,:head,:put</tt>
|
198
208
|
# * <tt>path: '/posts'</tt>
|
199
|
-
# * <tt>args: payload: 'some text' and/or headers: {'
|
209
|
+
# * <tt>args: payload: 'some text' and/or headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
200
210
|
def request(method, path, *args)
|
201
211
|
request!(method, path, *args)
|
202
212
|
rescue Error::RESTError => se
|
@@ -206,7 +216,7 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
206
216
|
#Executes a request against your server and return a response instance.
|
207
217
|
# * <tt>method: :get,:post,:delete,:head,:put</tt>
|
208
218
|
# * <tt>path: '/posts'</tt>
|
209
|
-
# * <tt>args: payload: 'some text' and/or headers: {'
|
219
|
+
# * <tt>args: payload: 'some text' and/or headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
|
210
220
|
def request!(method, path, *args)
|
211
221
|
headers = default_headers.merge(args.extract_options!)
|
212
222
|
unless @host.user.blank? && @host.password.blank?
|
@@ -217,10 +227,9 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
217
227
|
|
218
228
|
::Restfulie::Common::Logger.logger.info(request_to_s(method, path, *args)) if ::Restfulie::Common::Logger.logger
|
219
229
|
begin
|
220
|
-
|
221
|
-
response = ResponseHandler.handle(method, path, connection, self).parse
|
230
|
+
response = ResponseHandler.handle(method, path, get_connection_provider.send(method, path, *args))
|
222
231
|
rescue Exception => e
|
223
|
-
raise Error::ServerNotAvailableError.new(self, Response.new(method, path, 503, nil, {}
|
232
|
+
raise Error::ServerNotAvailableError.new(self, Response.new(method, path, 503, nil, {}), e )
|
224
233
|
end
|
225
234
|
|
226
235
|
case response.code
|
@@ -342,6 +351,10 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
342
351
|
request(:post, path, payload, headers)
|
343
352
|
end
|
344
353
|
|
354
|
+
def patch(payload)
|
355
|
+
request(:patch, path, payload, headers)
|
356
|
+
end
|
357
|
+
|
345
358
|
def put(payload)
|
346
359
|
request(:put, path, payload, headers)
|
347
360
|
end
|
@@ -362,6 +375,10 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
362
375
|
request!(:post, path, payload, headers)
|
363
376
|
end
|
364
377
|
|
378
|
+
def patch!(payload)
|
379
|
+
request!(:patch, path, payload, headers)
|
380
|
+
end
|
381
|
+
|
365
382
|
def put!(payload)
|
366
383
|
request!(:put, path, payload, headers)
|
367
384
|
end
|
@@ -378,6 +395,7 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
378
395
|
|
379
396
|
end
|
380
397
|
|
398
|
+
|
381
399
|
#=RequestHistory
|
382
400
|
# Uses RequestBuilder and remind previous requests
|
383
401
|
#
|
@@ -386,7 +404,7 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
386
404
|
# @executor = ::Restfulie::Client::HTTP::RequestHistoryExecutor.new("http://restfulie.com") #this class includes RequestHistory module.
|
387
405
|
# @executor.at('/posts').as('application/xml').accepts('application/atom+xml').with('Accept-Language' => 'en').get.code #=> 200 #first request
|
388
406
|
# @executor.at('/blogs').as('application/xml').accepts('application/atom+xml').with('Accept-Language' => 'en').get.code #=> 200 #second request
|
389
|
-
# @executor.request_history!(0) #doing first request
|
407
|
+
# @executor.request_history!(0) #doing first request
|
390
408
|
#
|
391
409
|
module RequestHistory
|
392
410
|
include RequestBuilder
|
@@ -457,29 +475,26 @@ module Restfulie::Client::HTTP #:nodoc:
|
|
457
475
|
end
|
458
476
|
|
459
477
|
#=This class includes RequestBuilder module.
|
460
|
-
class RequestBuilderExecutor
|
478
|
+
class RequestBuilderExecutor < RequestExecutor
|
461
479
|
include RequestBuilder
|
462
480
|
|
463
|
-
# * <tt> host (e.g. 'http://restfulie.com') </tt>
|
464
|
-
# * <tt> default_headers (e.g. {'Cache-control' => 'no-cache'} ) </tt>
|
465
|
-
def initialize(host, default_headers = {})
|
466
|
-
self.host=host
|
467
|
-
self.default_headers=default_headers
|
468
|
-
end
|
469
481
|
def host=(host)
|
470
482
|
super
|
471
483
|
at(self.host.path)
|
472
484
|
end
|
485
|
+
|
473
486
|
def at(path)
|
474
487
|
@path = path
|
475
488
|
self
|
476
489
|
end
|
490
|
+
|
477
491
|
def path
|
478
492
|
@path
|
479
493
|
end
|
494
|
+
|
480
495
|
end
|
481
496
|
|
482
|
-
#=This class inherits
|
497
|
+
#=This class inherits RequestFollowExecutor and include RequestHistory module.
|
483
498
|
class RequestHistoryExecutor < RequestBuilderExecutor
|
484
499
|
include RequestHistory
|
485
500
|
end
|
@@ -1,69 +1,4 @@
|
|
1
1
|
module Restfulie::Client::HTTP#:nodoc:
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
def method_missing(method_sym,*args)
|
6
|
-
return super(method_sym, *args) unless simple_extensions
|
7
|
-
|
8
|
-
found = find_extension_entry_for(method_sym)
|
9
|
-
return super(method_sym, *args) if found.empty?
|
10
|
-
result = found.collect do |pair|
|
11
|
-
pair.last.length==1 ? pair.last.first : pair.last
|
12
|
-
end
|
13
|
-
result.length==1 ? result.first : result
|
14
|
-
end
|
15
|
-
|
16
|
-
def respond_to?(method_sym)
|
17
|
-
return super(method_sym) unless simple_extensions
|
18
|
-
|
19
|
-
found = find_extension_entry_for(method_sym)
|
20
|
-
(found.length!=0) || super(method_sym)
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
def find_extension_entry_for(method_sym)
|
25
|
-
start = -(method_sym.to_s.length + 1)
|
26
|
-
found = simple_extensions.select do |k, v|
|
27
|
-
method_sym.to_s == k[start..-2]
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
# Offers a way to access Atom entries element's in namespaced extensions.
|
33
|
-
module AtomElementShortcut
|
34
|
-
def method_missing(method_sym,*args)
|
35
|
-
return super(method_sym, *args) unless simple_extensions
|
36
|
-
|
37
|
-
start = -(method_sym.to_s.length + 1)
|
38
|
-
found = simple_extensions.select do |k, v|
|
39
|
-
method_sym.to_s == k[start..-2]
|
40
|
-
end
|
41
|
-
return super(method_sym, *args) if found.empty?
|
42
|
-
result = found.collect do |pair|
|
43
|
-
pair.last.length==1 ? pair.last.first : pair.last
|
44
|
-
end
|
45
|
-
result.length==1 ? result.first : result
|
46
|
-
end
|
47
|
-
end
|
48
|
-
|
49
|
-
# inject new behavior in rAtom instances to enable easily access to link relationships.
|
50
|
-
::Atom::Feed.instance_eval {
|
51
|
-
include Restfulie::Client::LinkShortcut
|
52
|
-
include AtomElementShortcut
|
53
|
-
}
|
54
|
-
::Atom::Entry.instance_eval {
|
55
|
-
include Restfulie::Client::LinkShortcut
|
56
|
-
include AtomElementShortcut
|
57
|
-
}
|
58
|
-
::Atom::Link.instance_eval {
|
59
|
-
include Restfulie::Client::HTTP::LinkRequestBuilder
|
60
|
-
}
|
61
|
-
|
62
|
-
end
|
63
|
-
|
64
|
-
|
65
|
-
class Atom::Link
|
66
|
-
def content_type
|
67
|
-
type
|
68
|
-
end
|
69
|
-
end
|
2
|
+
# inject new behavior in Atom instances to enable easily access to link relationships.
|
3
|
+
::Restfulie::Common::Representation::Atom::Link.instance_eval { include LinkRequestBuilder }
|
4
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Net::HTTP::Patch < Net::HTTP::Get
|
2
|
+
METHOD = "PATCH"
|
3
|
+
end
|
4
|
+
|
5
|
+
# Definition of a patch method in the same way that post works
|
6
|
+
class Net::HTTP
|
7
|
+
def patch(path, data, initheader = nil, dest = nil, &block) # :yield: +body_segment+
|
8
|
+
res = nil
|
9
|
+
request(Patch.new(path, initheader), data) {|r|
|
10
|
+
r.read_body dest, &block
|
11
|
+
res = r
|
12
|
+
}
|
13
|
+
unless @newimpl
|
14
|
+
res.value
|
15
|
+
return res, res.body
|
16
|
+
end
|
17
|
+
res
|
18
|
+
end
|
19
|
+
end
|
@@ -3,11 +3,6 @@ module Restfulie::Client::HTTP#:nodoc:
|
|
3
3
|
#Client errors
|
4
4
|
module Error
|
5
5
|
|
6
|
-
#Generic error class and superclass of all other errors raised by client restfulie
|
7
|
-
class BaseError < StandardError; end
|
8
|
-
|
9
|
-
class TranslationError < BaseError; end
|
10
|
-
|
11
6
|
# Standard error thrown on major client exceptions
|
12
7
|
class RESTError < StandardError
|
13
8
|
|
@@ -20,13 +15,15 @@ module Restfulie::Client::HTTP#:nodoc:
|
|
20
15
|
end
|
21
16
|
|
22
17
|
def to_s
|
23
|
-
"HTTP error #{@response.code} when invoking #{@request.host}
|
18
|
+
"HTTP error #{@response.code} when invoking #{@request.host} via #{@response.method}. " +
|
24
19
|
((@response.body.blank?) ? "No additional data was sent." : "The complete response was:\n" + @response.body)
|
25
20
|
rescue
|
26
21
|
super
|
27
22
|
end
|
28
23
|
|
29
24
|
end
|
25
|
+
|
26
|
+
class AutoFollowWithoutLocationError < RESTError; end
|
30
27
|
|
31
28
|
#Represents the HTTP code 503
|
32
29
|
class ServerNotAvailableError < RESTError
|
@@ -3,48 +3,30 @@ module Restfulie::Client::HTTP
|
|
3
3
|
|
4
4
|
module ResponseHolder
|
5
5
|
attr_accessor :response
|
6
|
-
|
7
|
-
def respond_to?(symbol)
|
8
|
-
super(symbol) || (super(:links) && respond_to_rel?(symbol.to_s))
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
# whether this response contains specific relations
|
13
|
-
def respond_to_rel?(rel)
|
14
|
-
links.any? { |link| link.rel==rel }
|
15
|
-
end
|
16
|
-
|
17
6
|
end
|
18
7
|
|
19
8
|
module RequestMarshaller
|
20
|
-
include ::Restfulie::Client::HTTP::
|
9
|
+
include ::Restfulie::Client::HTTP::RequestHistory
|
21
10
|
|
22
|
-
# accepts a series of media types by default
|
23
|
-
def initialize
|
24
|
-
end
|
25
|
-
|
26
11
|
@@representations = {
|
27
|
-
'application/atom+xml' => ::Restfulie::Common::
|
12
|
+
'application/atom+xml' => ::Restfulie::Common::Converter::Atom
|
28
13
|
}
|
29
14
|
def self.register_representation(media_type,representation)
|
30
15
|
@@representations[media_type] = representation
|
31
16
|
end
|
32
17
|
|
33
|
-
RequestMarshaller.register_representation('application/xml', ::Restfulie::Common::
|
34
|
-
RequestMarshaller.register_representation('text/xml', ::Restfulie::Common::
|
18
|
+
RequestMarshaller.register_representation('application/xml', ::Restfulie::Common::Converter::Xml)
|
19
|
+
RequestMarshaller.register_representation('text/xml', ::Restfulie::Common::Converter::Xml)
|
35
20
|
RequestMarshaller.register_representation('application/json', ::Restfulie::Common::Representation::Json)
|
36
21
|
|
37
22
|
def self.content_type_for(media_type)
|
38
23
|
return nil unless media_type
|
39
24
|
content_type = media_type.split(';')[0] # [/(.*?);/, 1]
|
40
|
-
|
41
|
-
type ? type.new : nil
|
25
|
+
@@representations[content_type]
|
42
26
|
end
|
43
27
|
|
44
28
|
def accepts(media_types)
|
45
|
-
@acceptable_mediatypes = media_types
|
46
29
|
@default_representation = @@representations[media_types]
|
47
|
-
raise "Undefined representation for #{media_types}" unless @default_representation
|
48
30
|
super
|
49
31
|
end
|
50
32
|
|
@@ -53,16 +35,26 @@ module Restfulie::Client::HTTP
|
|
53
35
|
self
|
54
36
|
end
|
55
37
|
|
56
|
-
|
57
|
-
|
58
|
-
|
38
|
+
def post(payload, options = { :recipe => nil })
|
39
|
+
request(:post, path, payload, options.merge(headers))
|
40
|
+
end
|
41
|
+
|
42
|
+
def post!(payload, options = { :recipe => nil })
|
43
|
+
request!(:post, path, payload, options.merge(headers))
|
44
|
+
end
|
45
|
+
|
46
|
+
#Executes super if its a raw request, returning the content itself.
|
47
|
+
#otherwise tries to parse the content with a mediatype handler or returns the response itself.
|
48
|
+
def request!(method, path, *args)
|
59
49
|
if has_payload?(method, path, *args)
|
50
|
+
recipe = get_recipe(*args)
|
51
|
+
|
60
52
|
payload = get_payload(method, path, *args)
|
61
53
|
rel = self.respond_to?(:rel) ? self.rel : ""
|
62
54
|
type = headers['Content-Type']
|
63
55
|
raise Restfulie::Common::Error::RestfulieError, "Missing content type related to the data to be submitted" unless type
|
64
56
|
marshaller = RequestMarshaller.content_type_for(type)
|
65
|
-
payload = marshaller.marshal(payload, rel)
|
57
|
+
payload = marshaller.marshal(payload, { :rel => rel, :recipe => recipe })
|
66
58
|
args = set_marshalled_payload(method, path, payload, *args)
|
67
59
|
args = add_representation_headers(method, path, marshaller, *args)
|
68
60
|
end
|
@@ -78,7 +70,6 @@ module Restfulie::Client::HTTP
|
|
78
70
|
|
79
71
|
private
|
80
72
|
|
81
|
-
|
82
73
|
# parses the http response.
|
83
74
|
# first checks if its a 201, redirecting to the resource location.
|
84
75
|
# otherwise check if its a raw request, returning the content itself.
|
@@ -97,12 +88,21 @@ module Restfulie::Client::HTTP
|
|
97
88
|
unmarshalled.response = response
|
98
89
|
unmarshalled
|
99
90
|
else
|
91
|
+
response.extend(ResponseHolder)
|
92
|
+
response.response = response
|
100
93
|
response
|
101
94
|
end
|
102
95
|
end
|
103
|
-
|
96
|
+
|
97
|
+
def get_recipe(*args)
|
98
|
+
headers_and_recipe = args.extract_options!
|
99
|
+
recipe = headers_and_recipe.delete(:recipe)
|
100
|
+
args << headers_and_recipe
|
101
|
+
recipe
|
102
|
+
end
|
103
|
+
|
104
104
|
def has_payload?(method, path, *args)
|
105
|
-
[:put,:post].include?(method)
|
105
|
+
[:put,:post,:patch].include?(method)
|
106
106
|
end
|
107
107
|
|
108
108
|
def get_payload(method, path, *args)
|
@@ -126,34 +126,20 @@ module Restfulie::Client::HTTP
|
|
126
126
|
|
127
127
|
end
|
128
128
|
|
129
|
-
#
|
129
|
+
# NOTE: When including this module remember to override the type method to return
|
130
|
+
# a valid content type as a string.
|
130
131
|
module LinkRequestBuilder
|
131
|
-
include
|
132
|
+
include RequestMarshaller
|
132
133
|
def path#:nodoc:
|
133
134
|
at(href)
|
134
|
-
as(
|
135
|
+
as(type) if type
|
135
136
|
super
|
136
137
|
end
|
137
138
|
end
|
138
139
|
|
139
140
|
#=This class includes RequestBuilder module.
|
140
|
-
class RequestMarshallerExecutor
|
141
|
+
class RequestMarshallerExecutor < RequestHistoryExecutor
|
141
142
|
include RequestMarshaller
|
142
|
-
|
143
|
-
# * <tt> host (e.g. 'http://restfulie.com') </tt>
|
144
|
-
# * <tt> default_headers (e.g. {'Cache-control' => 'no-cache'} ) </tt>
|
145
|
-
def initialize(host, default_headers = {})
|
146
|
-
self.host=host
|
147
|
-
self.default_headers=default_headers
|
148
|
-
end
|
149
|
-
|
150
|
-
def at(path)
|
151
|
-
@path = path
|
152
|
-
self
|
153
|
-
end
|
154
|
-
def path
|
155
|
-
@path
|
156
|
-
end
|
157
143
|
end
|
158
144
|
|
159
145
|
end
|