restfulie 0.6.0 → 0.7.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.
- data/README.textile +83 -7
- data/Rakefile +98 -13
- data/lib/restfulie/client/base.rb +48 -53
- data/lib/restfulie/client/configuration.rb +69 -0
- data/lib/restfulie/client/http/adapter.rb +487 -0
- data/lib/restfulie/client/http/atom_ext.rb +87 -0
- data/lib/restfulie/client/http/cache.rb +28 -0
- data/lib/restfulie/client/http/error.rb +80 -0
- data/lib/restfulie/client/http/marshal.rb +147 -0
- data/lib/restfulie/client/http.rb +13 -0
- data/lib/restfulie/client.rb +8 -56
- data/lib/restfulie/common/builder/builder_base.rb +58 -0
- data/lib/restfulie/common/builder/helpers.rb +22 -0
- data/lib/restfulie/common/builder/marshalling/atom.rb +197 -0
- data/lib/restfulie/common/builder/marshalling/base.rb +12 -0
- data/lib/restfulie/common/builder/marshalling/json.rb +2 -0
- data/lib/restfulie/common/builder/marshalling.rb +16 -0
- data/lib/restfulie/common/builder/rules/collection_rule.rb +10 -0
- data/lib/restfulie/common/builder/rules/link.rb +20 -0
- data/lib/restfulie/common/builder/rules/links.rb +9 -0
- data/lib/restfulie/common/builder/rules/member_rule.rb +8 -0
- data/lib/restfulie/common/builder/rules/namespace.rb +25 -0
- data/lib/restfulie/common/builder/rules/rules_base.rb +76 -0
- data/lib/restfulie/common/builder.rb +16 -0
- data/lib/restfulie/common/errors.rb +9 -0
- data/lib/restfulie/{logger.rb → common/logger.rb} +3 -5
- data/lib/restfulie/common/representation/atom.rb +48 -0
- data/lib/restfulie/common/representation/generic.rb +33 -0
- data/lib/restfulie/common/representation/xml.rb +24 -0
- data/lib/restfulie/common/representation.rb +10 -0
- data/lib/restfulie/common.rb +23 -0
- data/lib/restfulie/server/action_controller/base.rb +31 -0
- data/lib/restfulie/server/action_controller/params_parser.rb +62 -0
- data/lib/restfulie/server/action_controller/restful_responder.rb +39 -0
- data/lib/restfulie/server/action_controller/routing/restful_route.rb +14 -0
- data/lib/restfulie/server/action_controller/routing.rb +12 -0
- data/lib/restfulie/server/action_controller.rb +15 -0
- data/lib/restfulie/server/action_view/helpers.rb +45 -0
- data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +15 -0
- data/lib/restfulie/server/action_view/template_handlers.rb +13 -0
- data/lib/restfulie/server/action_view.rb +8 -0
- data/lib/restfulie/server/configuration.rb +21 -0
- data/lib/restfulie/server/core_ext/array.rb +45 -0
- data/lib/restfulie/server/core_ext.rb +1 -0
- data/lib/restfulie/server/restfulie_controller.rb +1 -17
- data/lib/restfulie/server.rb +15 -0
- data/lib/restfulie.rb +4 -72
- data/lib/vendor/atom/configuration.rb +24 -0
- data/lib/vendor/atom/pub.rb +250 -0
- data/lib/vendor/atom/xml/parser.rb +373 -0
- data/lib/vendor/atom.rb +771 -0
- metadata +94 -33
- data/lib/restfulie/client/atom_media_type.rb +0 -75
- data/lib/restfulie/client/cache.rb +0 -103
- data/lib/restfulie/client/entry_point.rb +0 -94
- data/lib/restfulie/client/extensions/http.rb +0 -116
- data/lib/restfulie/client/helper.rb +0 -28
- data/lib/restfulie/client/instance.rb +0 -158
- data/lib/restfulie/client/request_execution.rb +0 -321
- data/lib/restfulie/client/state.rb +0 -36
- data/lib/restfulie/media_type.rb +0 -143
- data/lib/restfulie/media_type_control.rb +0 -115
- data/lib/restfulie/media_type_defaults.rb +0 -51
- data/lib/restfulie/server/atom_media_type.rb +0 -115
- data/lib/restfulie/server/base.rb +0 -91
- data/lib/restfulie/server/controller.rb +0 -122
- data/lib/restfulie/server/instance.rb +0 -102
- data/lib/restfulie/server/marshalling.rb +0 -47
- data/lib/restfulie/server/opensearch/description.rb +0 -54
- data/lib/restfulie/server/opensearch.rb +0 -18
- data/lib/restfulie/server/transition.rb +0 -93
- data/lib/restfulie/unmarshalling.rb +0 -131
- data/lib/vendor/jeokkarak/hashi.rb +0 -65
- data/lib/vendor/jeokkarak/jeokkarak.rb +0 -81
@@ -0,0 +1,373 @@
|
|
1
|
+
# Copyright (c) 2008 The Kaphan Foundation
|
2
|
+
#
|
3
|
+
# For licensing information see LICENSE.txt.
|
4
|
+
#
|
5
|
+
# Please visit http://www.peerworks.org/contact for further information.
|
6
|
+
#
|
7
|
+
require 'net/http'
|
8
|
+
require 'time'
|
9
|
+
|
10
|
+
# Just a couple methods form transforming strings
|
11
|
+
unless defined?(ActiveSupport)
|
12
|
+
class String # :nodoc:
|
13
|
+
def singularize
|
14
|
+
if self =~ /ies$/
|
15
|
+
self.sub(/ies$/, 'y')
|
16
|
+
else
|
17
|
+
self.sub(/s$/, '')
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def demodulize
|
22
|
+
self.sub(/.*::/, '')
|
23
|
+
end
|
24
|
+
|
25
|
+
def constantize
|
26
|
+
Object.module_eval("::#{self}", __FILE__, __LINE__)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
module Atom
|
32
|
+
class LoadError < StandardError
|
33
|
+
attr_reader :response
|
34
|
+
def initialize(response)
|
35
|
+
@response = response
|
36
|
+
end
|
37
|
+
|
38
|
+
def to_s
|
39
|
+
"Atom::LoadError: #{response.code} #{response.message}"
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
module Xml # :nodoc:
|
44
|
+
class NamespaceMap
|
45
|
+
def initialize(default = Atom::NAMESPACE)
|
46
|
+
@default = default
|
47
|
+
@i = 0
|
48
|
+
@map = {}
|
49
|
+
end
|
50
|
+
|
51
|
+
def prefix(ns, element)
|
52
|
+
if ns == @default
|
53
|
+
element
|
54
|
+
else
|
55
|
+
"#{get(ns)}:#{element}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get(ns)
|
60
|
+
if ns == Atom::NAMESPACE
|
61
|
+
@map[ns] = "atom"
|
62
|
+
elsif ns == Atom::Pub::NAMESPACE
|
63
|
+
@map[ns] = "app"
|
64
|
+
else
|
65
|
+
@map[ns] or @map[ns] = "ns#{@i += 1}"
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
def each(&block)
|
70
|
+
@map.each(&block)
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
module Parseable # :nodoc:
|
75
|
+
def parse(xml, options = {})
|
76
|
+
starting_depth = xml.depth
|
77
|
+
loop do
|
78
|
+
case xml.node_type
|
79
|
+
when XML::Reader::TYPE_ELEMENT
|
80
|
+
if element_specs.include?(xml.local_name) && (self.class.known_namespaces + [Atom::NAMESPACE, Atom::Pub::NAMESPACE]).include?(xml.namespace_uri)
|
81
|
+
element_specs[xml.local_name].parse(self, xml)
|
82
|
+
elsif attributes.any?
|
83
|
+
while (xml.move_to_next_attribute == 1)
|
84
|
+
if attributes.include?(xml.name)
|
85
|
+
# Support attribute names with namespace prefixes
|
86
|
+
self.send("#{xml.name.sub(/:/, '_')}=", xml.value)
|
87
|
+
elsif self.respond_to?(:simple_extensions)
|
88
|
+
self[xml.namespace_uri, xml.local_name].as_attribute = true
|
89
|
+
self[xml.namespace_uri, xml.local_name] << xml.value
|
90
|
+
end
|
91
|
+
end
|
92
|
+
elsif self.respond_to?(:simple_extensions)
|
93
|
+
self[xml.namespace_uri, xml.local_name] << xml.read_inner_xml
|
94
|
+
end
|
95
|
+
end
|
96
|
+
break unless !options[:once] && xml.next == 1 && xml.depth >= starting_depth
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def next_node_is?(xml, element, ns = nil)
|
101
|
+
# Get to the next element
|
102
|
+
while xml.next == 1 && xml.node_type != XML::Reader::TYPE_ELEMENT; end
|
103
|
+
current_node_is?(xml, element, ns)
|
104
|
+
end
|
105
|
+
|
106
|
+
def current_node_is?(xml, element, ns = nil)
|
107
|
+
xml.node_type == XML::Reader::TYPE_ELEMENT && xml.local_name == element && (ns.nil? || ns == xml.namespace_uri)
|
108
|
+
end
|
109
|
+
|
110
|
+
def Parseable.included(o)
|
111
|
+
o.class_eval do
|
112
|
+
def o.ordered_element_specs; @ordered_element_specs ||= []; end
|
113
|
+
def o.element_specs; @element_specs ||= {}; end
|
114
|
+
def o.attributes; @attributes ||= []; end
|
115
|
+
def element_specs; self.class.element_specs; end
|
116
|
+
def ordered_element_specs; self.class.ordered_element_specs; end
|
117
|
+
def attributes; self.class.attributes; end
|
118
|
+
def o.namespace(ns = @namespace); @namespace = ns; end
|
119
|
+
def o.add_extension_namespace(ns, url); self.extensions_namespaces[ns.to_s] = url; end
|
120
|
+
def o.extensions_namespaces; @extensions_namespaces ||= {} end
|
121
|
+
def o.known_namespaces; @known_namespaces ||= [] end
|
122
|
+
end
|
123
|
+
o.send(:extend, DeclarationMethods)
|
124
|
+
end
|
125
|
+
|
126
|
+
def ==(o)
|
127
|
+
if self.object_id == o.object_id
|
128
|
+
true
|
129
|
+
elsif o.instance_of?(self.class)
|
130
|
+
self.class.element_specs.values.all? do |spec|
|
131
|
+
self.send(spec.attribute) == o.send(spec.attribute)
|
132
|
+
end
|
133
|
+
else
|
134
|
+
false
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
# There doesn't seem to be a way to set namespaces using libxml-ruby,
|
139
|
+
# so ratom has to manage namespace to URI prefixing itself, which
|
140
|
+
# makes this method more complicated that it needs to be.
|
141
|
+
#
|
142
|
+
def to_xml(nodeonly = false, root_name = self.class.name.demodulize.downcase, namespace = nil, namespace_map = nil)
|
143
|
+
namespace_map = NamespaceMap.new(self.class.namespace) if namespace_map.nil?
|
144
|
+
node = XML::Node.new(root_name)
|
145
|
+
node['xmlns'] = self.class.namespace unless nodeonly || !self.class.respond_to?(:namespace)
|
146
|
+
self.class.extensions_namespaces.each do |ns_alias,uri|
|
147
|
+
node["xmlns:#{ns_alias}"] = uri
|
148
|
+
end
|
149
|
+
|
150
|
+
self.class.ordered_element_specs.each do |spec|
|
151
|
+
if spec.single?
|
152
|
+
if attribute = self.send(spec.attribute)
|
153
|
+
if attribute.respond_to?(:to_xml)
|
154
|
+
node << attribute.to_xml(true, spec.name, spec.options[:namespace], namespace_map)
|
155
|
+
else
|
156
|
+
n = XML::Node.new(spec.name)
|
157
|
+
n['xmlns'] = spec.options[:namespace] if spec.options[:namespace]
|
158
|
+
n << (attribute.is_a?(Time)? attribute.xmlschema : attribute.to_s)
|
159
|
+
node << n
|
160
|
+
end
|
161
|
+
end
|
162
|
+
else
|
163
|
+
self.send(spec.attribute).each do |attribute|
|
164
|
+
if attribute.respond_to?(:to_xml)
|
165
|
+
node << attribute.to_xml(true, spec.name.singularize, nil, namespace_map)
|
166
|
+
else
|
167
|
+
n = XML::Node.new(spec.name.singularize)
|
168
|
+
n['xmlns'] = spec.options[:namespace] if spec.options[:namespace]
|
169
|
+
n << attribute.to_s
|
170
|
+
node << n
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
self.class.attributes.each do |attribute|
|
177
|
+
if value = self.send("#{attribute.sub(/:/, '_')}")
|
178
|
+
if value != 0
|
179
|
+
node[attribute] = value.to_s
|
180
|
+
end
|
181
|
+
end
|
182
|
+
end
|
183
|
+
|
184
|
+
if self.respond_to?(:simple_extensions) && self.simple_extensions
|
185
|
+
self.simple_extensions.each do |name, value_array|
|
186
|
+
if name =~ /\{(.*),(.*)\}/
|
187
|
+
value_array.each do |value|
|
188
|
+
if value_array.as_attribute
|
189
|
+
node["#{namespace_map.get($1)}:#{$2}"] = value
|
190
|
+
else
|
191
|
+
ext = XML::Node.new("#{namespace_map.get($1)}:#{$2}")
|
192
|
+
ext << value
|
193
|
+
node << ext
|
194
|
+
end
|
195
|
+
end
|
196
|
+
else
|
197
|
+
STDERR.print "Couldn't split #{name}"
|
198
|
+
end
|
199
|
+
end
|
200
|
+
end
|
201
|
+
|
202
|
+
unless nodeonly
|
203
|
+
namespace_map.each do |ns, prefix|
|
204
|
+
node["xmlns:#{prefix}"] = ns
|
205
|
+
end
|
206
|
+
|
207
|
+
doc = XML::Document.new
|
208
|
+
doc.root = node
|
209
|
+
doc.to_s
|
210
|
+
else
|
211
|
+
node
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
module DeclarationMethods # :nodoc:
|
216
|
+
def element(*names)
|
217
|
+
options = {:type => :single}
|
218
|
+
options.merge!(names.pop) if names.last.is_a?(Hash)
|
219
|
+
|
220
|
+
names.each do |name|
|
221
|
+
attr_accessor name.to_s.sub(/:/, '_').to_sym
|
222
|
+
ns, local_name = name.to_s[/(.*):(.*)/,1], $2 || name
|
223
|
+
self.known_namespaces << self.extensions_namespaces[ns] if ns
|
224
|
+
self.ordered_element_specs << self.element_specs[local_name.to_s] = ParseSpec.new(name, options)
|
225
|
+
end
|
226
|
+
end
|
227
|
+
|
228
|
+
def elements(*names)
|
229
|
+
options = {:type => :collection}
|
230
|
+
options.merge!(names.pop) if names.last.is_a?(Hash)
|
231
|
+
|
232
|
+
names.each do |name|
|
233
|
+
name_sym = name.to_s.sub(/:/, '_').to_sym
|
234
|
+
attr_writer name_sym
|
235
|
+
define_method name_sym do
|
236
|
+
ivar = :"@#{name_sym}"
|
237
|
+
self.instance_variable_set ivar, [] unless self.instance_variable_defined? ivar
|
238
|
+
self.instance_variable_get ivar
|
239
|
+
end
|
240
|
+
ns, local_name = name.to_s[/(.*):(.*)/,1], $2 || name
|
241
|
+
self.known_namespaces << self.extensions_namespaces[ns] if ns
|
242
|
+
self.ordered_element_specs << self.element_specs[local_name.to_s.singularize] = ParseSpec.new(name, options)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
|
246
|
+
def attribute(*names)
|
247
|
+
names.each do |name|
|
248
|
+
attr_accessor name.to_s.sub(/:/, '_').to_sym
|
249
|
+
self.attributes << name.to_s
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
def loadable!(&error_handler)
|
254
|
+
class_name = self.name
|
255
|
+
(class << self; self; end).instance_eval do
|
256
|
+
|
257
|
+
define_method "load_#{class_name.demodulize.downcase}" do |*args|
|
258
|
+
o = args.first
|
259
|
+
opts = args.size > 1 ? args.last : {}
|
260
|
+
|
261
|
+
xml =
|
262
|
+
case o
|
263
|
+
when String
|
264
|
+
XML::Reader.string(o)
|
265
|
+
when IO
|
266
|
+
XML::Reader.io(o)
|
267
|
+
when URI
|
268
|
+
raise ArgumentError, "#{class_name}.load only handles http URIs" if o.scheme != 'http'
|
269
|
+
response = nil
|
270
|
+
Net::HTTP.start(o.host, o.port) do |http|
|
271
|
+
request = Net::HTTP::Get.new(o.request_uri)
|
272
|
+
if opts[:user] && opts[:pass]
|
273
|
+
request.basic_auth(opts[:user], opts[:pass])
|
274
|
+
elsif opts[:hmac_access_id] && opts[:hmac_secret_key]
|
275
|
+
if Atom::Configuration.auth_hmac_enabled?
|
276
|
+
AuthHMAC.sign!(request, opts[:hmac_access_id], opts[:hmac_secret_key])
|
277
|
+
else
|
278
|
+
raise ArgumentError, "AuthHMAC credentials provides by auth-hmac gem is not installed"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
response = http.request(request)
|
282
|
+
end
|
283
|
+
case response
|
284
|
+
when Net::HTTPSuccess
|
285
|
+
XML::Reader.string(response.body)
|
286
|
+
when nil
|
287
|
+
raise ArgumentError.new("nil response to #{o}")
|
288
|
+
else
|
289
|
+
raise Atom::LoadError.new(response)
|
290
|
+
end
|
291
|
+
else
|
292
|
+
raise ArgumentError, "#{class_name}.load needs String, URI or IO, got #{o.class.name}"
|
293
|
+
end
|
294
|
+
|
295
|
+
if error_handler
|
296
|
+
XML::Error.set_handler(&error_handler)
|
297
|
+
else
|
298
|
+
XML::Error.set_handler do |reader, message, severity, base, line|
|
299
|
+
if severity == XML::Reader::SEVERITY_ERROR
|
300
|
+
raise ArgumentError, "#{message} at #{line} in #{o}"
|
301
|
+
end
|
302
|
+
end
|
303
|
+
end
|
304
|
+
|
305
|
+
o = self.new(xml)
|
306
|
+
xml.close
|
307
|
+
o
|
308
|
+
end
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
def parse(xml)
|
313
|
+
new(xml)
|
314
|
+
end
|
315
|
+
end
|
316
|
+
|
317
|
+
# Contains the specification for how an element should be parsed.
|
318
|
+
#
|
319
|
+
# This should not need to be constructed directly, instead use the
|
320
|
+
# element and elements macros in the declaration of the class.
|
321
|
+
#
|
322
|
+
# See Parseable.
|
323
|
+
#
|
324
|
+
class ParseSpec # :nodoc:
|
325
|
+
attr_reader :name, :options, :attribute
|
326
|
+
|
327
|
+
def initialize(name, options = {})
|
328
|
+
@name = name.to_s
|
329
|
+
@attribute = name.to_s.sub(/:/, '_')
|
330
|
+
@options = options
|
331
|
+
end
|
332
|
+
|
333
|
+
# Parses a chunk of XML according the specification.
|
334
|
+
# The data extracted will be assigned to the target object.
|
335
|
+
#
|
336
|
+
def parse(target, xml)
|
337
|
+
case options[:type]
|
338
|
+
when :single
|
339
|
+
target.send("#{@attribute}=".to_sym, build(target, xml))
|
340
|
+
when :collection
|
341
|
+
collection = target.send(@attribute.to_s)
|
342
|
+
element = build(target, xml)
|
343
|
+
collection << element
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
def single?
|
348
|
+
options[:type] == :single
|
349
|
+
end
|
350
|
+
|
351
|
+
private
|
352
|
+
# Create a member
|
353
|
+
def build(target, xml)
|
354
|
+
if options[:class].is_a?(Class)
|
355
|
+
if options[:content_only]
|
356
|
+
options[:class].parse(xml.read_string)
|
357
|
+
else
|
358
|
+
options[:class].parse(xml)
|
359
|
+
end
|
360
|
+
elsif options[:type] == :single
|
361
|
+
xml.read_string
|
362
|
+
elsif options[:content_only]
|
363
|
+
xml.read_string
|
364
|
+
else
|
365
|
+
target_class = target.class.name
|
366
|
+
target_class = target_class.sub(/#{target_class.demodulize}$/, name.singularize.capitalize)
|
367
|
+
target_class.constantize.parse(xml)
|
368
|
+
end
|
369
|
+
end
|
370
|
+
end
|
371
|
+
end
|
372
|
+
end
|
373
|
+
end
|