restfulie 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/Gemfile +21 -0
  2. data/README.textile +10 -9
  3. data/Rakefile +12 -5
  4. data/lib/restfulie/client/base.rb +10 -6
  5. data/lib/restfulie/client/http/adapter.rb +48 -33
  6. data/lib/restfulie/client/http/atom_ext.rb +3 -68
  7. data/lib/restfulie/client/http/core_ext/http.rb +19 -0
  8. data/lib/restfulie/client/http/core_ext.rb +6 -0
  9. data/lib/restfulie/client/http/error.rb +3 -6
  10. data/lib/restfulie/client/http/marshal.rb +35 -49
  11. data/lib/restfulie/client/http/xml_ext.rb +7 -0
  12. data/lib/restfulie/client/http.rb +2 -2
  13. data/lib/restfulie/client/mikyung/concatenator.rb +15 -0
  14. data/lib/restfulie/client/mikyung/core.rb +44 -0
  15. data/lib/restfulie/client/mikyung/languages.rb +29 -0
  16. data/lib/restfulie/client/mikyung/rest_process_model.rb +114 -0
  17. data/lib/restfulie/client/mikyung/steady_state_walker.rb +32 -0
  18. data/lib/restfulie/client/mikyung/then_condition.rb +33 -0
  19. data/lib/restfulie/client/mikyung/when_condition.rb +53 -0
  20. data/lib/restfulie/client/mikyung.rb +19 -0
  21. data/lib/restfulie/client.rb +1 -0
  22. data/lib/restfulie/common/converter/atom/builder.rb +109 -0
  23. data/lib/restfulie/common/converter/atom/helpers.rb +9 -0
  24. data/lib/restfulie/common/converter/atom.rb +87 -0
  25. data/lib/restfulie/common/converter/values.rb +29 -0
  26. data/lib/restfulie/common/converter.rb +11 -0
  27. data/lib/restfulie/common/core_ext/proc.rb +48 -0
  28. data/lib/restfulie/common/core_ext.rb +5 -0
  29. data/lib/restfulie/common/errors.rb +6 -0
  30. data/lib/restfulie/common/representation/atom/atom.rng +597 -0
  31. data/lib/restfulie/common/representation/atom/base.rb +375 -0
  32. data/lib/restfulie/common/representation/atom/entry.rb +107 -0
  33. data/lib/restfulie/common/representation/atom/feed.rb +106 -0
  34. data/lib/restfulie/common/representation/atom.rb +43 -33
  35. data/lib/restfulie/common/representation/json.rb +1 -2
  36. data/lib/restfulie/common/representation/xml.rb +209 -23
  37. data/lib/restfulie/common/representation.rb +0 -1
  38. data/lib/restfulie/common.rb +2 -3
  39. data/lib/restfulie/server/action_controller/base.rb +21 -2
  40. data/lib/restfulie/server/action_controller/params_parser.rb +16 -16
  41. data/lib/restfulie/server/action_controller/restful_responder.rb +3 -3
  42. data/lib/restfulie/server/action_controller/routing/patch.rb +6 -0
  43. data/lib/restfulie/server/action_view/helpers.rb +8 -8
  44. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +3 -2
  45. data/lib/restfulie/server/core_ext/array.rb +13 -12
  46. metadata +51 -34
  47. data/lib/restfulie/client/http/link.rb +0 -39
  48. data/lib/restfulie/client/http/xml.rb +0 -4
  49. data/lib/restfulie/common/builder/builder_base.rb +0 -73
  50. data/lib/restfulie/common/builder/helpers.rb +0 -22
  51. data/lib/restfulie/common/builder/marshalling/atom.rb +0 -197
  52. data/lib/restfulie/common/builder/marshalling/base.rb +0 -12
  53. data/lib/restfulie/common/builder/marshalling/json.rb +0 -2
  54. data/lib/restfulie/common/builder/marshalling/xml.rb +0 -183
  55. data/lib/restfulie/common/builder/marshalling.rb +0 -16
  56. data/lib/restfulie/common/builder/rules/collection_rule.rb +0 -10
  57. data/lib/restfulie/common/builder/rules/custom_attributes.rb +0 -24
  58. data/lib/restfulie/common/builder/rules/link.rb +0 -20
  59. data/lib/restfulie/common/builder/rules/links.rb +0 -9
  60. data/lib/restfulie/common/builder/rules/member_rule.rb +0 -8
  61. data/lib/restfulie/common/builder/rules/namespace.rb +0 -35
  62. data/lib/restfulie/common/builder/rules/rules_base.rb +0 -77
  63. data/lib/restfulie/common/builder.rb +0 -17
  64. data/lib/vendor/atom/configuration.rb +0 -24
  65. data/lib/vendor/atom/pub.rb +0 -250
  66. data/lib/vendor/atom/xml/parser.rb +0 -373
  67. 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
- describe_collection(@orders) do |collection|
54
- collection.id = orders_url
55
- collection.links << link( :rel => :create, :href => orders_url )
56
- collection.describe_members
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 gems and:
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
- gem install rack-conneg
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.7.2"
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
- restore.extend(Base)
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::NilEntryPoint.new.at(uri)
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, request)
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, request)
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, request)
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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: {'Accpet' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
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
- connection = get_connection_provider.send(method, path, *args)
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, {}, self), e )
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 again
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 RequestBuilderExecutor and include RequestHistory module.
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
- # Offers a way to access Atom entries element's in namespaced extensions.
4
- module AtomElementShortcut
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
@@ -0,0 +1,6 @@
1
+ %w(
2
+ http
3
+ ).each do |file|
4
+ require "restfulie/client/http/core_ext/#{file}"
5
+ end
6
+
@@ -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}#{::URI.decode(@response.path)} via #{@response.method}. " +
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::RequestBuilder
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::Representation::Atom
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::Representation::XmlD)
34
- RequestMarshaller.register_representation('text/xml', ::Restfulie::Common::Representation::XmlD)
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
- type = @@representations[content_type]
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
- #Executes super and unmarshalls it
57
- def request!(method, path, *args)
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
- # Gives to Link capabilities to fetch related resources.
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 Restfulie::Client::HTTP::RequestMarshaller
132
+ include RequestMarshaller
132
133
  def path#:nodoc:
133
134
  at(href)
134
- as(content_type) if respond_to?(:content_type) && content_type
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