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