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.
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