restfulie 0.6.0 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. data/README.textile +83 -7
  2. data/Rakefile +98 -13
  3. data/lib/restfulie/client/base.rb +48 -53
  4. data/lib/restfulie/client/configuration.rb +69 -0
  5. data/lib/restfulie/client/http/adapter.rb +487 -0
  6. data/lib/restfulie/client/http/atom_ext.rb +87 -0
  7. data/lib/restfulie/client/http/cache.rb +28 -0
  8. data/lib/restfulie/client/http/error.rb +80 -0
  9. data/lib/restfulie/client/http/marshal.rb +147 -0
  10. data/lib/restfulie/client/http.rb +13 -0
  11. data/lib/restfulie/client.rb +8 -56
  12. data/lib/restfulie/common/builder/builder_base.rb +58 -0
  13. data/lib/restfulie/common/builder/helpers.rb +22 -0
  14. data/lib/restfulie/common/builder/marshalling/atom.rb +197 -0
  15. data/lib/restfulie/common/builder/marshalling/base.rb +12 -0
  16. data/lib/restfulie/common/builder/marshalling/json.rb +2 -0
  17. data/lib/restfulie/common/builder/marshalling.rb +16 -0
  18. data/lib/restfulie/common/builder/rules/collection_rule.rb +10 -0
  19. data/lib/restfulie/common/builder/rules/link.rb +20 -0
  20. data/lib/restfulie/common/builder/rules/links.rb +9 -0
  21. data/lib/restfulie/common/builder/rules/member_rule.rb +8 -0
  22. data/lib/restfulie/common/builder/rules/namespace.rb +25 -0
  23. data/lib/restfulie/common/builder/rules/rules_base.rb +76 -0
  24. data/lib/restfulie/common/builder.rb +16 -0
  25. data/lib/restfulie/common/errors.rb +9 -0
  26. data/lib/restfulie/{logger.rb → common/logger.rb} +3 -5
  27. data/lib/restfulie/common/representation/atom.rb +48 -0
  28. data/lib/restfulie/common/representation/generic.rb +33 -0
  29. data/lib/restfulie/common/representation/xml.rb +24 -0
  30. data/lib/restfulie/common/representation.rb +10 -0
  31. data/lib/restfulie/common.rb +23 -0
  32. data/lib/restfulie/server/action_controller/base.rb +31 -0
  33. data/lib/restfulie/server/action_controller/params_parser.rb +62 -0
  34. data/lib/restfulie/server/action_controller/restful_responder.rb +39 -0
  35. data/lib/restfulie/server/action_controller/routing/restful_route.rb +14 -0
  36. data/lib/restfulie/server/action_controller/routing.rb +12 -0
  37. data/lib/restfulie/server/action_controller.rb +15 -0
  38. data/lib/restfulie/server/action_view/helpers.rb +45 -0
  39. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +15 -0
  40. data/lib/restfulie/server/action_view/template_handlers.rb +13 -0
  41. data/lib/restfulie/server/action_view.rb +8 -0
  42. data/lib/restfulie/server/configuration.rb +21 -0
  43. data/lib/restfulie/server/core_ext/array.rb +45 -0
  44. data/lib/restfulie/server/core_ext.rb +1 -0
  45. data/lib/restfulie/server/restfulie_controller.rb +1 -17
  46. data/lib/restfulie/server.rb +15 -0
  47. data/lib/restfulie.rb +4 -72
  48. data/lib/vendor/atom/configuration.rb +24 -0
  49. data/lib/vendor/atom/pub.rb +250 -0
  50. data/lib/vendor/atom/xml/parser.rb +373 -0
  51. data/lib/vendor/atom.rb +771 -0
  52. metadata +94 -33
  53. data/lib/restfulie/client/atom_media_type.rb +0 -75
  54. data/lib/restfulie/client/cache.rb +0 -103
  55. data/lib/restfulie/client/entry_point.rb +0 -94
  56. data/lib/restfulie/client/extensions/http.rb +0 -116
  57. data/lib/restfulie/client/helper.rb +0 -28
  58. data/lib/restfulie/client/instance.rb +0 -158
  59. data/lib/restfulie/client/request_execution.rb +0 -321
  60. data/lib/restfulie/client/state.rb +0 -36
  61. data/lib/restfulie/media_type.rb +0 -143
  62. data/lib/restfulie/media_type_control.rb +0 -115
  63. data/lib/restfulie/media_type_defaults.rb +0 -51
  64. data/lib/restfulie/server/atom_media_type.rb +0 -115
  65. data/lib/restfulie/server/base.rb +0 -91
  66. data/lib/restfulie/server/controller.rb +0 -122
  67. data/lib/restfulie/server/instance.rb +0 -102
  68. data/lib/restfulie/server/marshalling.rb +0 -47
  69. data/lib/restfulie/server/opensearch/description.rb +0 -54
  70. data/lib/restfulie/server/opensearch.rb +0 -18
  71. data/lib/restfulie/server/transition.rb +0 -93
  72. data/lib/restfulie/unmarshalling.rb +0 -131
  73. data/lib/vendor/jeokkarak/hashi.rb +0 -65
  74. 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