restfulie 0.7.0 → 0.7.1

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/README.textile CHANGED
@@ -91,6 +91,7 @@ If you want to build the project and run its tests, remember to install all (cli
91
91
  <pre>
92
92
  gem install rack-conneg
93
93
  gem install responders_backport
94
+ gem install json_pure
94
95
  </pre>
95
96
 
96
97
  <script type="text/javascript">
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'spec/rake/spectask'
6
6
  require 'rake/rdoctask'
7
7
 
8
8
  GEM = "restfulie"
9
- GEM_VERSION = "0.7.0"
9
+ GEM_VERSION = "0.7.1"
10
10
  SUMMARY = "Hypermedia aware resource based library in ruby (client side) and ruby on rails (server side)."
11
11
  AUTHOR = "Guilherme Silveira, Caue Guerra"
12
12
  EMAIL = "guilherme.silveira@caelum.com.br"
@@ -22,6 +22,7 @@ spec = Gem::Specification.new do |s|
22
22
  s.add_dependency("actionpack", [">= 2.3.2"])
23
23
  s.add_dependency("activesupport", [">= 2.3.2"])
24
24
  s.add_dependency("responders_backport", ["~> 0.1.0"])
25
+ s.add_dependency("json_pure", [">= 1.2.4"])
25
26
 
26
27
  s.author = AUTHOR
27
28
  s.email = EMAIL
@@ -22,6 +22,10 @@ module Restfulie::Client#:nodoc
22
22
  end
23
23
 
24
24
  end
25
+ class NilEntryPoint
26
+ include Restfulie::Client::EntryPoint
27
+ # extend self
28
+ end
25
29
 
26
30
  module Base
27
31
  include HTTP::RequestMarshaller
@@ -52,9 +56,11 @@ module Restfulie::Client#:nodoc
52
56
 
53
57
  end
54
58
 
59
+
55
60
  # Shortcut to Restfulie::Client::EntryPoint
56
61
  module Restfulie
57
- include Client::EntryPoint
58
- extend self
62
+ def self.at(uri)
63
+ Client::NilEntryPoint.new.at(uri)
64
+ end
59
65
  end
60
66
 
@@ -1,22 +1,4 @@
1
1
  module Restfulie::Client::HTTP#:nodoc:
2
-
3
- # Offer easy access to Atom link relationships, such as <tt>post.next</tt> for
4
- # <tt>&lt;link rel="next" href="http://resource.entrypoint.com/post/12" type="application/atom+xml" /&gt;</tt> relationships.
5
- module AtomLinkShortcut
6
- def method_missing(method_sym,*args)#:nodoc:
7
- selected_links = links.select{ |l| l.rel == method_sym.to_s }
8
- super if selected_links.empty?
9
- link = (selected_links.size == 1) ? selected_links.first : selected_links
10
-
11
- return link unless link.instance_variable_defined?(:@type)
12
- link.accepts(link.type)
13
-
14
- representation = Restfulie::Client::HTTP::RequestMarshaller.content_type_for(link.type)
15
- return representation.prepare_link_for(link) if representation
16
- link
17
-
18
- end
19
- end
20
2
 
21
3
  # Offers a way to access Atom entries element's in namespaced extensions.
22
4
  module AtomElementShortcut
@@ -64,24 +46,24 @@ module Restfulie::Client::HTTP#:nodoc:
64
46
  end
65
47
  end
66
48
 
67
- # Gives to Atom::Link capabilities to fetch related resources.
68
- module LinkRequestBuilder
69
- include RequestMarshaller
70
- def path#:nodoc:
71
- at(href)
72
- super
73
- end
74
- end
75
-
76
49
  # inject new behavior in rAtom instances to enable easily access to link relationships.
77
50
  ::Atom::Feed.instance_eval {
78
- include AtomLinkShortcut
51
+ include Restfulie::Client::LinkShortcut
79
52
  include AtomElementShortcut
80
53
  }
81
54
  ::Atom::Entry.instance_eval {
82
- include AtomLinkShortcut
55
+ include Restfulie::Client::LinkShortcut
83
56
  include AtomElementShortcut
84
57
  }
85
- ::Atom::Link.instance_eval { include LinkRequestBuilder }
58
+ ::Atom::Link.instance_eval {
59
+ include Restfulie::Client::HTTP::LinkRequestBuilder
60
+ }
86
61
 
87
62
  end
63
+
64
+
65
+ class Atom::Link
66
+ def content_type
67
+ type
68
+ end
69
+ end
@@ -0,0 +1,39 @@
1
+ module Restfulie::Client
2
+
3
+ # Offer easy access to link relationships, such as <tt>post.next</tt> for
4
+ # <tt>&lt;link rel="next" href="http://resource.entrypoint.com/post/12" type="application/atom+xml" /&gt;</tt> relationships.
5
+ module LinkShortcut
6
+ def method_missing(method_sym,*args)#:nodoc:
7
+ selected_links = links.select{ |l| l.rel == method_sym.to_s }
8
+ super if selected_links.empty?
9
+ link = (selected_links.size == 1) ? selected_links.first : selected_links
10
+
11
+ return link unless link.instance_variable_defined?(:@type)
12
+ link.accepts(link.type)
13
+
14
+ representation = Restfulie::Client::HTTP::RequestMarshaller.content_type_for(link.type)
15
+ return representation.prepare_link_for(link) if representation
16
+ link
17
+
18
+ end
19
+ end
20
+
21
+ class Link
22
+
23
+ include Restfulie::Client::HTTP::LinkRequestBuilder
24
+
25
+ def initialize(options = {})
26
+ @options = options
27
+ end
28
+ def href
29
+ @options["href"]
30
+ end
31
+ def rel
32
+ @options["rel"]
33
+ end
34
+ def content_type
35
+ @options["type"]
36
+ end
37
+ end
38
+
39
+ end
@@ -5,7 +5,7 @@ module Restfulie::Client::HTTP
5
5
  attr_accessor :response
6
6
 
7
7
  def respond_to?(symbol)
8
- respond_to_rel?(symbol.to_s) || super(symbol)
8
+ super(symbol) || (super(:links) && respond_to_rel?(symbol.to_s))
9
9
  end
10
10
 
11
11
  private
@@ -21,18 +21,21 @@ module Restfulie::Client::HTTP
21
21
 
22
22
  # accepts a series of media types by default
23
23
  def initialize
24
- @acceptable_mediatypes = "application/atom+xml"
25
24
  end
26
25
 
27
26
  @@representations = {
28
- 'application/atom+xml' => ::Restfulie::Common::Representation::Atom,
29
- 'application/xml' => ::Restfulie::Common::Representation::XmlD
27
+ 'application/atom+xml' => ::Restfulie::Common::Representation::Atom
30
28
  }
31
29
  def self.register_representation(media_type,representation)
32
30
  @@representations[media_type] = representation
33
31
  end
34
32
 
33
+ RequestMarshaller.register_representation('application/xml', ::Restfulie::Common::Representation::XmlD)
34
+ RequestMarshaller.register_representation('text/xml', ::Restfulie::Common::Representation::XmlD)
35
+ RequestMarshaller.register_representation('application/json', ::Restfulie::Common::Representation::Json)
36
+
35
37
  def self.content_type_for(media_type)
38
+ return nil unless media_type
36
39
  content_type = media_type.split(';')[0] # [/(.*?);/, 1]
37
40
  type = @@representations[content_type]
38
41
  type ? type.new : nil
@@ -52,30 +55,39 @@ module Restfulie::Client::HTTP
52
55
 
53
56
  #Executes super and unmarshalls it
54
57
  def request!(method, path, *args)
55
- representation = do_conneg_and_choose_representation(method, path, *args)
56
- if representation
57
- if has_payload?(method, path, *args)
58
- payload = get_payload(method, path, *args)
59
- rel = self.respond_to?(:rel) ? self.rel : ""
60
- payload = representation.marshal(payload, rel)
61
- args = set_marshalled_payload(method, path, payload, *args)
62
- end
63
- args = add_representation_headers(method, path, representation, *args)
58
+
59
+ if has_payload?(method, path, *args)
60
+ payload = get_payload(method, path, *args)
61
+ rel = self.respond_to?(:rel) ? self.rel : ""
62
+ type = headers['Content-Type']
63
+ raise Restfulie::Common::Error::RestfulieError, "Missing content type related to the data to be submitted" unless type
64
+ marshaller = RequestMarshaller.content_type_for(type)
65
+ payload = marshaller.marshal(payload, rel)
66
+ args = set_marshalled_payload(method, path, payload, *args)
67
+ args = add_representation_headers(method, path, marshaller, *args)
68
+ end
69
+
70
+ if @acceptable_mediatypes
71
+ unmarshaller = RequestMarshaller.content_type_for(@acceptable_mediatypes)
72
+ args = add_representation_headers(method, path, unmarshaller, *args)
64
73
  end
74
+
65
75
  response = super(method, path, *args)
66
- parse_response(response, representation)
76
+ parse_response(response)
67
77
  end
68
78
 
69
79
  private
70
80
 
81
+
71
82
  # parses the http response.
72
83
  # first checks if its a 201, redirecting to the resource location.
73
84
  # otherwise check if its a raw request, returning the content itself.
74
85
  # finally, tries to parse the content with a mediatype handler or returns the response itself.
75
- def parse_response(response, representation)
86
+ def parse_response(response)
76
87
  if response.code == 201
77
- location = response.headers['location']
78
- Restfulie.at(location).accepts(@acceptable_mediatypes).get!
88
+ request = Restfulie.at(response.headers['location'])
89
+ request.accepts(@acceptable_mediatypes) if @acceptable_mediatypes
90
+ request.get!
79
91
  elsif @raw
80
92
  response
81
93
  elsif !response.body.empty?
@@ -89,16 +101,6 @@ module Restfulie::Client::HTTP
89
101
  end
90
102
  end
91
103
 
92
- def content_type_for(media_type)
93
- @@representations[media_type.split(';')[0]].new # [/(.*?);/, 1]
94
- end
95
-
96
- def do_conneg_and_choose_representation(method, path, *args)
97
- #TODO make a request to server (conneg)
98
- representation = @default_representation || @default_representation = @@representations['application/atom+xml']
99
- representation.new
100
- end
101
-
102
104
  def has_payload?(method, path, *args)
103
105
  [:put,:post].include?(method)
104
106
  end
@@ -117,12 +119,23 @@ module Restfulie::Client::HTTP
117
119
 
118
120
  def add_representation_headers(method, path, representation, *args)
119
121
  headers = args.extract_options!
120
- args << representation.headers[method]
122
+ headers = headers.merge(representation.headers[method] || {})
123
+ args << headers
121
124
  args
122
125
  end
123
126
 
124
127
  end
125
128
 
129
+ # Gives to Link capabilities to fetch related resources.
130
+ module LinkRequestBuilder
131
+ include Restfulie::Client::HTTP::RequestMarshaller
132
+ def path#:nodoc:
133
+ at(href)
134
+ as(content_type) if respond_to?(:content_type) && content_type
135
+ super
136
+ end
137
+ end
138
+
126
139
  #=This class includes RequestBuilder module.
127
140
  class RequestMarshallerExecutor
128
141
  include RequestMarshaller
@@ -144,4 +157,3 @@ module Restfulie::Client::HTTP
144
157
  end
145
158
 
146
159
  end
147
-
@@ -0,0 +1,4 @@
1
+ ::Hash.instance_eval {
2
+ include Restfulie::Client::LinkShortcut
3
+ }
4
+
@@ -6,7 +6,9 @@ end
6
6
  adapter
7
7
  cache
8
8
  marshal
9
+ link
9
10
  atom_ext
11
+ xml
10
12
  ).each do |file|
11
13
  require "restfulie/client/http/#{file}"
12
14
  end
@@ -34,14 +34,6 @@ module Restfulie::Common::Representation
34
34
  def prepare_link_for(link)
35
35
  link
36
36
  end
37
-
38
- def prepare_link_for(link)
39
- link
40
- end
41
-
42
- def prepare_link_for(link)
43
- link
44
- end
45
37
  end
46
38
 
47
39
  end
@@ -0,0 +1,25 @@
1
+ module Restfulie::Common::Representation
2
+
3
+ # Implements the interface for marshal Xml media type requests (application/xml)
4
+ class Json
5
+
6
+ cattr_reader :media_type_name
7
+ @@media_type_name = 'application/json'
8
+
9
+ cattr_reader :headers
10
+ @@headers = {
11
+ :post => { 'Content-Type' => media_type_name }
12
+ }
13
+
14
+ def unmarshal(string)
15
+ JSON.parse(string)
16
+ end
17
+
18
+ def marshal(entity, rel)
19
+ return entity if entity.kind_of? String
20
+ entity.to_json
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -1,7 +1,32 @@
1
+ class Hash
2
+ def links(*args)
3
+ links = fetch("link", [])
4
+ links = [links] unless links.kind_of? Array
5
+ links = [] unless links
6
+ links = links.map do |l|
7
+ Restfulie::Client::Link.new(l)
8
+ end
9
+ if args.empty?
10
+ links
11
+ else
12
+ found = links.find do |link|
13
+ link.rel == args[0].to_s
14
+ end
15
+ found
16
+ end
17
+ end
18
+ def method_missing(sym, *args)
19
+ self[sym.to_s].nil? ? super(sym, args) : self[sym.to_s]
20
+ end
21
+ def respond_to?(sym)
22
+ include?(sym.to_s) || super(sym)
23
+ end
24
+ end
25
+
1
26
  module Restfulie::Common::Representation
27
+
2
28
  # Implements the interface for marshal Xml media type requests (application/xml)
3
29
  class XmlD
4
-
5
30
  cattr_reader :media_type_name
6
31
  @@media_type_name = 'application/xml'
7
32
 
@@ -11,7 +36,7 @@ module Restfulie::Common::Representation
11
36
  }
12
37
 
13
38
  def unmarshal(string)
14
- raise "should never be invoked, xml to ruby objects should be handled by rails itself"
39
+ Hash.from_xml(string).values.first
15
40
  end
16
41
 
17
42
  def marshal(string, rel)
@@ -21,4 +46,3 @@ module Restfulie::Common::Representation
21
46
  end
22
47
 
23
48
  end
24
-
@@ -3,6 +3,8 @@ module Restfulie::Common::Representation; end
3
3
 
4
4
  %w(
5
5
  atom
6
+ generic
7
+ json
6
8
  xml
7
9
  ).each do |file|
8
10
  require File.join(File.dirname(__FILE__), 'representation', file)
@@ -42,21 +42,21 @@ end
42
42
  # extensions are handled by the Rack stack
43
43
  #
44
44
  # TODO Change this when porting this code to Rails 3
45
- ::ActionController::ParamsParser.class_eval do
46
- def call(env)
47
- begin
48
- if params = parse_formatted_parameters(env)
49
- env["action_controller.request.request_parameters"] = params
50
- else
51
- if env["CONTENT_LENGTH"] && (env["CONTENT_LENGTH"] != "0")
52
- return [415, {'Content-Type' => 'text/html'}, "<html><body><h1>415 Unsupported Media Type</h1></body></html>"]
53
- end
54
- end
55
- rescue
56
- return [400, {'Content-Type' => 'text/html'}, "<html><body><h1>400 Bad Request</h1></body></html>"]
57
- end
45
+ #::ActionController::ParamsParser.class_eval do
46
+ #def call(env)
47
+ #begin
48
+ #if params = parse_formatted_parameters(env)
49
+ #env["action_controller.request.request_parameters"] = params
50
+ #else
51
+ #if env["CONTENT_LENGTH"] && (env["CONTENT_LENGTH"] != "0")
52
+ #return [415, {'Content-Type' => 'text/html'}, "<html><body><h1>415 Unsupported Media Type</h1></body></html>"]
53
+ #end
54
+ #end
55
+ #rescue
56
+ #return [400, {'Content-Type' => 'text/html'}, "<html><body><h1>400 Bad Request</h1></body></html>"]
57
+ #end
58
58
 
59
- @app.call(env)
60
- end
61
- end
59
+ #@app.call(env)
60
+ #end
61
+ #end
62
62
 
metadata CHANGED
@@ -5,8 +5,8 @@ version: !ruby/object:Gem::Version
5
5
  segments:
6
6
  - 0
7
7
  - 7
8
- - 0
9
- version: 0.7.0
8
+ - 1
9
+ version: 0.7.1
10
10
  platform: ruby
11
11
  authors:
12
12
  - Guilherme Silveira, Caue Guerra
@@ -14,7 +14,7 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-04-12 00:00:00 -03:00
17
+ date: 2010-04-21 00:00:00 -03:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
@@ -59,6 +59,20 @@ dependencies:
59
59
  version: 0.1.0
60
60
  type: :runtime
61
61
  version_requirements: *id003
62
+ - !ruby/object:Gem::Dependency
63
+ name: json_pure
64
+ prerelease: false
65
+ requirement: &id004 !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 1
71
+ - 2
72
+ - 4
73
+ version: 1.2.4
74
+ type: :runtime
75
+ version_requirements: *id004
62
76
  description:
63
77
  email: guilherme.silveira@caelum.com.br
64
78
  executables: []
@@ -74,7 +88,9 @@ files:
74
88
  - lib/restfulie/client/http/atom_ext.rb
75
89
  - lib/restfulie/client/http/cache.rb
76
90
  - lib/restfulie/client/http/error.rb
91
+ - lib/restfulie/client/http/link.rb
77
92
  - lib/restfulie/client/http/marshal.rb
93
+ - lib/restfulie/client/http/xml.rb
78
94
  - lib/restfulie/client/http.rb
79
95
  - lib/restfulie/client.rb
80
96
  - lib/restfulie/common/builder/builder_base.rb
@@ -94,6 +110,7 @@ files:
94
110
  - lib/restfulie/common/logger.rb
95
111
  - lib/restfulie/common/representation/atom.rb
96
112
  - lib/restfulie/common/representation/generic.rb
113
+ - lib/restfulie/common/representation/json.rb
97
114
  - lib/restfulie/common/representation/xml.rb
98
115
  - lib/restfulie/common/representation.rb
99
116
  - lib/restfulie/common.rb