restfulie 0.9.3 → 1.0.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (78) hide show
  1. data/Gemfile +2 -0
  2. data/Gemfile.lock +2 -2
  3. data/README.textile +4 -2
  4. data/Rakefile +12 -13
  5. data/lib/restfulie/client/base.rb +9 -2
  6. data/lib/restfulie/client/cache/basic.rb +6 -5
  7. data/lib/restfulie/client/cache/http_ext.rb +10 -8
  8. data/lib/restfulie/client/cache/restrictions.rb +1 -6
  9. data/lib/restfulie/client/dsl.rb +66 -0
  10. data/lib/restfulie/client/entry_point.rb +34 -9
  11. data/lib/restfulie/client/ext/atom_ext.rb +4 -2
  12. data/lib/restfulie/client/ext/json_ext.rb +5 -1
  13. data/lib/restfulie/client/feature/base.rb +75 -0
  14. data/lib/restfulie/client/feature/base_request.rb +35 -0
  15. data/lib/restfulie/client/feature/cache.rb +16 -0
  16. data/lib/restfulie/client/feature/enhance_response.rb +12 -0
  17. data/lib/restfulie/client/feature/follow_request.rb +41 -0
  18. data/lib/restfulie/client/feature/history.rb +26 -0
  19. data/lib/restfulie/client/feature/history_request.rb +19 -0
  20. data/lib/restfulie/client/feature/open_search/pattern_matcher.rb +25 -0
  21. data/lib/restfulie/client/feature/open_search.rb +21 -0
  22. data/lib/restfulie/client/feature/serialize_body.rb +32 -0
  23. data/lib/restfulie/client/feature/setup_header.rb +22 -0
  24. data/lib/restfulie/client/feature/throw_error.rb +41 -0
  25. data/lib/restfulie/client/feature/verb.rb +119 -0
  26. data/lib/restfulie/client/feature.rb +5 -0
  27. data/lib/restfulie/client/http/response_holder.rb +26 -6
  28. data/lib/restfulie/client/http.rb +1 -21
  29. data/lib/restfulie/client/master_delegator.rb +31 -0
  30. data/lib/restfulie/client/mikyung/core.rb +5 -4
  31. data/lib/restfulie/client/mikyung/steady_state_walker.rb +1 -1
  32. data/lib/restfulie/client/mikyung.rb +1 -8
  33. data/lib/restfulie/client.rb +3 -1
  34. data/lib/restfulie/common/converter/atom/base.rb +2 -0
  35. data/lib/restfulie/common/converter/form_url_encoded.rb +16 -0
  36. data/lib/restfulie/common/converter/json/base.rb +5 -2
  37. data/lib/restfulie/common/converter/open_search/descriptor.rb +32 -0
  38. data/lib/restfulie/common/converter/open_search.rb +16 -0
  39. data/lib/restfulie/common/converter/xml/base.rb +3 -1
  40. data/lib/restfulie/common/converter/xml/builder.rb +3 -2
  41. data/lib/restfulie/common/converter/xml/helpers.rb +4 -4
  42. data/lib/restfulie/common/converter/xml/link.rb +5 -0
  43. data/lib/restfulie/common/converter/xml/links.rb +1 -5
  44. data/lib/restfulie/common/converter.rb +25 -4
  45. data/lib/restfulie/common/core_ext/hash.rb +6 -0
  46. data/lib/restfulie/common/links.rb +9 -0
  47. data/lib/restfulie/common/representation/atom/base.rb +34 -33
  48. data/lib/restfulie/common/representation/atom/xml.rb +5 -10
  49. data/lib/restfulie/common/representation/generic.rb +0 -12
  50. data/lib/restfulie/common/representation/json/keys_as_methods.rb +2 -0
  51. data/lib/restfulie/common/representation.rb +2 -9
  52. data/lib/restfulie/common.rb +2 -1
  53. data/lib/restfulie/server/action_controller/trait/cacheable.rb +81 -0
  54. data/lib/restfulie/server/action_controller/trait/created.rb +17 -0
  55. data/lib/restfulie/server/action_controller/trait/save_prior_to_create.rb +13 -0
  56. data/lib/restfulie/server/action_controller/trait.rb +9 -0
  57. data/lib/restfulie/server/action_controller.rb +1 -5
  58. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +1 -1
  59. data/lib/restfulie/server.rb +6 -0
  60. data/lib/restfulie/version.rb +4 -4
  61. data/lib/restfulie.rb +21 -3
  62. metadata +37 -26
  63. data/lib/restfulie/client/ext/xml_ext.rb +0 -4
  64. data/lib/restfulie/client/http/link_request_builder.rb +0 -16
  65. data/lib/restfulie/client/http/request_adapter.rb +0 -213
  66. data/lib/restfulie/client/http/request_builder.rb +0 -114
  67. data/lib/restfulie/client/http/request_builder_executor.rb +0 -24
  68. data/lib/restfulie/client/http/request_executor.rb +0 -17
  69. data/lib/restfulie/client/http/request_follow.rb +0 -42
  70. data/lib/restfulie/client/http/request_follow_executor.rb +0 -10
  71. data/lib/restfulie/client/http/request_history.rb +0 -71
  72. data/lib/restfulie/client/http/request_history_executor.rb +0 -10
  73. data/lib/restfulie/client/http/request_marshaller.rb +0 -129
  74. data/lib/restfulie/client/http/request_marshaller_executor.rb +0 -10
  75. data/lib/restfulie/client/http/response.rb +0 -23
  76. data/lib/restfulie/client/http/response_handler.rb +0 -67
  77. data/lib/restfulie/server/action_controller/cacheable_responder.rb +0 -77
  78. data/lib/restfulie/server/action_controller/created_responder.rb +0 -19
@@ -0,0 +1,22 @@
1
+ module Restfulie::Client::Feature
2
+
3
+ class SetupHeader
4
+
5
+ def execute(flow, request, response, env)
6
+ headers = request.default_headers.dup.merge(request.headers)
7
+ host = request.host
8
+ if host.user || host.password
9
+ headers["Authorization"] = "Basic " + ["#{host.user}:#{host.password}"].pack("m").delete("\r\n")
10
+ end
11
+ headers.delete :recipe
12
+ headers['cookie'] = request.cookies if request.cookies
13
+
14
+ # gs: this should not be overriden, do it in some other way
15
+ request.headers = headers
16
+
17
+ flow.continue(request, response, env)
18
+ end
19
+
20
+ end
21
+
22
+ end
@@ -0,0 +1,41 @@
1
+ class Restfulie::Client::Feature::ThrowError
2
+ def execute(flow, request, result_so_far, env)
3
+ result = flow.continue(request, result_so_far, env)
4
+ if result.kind_of? Exception
5
+ Restfulie::Common::Logger.logger.error(result)
6
+ raise Restfulie::Client::HTTP::Error::ServerNotAvailableError.new(request, Restfulie::Client::HTTP::Response.new(request.verb, request.path, 503, nil, {}), result )
7
+ end
8
+ case result.response.code.to_i
9
+ when 100..299
10
+ result
11
+ when 300..399
12
+ raise Restfulie::Client::HTTP::Error::Redirection.new(request, result)
13
+ when 400
14
+ raise Restfulie::Client::HTTP::Error::BadRequest.new(request, result)
15
+ when 401
16
+ raise Restfulie::Client::HTTP::Error::Unauthorized.new(request, result)
17
+ when 403
18
+ raise Restfulie::Client::HTTP::Error::Forbidden.new(request, result)
19
+ when 404
20
+ raise Restfulie::Client::HTTP::Error::NotFound.new(request, result)
21
+ when 405
22
+ raise Restfulie::Client::HTTP::Error::MethodNotAllowed.new(request, result)
23
+ when 407
24
+ raise Restfulie::Client::HTTP::Error::ProxyAuthenticationRequired.new(request, result)
25
+ when 409
26
+ raise Restfulie::Client::HTTP::Error::Conflict.new(request, result)
27
+ when 410
28
+ raise Restfulie::Client::HTTP::Error::Gone.new(request, result)
29
+ when 412
30
+ raise Restfulie::Client::HTTP::Error::PreconditionFailed.new(request, result)
31
+ when 402, 406, 408, 411, 413..499
32
+ raise Restfulie::Client::HTTP::Error::ClientError.new(request, result)
33
+ when 501
34
+ raise Restfulie::Client::HTTP::Error::NotImplemented.new(request, result)
35
+ when 500, 502..599
36
+ raise Restfulie::Client::HTTP::Error::ServerError.new(request, result)
37
+ else
38
+ raise Restfulie::Client::HTTP::Error::UnknownError.new(request, result)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,119 @@
1
+ module Restfulie::Client::Feature::Verb
2
+
3
+ # GET HTTP verb without {Error}
4
+ # * <tt>path: '/posts'</tt>
5
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
6
+ def get(params = {})
7
+ @verb = :get
8
+ at query_string(params)
9
+ request_flow
10
+ end
11
+
12
+ # HEAD HTTP verb without {Error}
13
+ # * <tt>path: '/posts'</tt>
14
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
15
+ def head
16
+ @verb = :head
17
+ request_flow
18
+ end
19
+
20
+ # POST HTTP verb without {Error}
21
+ # * <tt>path: '/posts'</tt>
22
+ # * <tt>payload: 'some text'</tt>
23
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
24
+ def post(payload, options = {:recipe => nil})
25
+ @verb = :post
26
+ request_flow :body => payload
27
+ end
28
+
29
+ # PATCH HTTP verb without {Error}
30
+ # * <tt>path: '/posts'</tt>
31
+ # * <tt>payload: 'some text'</tt>
32
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
33
+ def patch(payload)
34
+ @verb = :patch
35
+ request_flow :body => payload
36
+ end
37
+
38
+ # PUT HTTP verb without {Error}
39
+ # * <tt>path: '/posts'</tt>
40
+ # * <tt>payload: 'some text'</tt>
41
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
42
+ def put(payload)
43
+ @verb = :put
44
+ request_flow :body => payload
45
+ end
46
+
47
+ # DELETE HTTP verb without {Error}
48
+ # * <tt>path: '/posts'</tt>
49
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
50
+ def delete
51
+ @verb = :delete
52
+ request_flow
53
+ end
54
+
55
+ # GET HTTP verb {Error}
56
+ # * <tt>path: '/posts'</tt>
57
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
58
+ def get!(params = {})
59
+ @verb = :get
60
+ at query_string(params)
61
+ request :throw_error
62
+ request_flow
63
+ end
64
+
65
+ # HEAD HTTP verb {Error}
66
+ # * <tt>path: '/posts'</tt>
67
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
68
+ def head!
69
+ @verb = :head
70
+ request :throw_error
71
+ request_flow
72
+ end
73
+
74
+ # POST HTTP verb {Error}
75
+ # * <tt>path: '/posts'</tt>
76
+ # * <tt>payload: 'some text'</tt>
77
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
78
+ def post!(payload, options = {:recipe => nil})
79
+ @verb = :post
80
+ request :throw_error
81
+ request_flow :body => payload
82
+ end
83
+
84
+ # PATCH HTTP verb {Error}
85
+ # * <tt>path: '/posts'</tt>
86
+ # * <tt>payload: 'some text'</tt>
87
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
88
+ def patch!(payload)
89
+ @verb = :patch
90
+ request :throw_error
91
+ request_flow :body => payload
92
+ end
93
+
94
+ # PUT HTTP verb {Error}
95
+ # * <tt>path: '/posts'</tt>
96
+ # * <tt>payload: 'some text'</tt>
97
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
98
+ def put!(payload)
99
+ @verb = :put
100
+ request :throw_error
101
+ request_flow :body => payload
102
+ end
103
+
104
+ # DELETE HTTP verb {Error}
105
+ # * <tt>path: '/posts'</tt>
106
+ # * <tt>headers: {'Accept' => '*/*', 'Content-Type' => 'application/atom+xml'}</tt>
107
+ def delete!
108
+ @verb = :delete
109
+ request :throw_error
110
+ request_flow
111
+ end
112
+
113
+ protected
114
+
115
+ def query_string(params)
116
+ params = params.map { |param, value| "#{param}=#{value}"}.join("&")
117
+ params.blank? ? "" : URI.escape("?#{params}")
118
+ end
119
+ end
@@ -0,0 +1,5 @@
1
+ module Restfulie::Client
2
+ module Feature
3
+ Dir["#{File.dirname(__FILE__)}/feature/*.rb"].each {|f| autoload File.basename(f)[0..-4].camelize.to_sym, f }
4
+ end
5
+ end
@@ -1,9 +1,29 @@
1
- module Restfulie
2
- module Client
3
- module HTTP
4
- module ResponseHolder
5
- attr_accessor :response
6
- end
1
+ module Restfulie::Client::HTTP
2
+ module ResponseHolder
3
+ attr_reader :response, :request
4
+
5
+ def resource
6
+ type = headers['content-type'] || response['Content-Type']
7
+ representation = Restfulie::Common::Converter.content_type_for(type[0]) || Restfulie::Common::Representation::Generic.new
8
+ representation.unmarshal(response.body)
7
9
  end
10
+
11
+ def at(uri)
12
+ request.clone.at(uri)
13
+ end
14
+
15
+ def headers
16
+ response.to_hash
17
+ end
18
+
19
+ def results_from(request, response)
20
+ @request = request
21
+ @response = response
22
+ end
23
+
24
+ def verb
25
+ @request.verb
26
+ end
27
+
8
28
  end
9
29
  end
@@ -1,27 +1,7 @@
1
1
  module Restfulie
2
2
  module Client
3
3
  module HTTP#:nodoc:
4
- autoload :Error, 'restfulie/client/http/error'
5
- autoload :Response, 'restfulie/client/http/response'
6
- autoload :ResponseHandler, 'restfulie/client/http/response_handler'
7
- autoload :RequestAdapter, 'restfulie/client/http/request_adapter'
8
- autoload :RequestBuilder, 'restfulie/client/http/request_builder'
9
- autoload :RequestFollow, 'restfulie/client/http/request_follow'
10
- autoload :RequestHistory, 'restfulie/client/http/request_history'
11
- autoload :RequestExecutor, 'restfulie/client/http/request_executor'
12
- autoload :RequestBuilderExecutor, 'restfulie/client/http/request_builder_executor'
13
- autoload :RequestFollowExecutor, 'restfulie/client/http/request_follow_executor'
14
- autoload :RequestHistoryExecutor, 'restfulie/client/http/request_history_executor'
15
- autoload :Cache, 'restfulie/client/http/cache'
16
- autoload :ResponseHolder, 'restfulie/client/http/response_holder'
17
- autoload :RequestMarshaller, 'restfulie/client/http/request_marshaller'
18
- autoload :LinkRequestBuilder, 'restfulie/client/http/link_request_builder'
19
- autoload :RequestMarshallerExecutor, 'restfulie/client/http/request_marshaller_executor'
4
+ Dir["#{File.dirname(__FILE__)}/http/*.rb"].each {|f| autoload File.basename(f)[0..-4].camelize.to_sym, f }
20
5
  end
21
6
  end
22
7
  end
23
-
24
- require 'restfulie/client/ext/atom_ext'
25
- require 'restfulie/client/ext/xml_ext'
26
- require 'restfulie/client/ext/http_ext'
27
- require 'restfulie/client/ext/json_ext'
@@ -0,0 +1,31 @@
1
+ class MasterDelegator
2
+
3
+ alias_method :original_respond_to?, :respond_to?
4
+
5
+ def respond_to?(sym)
6
+ original_respond_to?(sym) || @requester.respond_to?(sym)
7
+ end
8
+
9
+ def method_missing(sym, *args, &block)
10
+ if original_respond_to?(sym)
11
+ result = super(sym, *args, &block)
12
+ elsif @requester.respond_to?(sym)
13
+ result = @requester.send(sym, *args, &block)
14
+ else
15
+ # let it go
16
+ return super(sym, *args, &block)
17
+ end
18
+ delegate_parse result
19
+ end
20
+
21
+ protected
22
+
23
+ def delegate(what, *args, &block)
24
+ delegate_parse @requester.send(what, *args, &block)
25
+ end
26
+
27
+ def delegate_parse(result)
28
+ (result == @requester) ? self : result
29
+ end
30
+
31
+ end
@@ -42,6 +42,11 @@ module Restfulie
42
42
 
43
43
  # keeps changing from a steady state to another until its goal has been achieved
44
44
  def run
45
+
46
+ # load the steps and scenario
47
+ @goal.steps
48
+ @goal.scenario
49
+
45
50
  if @start.kind_of? String
46
51
  client = Restfulie.at(@start)
47
52
  client = client.follow if @follow
@@ -52,10 +57,6 @@ module Restfulie
52
57
  @start = current = @goal.class.get_restfulie.get
53
58
  end
54
59
 
55
- # load the steps and scenario
56
- @goal.steps
57
- @goal.scenario
58
-
59
60
  while(!@goal.completed?(current))
60
61
  current = @walker.move(@goal, current, self)
61
62
  end
@@ -14,7 +14,7 @@ module Restfulie
14
14
  private
15
15
 
16
16
  def try_to_execute(step, current, max_attempts, mikyung)
17
- raise "Unable to proceed when trying to #{step}" if max_attempts == 0
17
+ raise "Unable to proceed when trying to analyze #{step.body}" if max_attempts == 0
18
18
 
19
19
  resource = step
20
20
  raise "Step returned 'give up'" if resource.nil?
@@ -1,13 +1,7 @@
1
1
  module Restfulie
2
2
  module Client
3
3
  module Mikyung
4
- autoload :WhenCondition, 'restfulie/client/mikyung/when_condition'
5
- autoload :ThenCondition, 'restfulie/client/mikyung/then_condition'
6
- autoload :RestProcessModel, 'restfulie/client/mikyung/rest_process_model'
7
- autoload :Concatenator, 'restfulie/client/mikyung/concatenator'
8
- autoload :Core, 'restfulie/client/mikyung/core'
9
- autoload :SteadyStateWalker, 'restfulie/client/mikyung/steady_state_walker'
10
- autoload :Languages, 'restfulie/client/mikyung/languages'
4
+ Dir["#{File.dirname(__FILE__)}/mikyung/*.rb"].each {|f| autoload File.basename(f)[0..-4].camelize.to_sym, f }
11
5
  end
12
6
  end
13
7
  end
@@ -17,6 +11,5 @@ end
17
11
  module Restfulie
18
12
  class Mikyung < Restfulie::Client::Mikyung::Core
19
13
  Restfulie::Common::Logger.logger.level = Logger::INFO
20
- # empty class
21
14
  end
22
15
  end
@@ -2,12 +2,15 @@ require 'restfulie/common'
2
2
 
3
3
  module Restfulie
4
4
  module Client
5
+ autoload :MasterDelegator, 'restfulie/client/master_delegator'
5
6
  autoload :HTTP, 'restfulie/client/http'
6
7
  autoload :Configuration, 'restfulie/client/configuration'
7
8
  autoload :EntryPoint, 'restfulie/client/entry_point'
8
9
  autoload :Base, 'restfulie/client/base'
9
10
  autoload :Mikyung, 'restfulie/client/mikyung'
10
11
  autoload :Cache, 'restfulie/client/cache'
12
+ autoload :Feature, 'restfulie/client/feature'
13
+ autoload :Dsl, 'restfulie/client/dsl'
11
14
 
12
15
  mattr_accessor :cache_provider, :cache_store
13
16
 
@@ -20,5 +23,4 @@ end
20
23
  require 'restfulie/client/ext/http_ext'
21
24
  require 'restfulie/client/ext/atom_ext'
22
25
  require 'restfulie/client/ext/json_ext'
23
- require 'restfulie/client/ext/xml_ext'
24
26
 
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/hash/conversions'
2
+
1
3
  module Restfulie
2
4
  module Common
3
5
  module Converter
@@ -0,0 +1,16 @@
1
+ class Restfulie::Common::Converter::FormUrlEncoded < Restfulie::Common::Representation::Generic
2
+ def self.marshal(content, rel)
3
+ if content.kind_of? Hash
4
+ content.map { |key, value| "#{key}=#{value}" }.join("&")
5
+ else
6
+ content
7
+ end
8
+ end
9
+
10
+ def self.unmarshal(content)
11
+ def content.links
12
+ []
13
+ end
14
+ content
15
+ end
16
+ end
@@ -34,8 +34,11 @@ module Restfulie
34
34
 
35
35
  # Check if the object is already an json
36
36
  unless recipe
37
- return Restfulie::Common::Representation::Json.create(obj) if obj.kind_of?(Hash) || obj.kind_of?(Array)
38
- raise Restfulie::Common::Error::ConverterError.new("Recipe required")
37
+ if obj.kind_of?(Hash) || obj.kind_of?(Array)
38
+ return Restfulie::Common::Representation::Json.create(obj)
39
+ else
40
+ raise Restfulie::Common::Error::ConverterError.new("Recipe required")
41
+ end
39
42
  end
40
43
 
41
44
  # Get recipe already described
@@ -0,0 +1,32 @@
1
+ class Restfulie::Common::Converter::OpenSearch::Descriptor
2
+
3
+ def initialize(hash)
4
+ @hash = hash["OpenSearchDescription"]
5
+ end
6
+
7
+ def urls
8
+ uris = @hash["Url"]
9
+ uris.kind_of?(Array) ? uris : [uris]
10
+ end
11
+
12
+ def use(content_type)
13
+ uri = urls.find do |url|
14
+ url["type"]==content_type
15
+ end
16
+ return nil if uri.nil?
17
+
18
+ base_uri, params_pattern = extract_uri(uri)
19
+ Restfulie.at(base_uri).accepts(content_type).open_search.with_pattern(params_pattern)
20
+ end
21
+
22
+ private
23
+ def extract_uri(uri)
24
+ uri = uri["template"]
25
+ interrogation = uri.index("?")
26
+ params = uri[interrogation+1..uri.size]
27
+ base_uri = uri[0..interrogation-1]
28
+ [base_uri, params]
29
+ end
30
+
31
+ end
32
+
@@ -0,0 +1,16 @@
1
+ module Restfulie
2
+ module Common
3
+ class Converter::OpenSearch#:nodoc:
4
+ autoload :Descriptor, 'restfulie/common/converter/open_search/descriptor'
5
+ end
6
+ end
7
+ end
8
+
9
+ class Restfulie::Common::Converter::OpenSearch
10
+
11
+ def self.unmarshal(xml)
12
+ hash = Hash.from_xml(xml)
13
+ descriptor = Descriptor.new(hash)
14
+ end
15
+
16
+ end
@@ -1,3 +1,5 @@
1
+ require 'active_support/core_ext/hash/conversions'
2
+
1
3
  module Restfulie
2
4
  module Common
3
5
  module Converter
@@ -43,7 +45,7 @@ module Restfulie
43
45
  end
44
46
 
45
47
  # Create representation and proxy
46
- builder = Builder.new(obj)
48
+ builder = Builder.new(obj, options)
47
49
 
48
50
  # Check recipe arity size before calling it
49
51
  recipe.call(*[builder, obj, options][0,recipe.arity])
@@ -42,11 +42,12 @@ module Restfulie
42
42
  insert_value("link", nil, options)
43
43
  end
44
44
 
45
- def members(a_collection = nil, &block)
45
+ def members(a_collection = nil, options = {}, &block)
46
46
  collection = a_collection || @obj
47
47
  raise Error::BuilderError("Members method require a collection to execute") unless collection.respond_to?(:each)
48
48
  collection.each do |member|
49
- entry = @doc.create_element(Restfulie::Common::Converter.root_element_for(member))
49
+ root = options[:root] || Restfulie::Common::Converter.root_element_for(member)
50
+ entry = @doc.create_element(root)
50
51
  entry.parent = @parent
51
52
  @parent = entry
52
53
  block.call(self, member)
@@ -3,12 +3,12 @@ module Restfulie
3
3
  module Converter
4
4
  module Xml
5
5
  module Helpers
6
- def collection(obj, *args, &block)
7
- Xml.to_xml(obj, {}, &block)
6
+ def collection(obj, opts = {}, &block)
7
+ Xml.to_xml(obj, opts, &block)
8
8
  end
9
9
 
10
- def member(obj, *args, &block)
11
- Xml.to_xml(obj, {}, &block)
10
+ def member(obj, opts = {}, &block)
11
+ Xml.to_xml(obj, opts, &block)
12
12
  end
13
13
  end
14
14
  end
@@ -18,6 +18,11 @@ module Restfulie
18
18
  def type
19
19
  content_type
20
20
  end
21
+ def follow
22
+ r = Restfulie.at(href)
23
+ r = r.as(content_type) if content_type
24
+ r
25
+ end
21
26
  end
22
27
  end
23
28
  end
@@ -6,11 +6,7 @@ module Restfulie
6
6
  def initialize(links)
7
7
  links = [links] unless links.kind_of? Array
8
8
  links = [] unless links
9
- @links = links.map do |l|
10
- link = Restfulie::Common::Converter::Xml::Link.new(l)
11
- link.instance_eval { self.class.send :include, ::Restfulie::Client::HTTP::LinkRequestBuilder }
12
- link
13
- end
9
+ @links = links.map { |l| Restfulie::Common::Converter::Xml::Link.new(l) }
14
10
  end
15
11
 
16
12
  def method_missing(sym, *args)
@@ -1,10 +1,7 @@
1
1
  module Restfulie
2
2
  module Common
3
3
  module Converter
4
- autoload :Values, 'restfulie/common/converter/values'
5
- autoload :Atom, 'restfulie/common/converter/atom'
6
- autoload :Json, 'restfulie/common/converter/json'
7
- autoload :Xml, 'restfulie/common/converter/xml'
4
+ Dir["#{File.dirname(__FILE__)}/converter/*.rb"].each {|f| autoload File.basename(f)[0..-4].camelize.to_sym, f }
8
5
 
9
6
  # Returns the default root element name for an item or collection
10
7
  def self.root_element_for(obj)
@@ -16,6 +13,30 @@ module Restfulie
16
13
  obj.class.to_s.underscore
17
14
  end
18
15
  end
16
+
17
+ def self.register(media_type,representation)
18
+ representations[media_type] = representation
19
+ end
20
+
21
+ def self.content_type_for(media_type)
22
+ return nil unless media_type
23
+ content_type = media_type.split(';')[0] # [/(.*?);/, 1]
24
+ representations[content_type]
25
+ end
26
+
27
+ private
28
+
29
+ def self.representations
30
+ @representations ||= {}
31
+ end
32
+
33
+ register 'application/atom+xml' , ::Restfulie::Common::Converter::Atom
34
+ register 'application/xml' , ::Restfulie::Common::Converter::Xml
35
+ register 'text/xml' , ::Restfulie::Common::Converter::Xml
36
+ register 'application/json' , ::Restfulie::Common::Converter::Json
37
+ register 'application/opensearchdescription+xml' , ::Restfulie::Common::Converter::OpenSearch
38
+ register 'application/x-www-form-urlencoded', Restfulie::Common::Converter::FormUrlEncoded
39
+
19
40
  end
20
41
  end
21
42
  end
@@ -1,12 +1,18 @@
1
1
  class Hash
2
+
2
3
  def links(*args)
3
4
  links = fetch("link", [])
4
5
  Restfulie::Common::Converter::Xml::Links.new(links)
5
6
  end
7
+
8
+ include Restfulie::Common::Links
9
+
6
10
  def method_missing(sym, *args)
7
11
  self[sym.to_s].nil? ? super(sym, args) : self[sym.to_s]
8
12
  end
13
+
9
14
  def respond_to?(sym)
10
15
  include?(sym.to_s) || super(sym)
11
16
  end
17
+
12
18
  end
@@ -0,0 +1,9 @@
1
+ module Restfulie
2
+ module Common
3
+ module Links
4
+ def refresh
5
+ links.self.follow.get
6
+ end
7
+ end
8
+ end
9
+ end