restfulie 0.7.0 → 0.7.1
Sign up to get free protection for your applications and to get access to all the features.
- data/README.textile +1 -0
- data/Rakefile +2 -1
- data/lib/restfulie/client/base.rb +8 -2
- data/lib/restfulie/client/http/atom_ext.rb +12 -30
- data/lib/restfulie/client/http/link.rb +39 -0
- data/lib/restfulie/client/http/marshal.rb +41 -29
- data/lib/restfulie/client/http/xml.rb +4 -0
- data/lib/restfulie/client/http.rb +2 -0
- data/lib/restfulie/common/representation/atom.rb +0 -8
- data/lib/restfulie/common/representation/json.rb +25 -0
- data/lib/restfulie/common/representation/xml.rb +27 -3
- data/lib/restfulie/common/representation.rb +2 -0
- data/lib/restfulie/server/action_controller/params_parser.rb +16 -16
- metadata +20 -3
data/README.textile
CHANGED
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.
|
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
|
-
|
58
|
-
|
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><link rel="next" href="http://resource.entrypoint.com/post/12" type="application/atom+xml" /></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
|
51
|
+
include Restfulie::Client::LinkShortcut
|
79
52
|
include AtomElementShortcut
|
80
53
|
}
|
81
54
|
::Atom::Entry.instance_eval {
|
82
|
-
include
|
55
|
+
include Restfulie::Client::LinkShortcut
|
83
56
|
include AtomElementShortcut
|
84
57
|
}
|
85
|
-
::Atom::Link.instance_eval {
|
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><link rel="next" href="http://resource.entrypoint.com/post/12" type="application/atom+xml" /></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
|
-
|
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
|
-
|
56
|
-
if
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
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
|
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
|
86
|
+
def parse_response(response)
|
76
87
|
if response.code == 201
|
77
|
-
|
78
|
-
|
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
|
-
|
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,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
|
-
|
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
|
-
|
@@ -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
|
-
|
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
|
-
|
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
|
-
-
|
9
|
-
version: 0.7.
|
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-
|
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
|