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