restfulie 0.7.2 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/Gemfile +21 -0
  2. data/README.textile +10 -9
  3. data/Rakefile +12 -5
  4. data/lib/restfulie/client/base.rb +10 -6
  5. data/lib/restfulie/client/http/adapter.rb +48 -33
  6. data/lib/restfulie/client/http/atom_ext.rb +3 -68
  7. data/lib/restfulie/client/http/core_ext/http.rb +19 -0
  8. data/lib/restfulie/client/http/core_ext.rb +6 -0
  9. data/lib/restfulie/client/http/error.rb +3 -6
  10. data/lib/restfulie/client/http/marshal.rb +35 -49
  11. data/lib/restfulie/client/http/xml_ext.rb +7 -0
  12. data/lib/restfulie/client/http.rb +2 -2
  13. data/lib/restfulie/client/mikyung/concatenator.rb +15 -0
  14. data/lib/restfulie/client/mikyung/core.rb +44 -0
  15. data/lib/restfulie/client/mikyung/languages.rb +29 -0
  16. data/lib/restfulie/client/mikyung/rest_process_model.rb +114 -0
  17. data/lib/restfulie/client/mikyung/steady_state_walker.rb +32 -0
  18. data/lib/restfulie/client/mikyung/then_condition.rb +33 -0
  19. data/lib/restfulie/client/mikyung/when_condition.rb +53 -0
  20. data/lib/restfulie/client/mikyung.rb +19 -0
  21. data/lib/restfulie/client.rb +1 -0
  22. data/lib/restfulie/common/converter/atom/builder.rb +109 -0
  23. data/lib/restfulie/common/converter/atom/helpers.rb +9 -0
  24. data/lib/restfulie/common/converter/atom.rb +87 -0
  25. data/lib/restfulie/common/converter/values.rb +29 -0
  26. data/lib/restfulie/common/converter.rb +11 -0
  27. data/lib/restfulie/common/core_ext/proc.rb +48 -0
  28. data/lib/restfulie/common/core_ext.rb +5 -0
  29. data/lib/restfulie/common/errors.rb +6 -0
  30. data/lib/restfulie/common/representation/atom/atom.rng +597 -0
  31. data/lib/restfulie/common/representation/atom/base.rb +375 -0
  32. data/lib/restfulie/common/representation/atom/entry.rb +107 -0
  33. data/lib/restfulie/common/representation/atom/feed.rb +106 -0
  34. data/lib/restfulie/common/representation/atom.rb +43 -33
  35. data/lib/restfulie/common/representation/json.rb +1 -2
  36. data/lib/restfulie/common/representation/xml.rb +209 -23
  37. data/lib/restfulie/common/representation.rb +0 -1
  38. data/lib/restfulie/common.rb +2 -3
  39. data/lib/restfulie/server/action_controller/base.rb +21 -2
  40. data/lib/restfulie/server/action_controller/params_parser.rb +16 -16
  41. data/lib/restfulie/server/action_controller/restful_responder.rb +3 -3
  42. data/lib/restfulie/server/action_controller/routing/patch.rb +6 -0
  43. data/lib/restfulie/server/action_view/helpers.rb +8 -8
  44. data/lib/restfulie/server/action_view/template_handlers/tokamak.rb +3 -2
  45. data/lib/restfulie/server/core_ext/array.rb +13 -12
  46. metadata +51 -34
  47. data/lib/restfulie/client/http/link.rb +0 -39
  48. data/lib/restfulie/client/http/xml.rb +0 -4
  49. data/lib/restfulie/common/builder/builder_base.rb +0 -73
  50. data/lib/restfulie/common/builder/helpers.rb +0 -22
  51. data/lib/restfulie/common/builder/marshalling/atom.rb +0 -197
  52. data/lib/restfulie/common/builder/marshalling/base.rb +0 -12
  53. data/lib/restfulie/common/builder/marshalling/json.rb +0 -2
  54. data/lib/restfulie/common/builder/marshalling/xml.rb +0 -183
  55. data/lib/restfulie/common/builder/marshalling.rb +0 -16
  56. data/lib/restfulie/common/builder/rules/collection_rule.rb +0 -10
  57. data/lib/restfulie/common/builder/rules/custom_attributes.rb +0 -24
  58. data/lib/restfulie/common/builder/rules/link.rb +0 -20
  59. data/lib/restfulie/common/builder/rules/links.rb +0 -9
  60. data/lib/restfulie/common/builder/rules/member_rule.rb +0 -8
  61. data/lib/restfulie/common/builder/rules/namespace.rb +0 -35
  62. data/lib/restfulie/common/builder/rules/rules_base.rb +0 -77
  63. data/lib/restfulie/common/builder.rb +0 -17
  64. data/lib/vendor/atom/configuration.rb +0 -24
  65. data/lib/vendor/atom/pub.rb +0 -250
  66. data/lib/vendor/atom/xml/parser.rb +0 -373
  67. data/lib/vendor/atom.rb +0 -771
@@ -0,0 +1,375 @@
1
+ module Restfulie::Common::Representation::Atom
2
+
3
+ class XML
4
+ attr_accessor :doc
5
+
6
+ def initialize(xml_obj = nil)
7
+ if xml_obj
8
+ xml_obj.kind_of?(Nokogiri::XML::Document) ? @doc = xml_obj.root : @doc = xml_obj
9
+ else
10
+ @doc = Nokogiri::XML::Document.new
11
+ root_node = @doc.create_element(atom_type.to_s)
12
+ root_node.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
13
+ root_node.parent = @doc
14
+ @doc = @doc.root
15
+ end
16
+ end
17
+
18
+ # Tools
19
+ def css(*args)
20
+ @doc.css(*args)
21
+ end
22
+
23
+ def xpath(*args)
24
+ @doc.xpath(*args)
25
+ end
26
+
27
+ def atom_type
28
+ self.class.name.demodulize.downcase
29
+ end
30
+
31
+ def to_xml
32
+ @doc.to_xml
33
+ end
34
+
35
+ def to_s
36
+ to_xml
37
+ end
38
+
39
+ protected
40
+
41
+ def text(node_name)
42
+ (node = @doc.at_xpath("xmlns:#{node_name}")) ? node.content : nil
43
+ end
44
+
45
+ def set_text(node_name, value)
46
+ unless (node = @doc.at_xpath("xmlns:#{node_name}"))
47
+ node = create_element(node_name, value)
48
+ node.parent = @doc
49
+ else
50
+ value = value.xmlschema if value.kind_of?(Time) || value.kind_of?(DateTime)
51
+ node.content = value
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def create_element(node, *args)
58
+ node = @doc.document.create_element(node) do |n|
59
+ args.each do |arg|
60
+ case arg
61
+ # Adding XML attributes
62
+ when Hash
63
+ arg.each { |k,v|
64
+ key = k.to_s
65
+ if key =~ /^xmlns(:\w+)?$/
66
+ ns_name = key.split(":", 2)[1]
67
+ n.add_namespace_definition(ns_name, v)
68
+ next
69
+ end
70
+ n[k.to_s] = v.to_s
71
+ }
72
+ # Adding XML node content
73
+ else
74
+ arg.kind_of?(Time) || arg.kind_of?(DateTime) ? content = arg.xmlschema : content = arg
75
+ n.content = content
76
+ end
77
+ end
78
+ end
79
+ end
80
+
81
+ end
82
+
83
+
84
+ class Base < XML
85
+
86
+ ATOM_ATTRIBUTES = {
87
+ :feed => {
88
+ :required => [:id, :title, :updated],
89
+ :recommended => [:author, :link],
90
+ :optional => [:category, :contributor, :rights, :generator, :icon, :logo, :subtitle]
91
+ },
92
+
93
+ :entry => {
94
+ :required => [:id, :title, :updated],
95
+ :recommended => [:author, :link, :content, :summary],
96
+ :optional => [:category, :contributor, :rights, :published, :source]
97
+ }
98
+ }
99
+
100
+ def initialize(xml_obj = nil)
101
+ @authors = nil
102
+ @contributors = nil
103
+ @links = nil
104
+ @categories = nil
105
+ @reserved = []
106
+ super(xml_obj)
107
+ end
108
+
109
+ # lists all extension points available in this entry
110
+ def extensions
111
+ result = []
112
+ @doc.children.each do |e|
113
+ if e.element?
114
+ result << e unless @reserved.map(&:to_s).include?(e.node_name)
115
+ end
116
+ end
117
+ return result
118
+ end
119
+
120
+ #simpletext
121
+ def id
122
+ text("id")
123
+ end
124
+
125
+ def id=(value)
126
+ set_text("id", value)
127
+ end
128
+
129
+ # text
130
+ def title
131
+ text("title")
132
+ end
133
+
134
+ def title=(value)
135
+ set_text("title", value)
136
+ end
137
+
138
+ def updated
139
+ value = text("updated")
140
+ Time.parse(value) unless value.nil?
141
+ end
142
+
143
+ def updated=(value)
144
+ set_text("updated", value)
145
+ end
146
+
147
+ # text
148
+ def rights
149
+ text("rights")
150
+ end
151
+
152
+ def rights=(value)
153
+ set_text("rights", value)
154
+ end
155
+
156
+ # Author have name, and optional uri and email, this describes a person
157
+ def authors
158
+ unless @authors
159
+ @authors = TagCollection.new(@doc)
160
+ @doc.xpath("xmlns:author").each do |author|
161
+ @authors << Person.new("author", author)
162
+ end
163
+ end
164
+
165
+ return @authors
166
+ end
167
+
168
+ def contributors
169
+ unless @contributors
170
+ @contributors = TagCollection.new(@doc)
171
+ @doc.xpath("xmlns:author").each do |contributor|
172
+ @contributors << Person.new("contributor", contributor)
173
+ end
174
+ end
175
+
176
+ return @contributor
177
+ end
178
+
179
+ # It has one required attribute, href, and five optional attributes: rel, type, hreflang, title, and length
180
+ def links
181
+ unless @links
182
+ @links = TagCollection.new(@doc) do |array, symbol, *args|
183
+ linkset = array.select {|link| link.rel == symbol.to_s }
184
+ unless linkset.empty?
185
+ linkset.size == 1 ? linkset.first : linkset
186
+ else
187
+ nil
188
+ end
189
+ end
190
+ @doc.xpath("xmlns:link").each do |link|
191
+ @links << Link.new(link)
192
+ end
193
+ end
194
+
195
+ return @links
196
+ end
197
+
198
+ def categories
199
+ unless @categories
200
+ @categories = TagCollection.new(@doc)
201
+ @doc.xpath("xmlns:category").each do |category|
202
+ @categories << Link.new(category)
203
+ end
204
+ end
205
+
206
+ return @categories
207
+ end
208
+ end
209
+
210
+ class TagCollection < ::Array
211
+ def initialize(parent_node, &block)
212
+ @node = parent_node
213
+ @method_missing_block = block_given? ? block : nil
214
+ super(0)
215
+ end
216
+
217
+ def <<(obj)
218
+ obj = [obj] unless obj.kind_of?(Array)
219
+ obj.each do |o|
220
+ o.doc.parent = @node
221
+ super(o)
222
+ end
223
+ end
224
+
225
+ def delete(obj)
226
+ if super(obj)
227
+ obj.doc.unlink
228
+ obj = nil
229
+ end
230
+ end
231
+
232
+ def method_missing(symbol, *args, &block)
233
+ if @method_missing_block
234
+ @method_missing_block.call(self, symbol, *args)
235
+ else
236
+ super
237
+ end
238
+ end
239
+ end
240
+
241
+ class Link < XML
242
+ def initialize(options_or_obj)
243
+ if options_or_obj.kind_of?(Hash)
244
+ @doc = Nokogiri::XML::Document.new()
245
+ options_or_obj = create_element("link", options_or_obj)
246
+ end
247
+ super(options_or_obj)
248
+ end
249
+
250
+ def href
251
+ @doc["href"]
252
+ end
253
+
254
+ def href=(value)
255
+ @doc["href"] = value
256
+ end
257
+
258
+ def rel
259
+ @doc["rel"]
260
+ end
261
+
262
+ def rel=(value)
263
+ @doc["rel"] = value
264
+ end
265
+
266
+ alias_method :__type__, :type
267
+ def type
268
+ @doc["type"]
269
+ end
270
+
271
+ def type=(value)
272
+ @doc["type"] = value
273
+ end
274
+
275
+ def hreflang
276
+ @doc["hreflang"]
277
+ end
278
+
279
+ def hreflang=(value)
280
+ @doc["hreflang"] = value
281
+ end
282
+
283
+ def title
284
+ @doc["title"]
285
+ end
286
+
287
+ def title=(value)
288
+ @doc["title"] = value
289
+ end
290
+
291
+ def length
292
+ @doc["length"]
293
+ end
294
+
295
+ def length=(value)
296
+ @doc["length"] = value
297
+ end
298
+ end
299
+
300
+ class Person < XML
301
+ def initialize(node_type, options_or_obj)
302
+ if options_or_obj.kind_of?(Hash)
303
+ @doc = Nokogiri::XML::Document.new()
304
+ node = @doc.create_element(node_type)
305
+ node.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
306
+ node.parent = @doc
307
+ super(node)
308
+ options_or_obj.each do |key,value|
309
+ self.send("#{key}=".to_sym, value)
310
+ end
311
+ else
312
+ super(options_or_obj)
313
+ end
314
+ end
315
+
316
+ def name
317
+ text("name")
318
+ end
319
+
320
+ def name=(value)
321
+ set_text("name", value)
322
+ end
323
+
324
+ def uri
325
+ text("uri")
326
+ end
327
+
328
+ def uri=(value)
329
+ set_text("uri", value)
330
+ end
331
+
332
+ def email
333
+ text("email")
334
+ end
335
+
336
+ def email=(value)
337
+ set_text("email", value)
338
+ end
339
+ end
340
+
341
+ class Category < XML
342
+ def initialize(options_or_obj)
343
+ if options_or_obj.kind_of?(Hash)
344
+ @doc = Nokogiri::XML::Document.new()
345
+ options_or_obj = create_element("category", options_or_obj)
346
+ end
347
+ super(options_or_obj)
348
+ end
349
+
350
+ def term
351
+ @doc["term"]
352
+ end
353
+
354
+ def term=(value)
355
+ @doc["term"] = value
356
+ end
357
+
358
+ def scheme
359
+ @doc["scheme"]
360
+ end
361
+
362
+ def scheme=(value)
363
+ @doc["scheme"] = value
364
+ end
365
+
366
+ def label
367
+ @doc["label"]
368
+ end
369
+
370
+ def label=(value)
371
+ @doc["label"] = value
372
+ end
373
+ end
374
+
375
+ end
@@ -0,0 +1,107 @@
1
+ module Restfulie::Common::Representation::Atom
2
+
3
+ class Entry < Base
4
+
5
+ def initialize(xml_obj = nil)
6
+ @source = nil
7
+ super(xml_obj)
8
+ @reserved = Base::ATOM_ATTRIBUTES[:entry][:required] + Base::ATOM_ATTRIBUTES[:entry][:recommended] + Base::ATOM_ATTRIBUTES[:entry][:optional]
9
+ end
10
+
11
+ #text
12
+ def content
13
+ text("content")
14
+ end
15
+
16
+ def content=(value)
17
+ set_text("content", value)
18
+ end
19
+
20
+ #text
21
+ def summary
22
+ text("summary")
23
+ end
24
+
25
+ def summary=(value)
26
+ set_text("summary", value)
27
+ end
28
+
29
+ #rfc 3339
30
+ def published
31
+ value = text("published")
32
+ Time.parse(value) unless value.nil?
33
+ end
34
+
35
+ def published=(value)
36
+ set_text("published", value)
37
+ end
38
+
39
+ # comp: id, title, udpated, rights (optional)
40
+ def source
41
+ unless @source
42
+ @doc.xpath("xmlns:source").each do |source|
43
+ @source = Generator.new(source)
44
+ end
45
+ end
46
+
47
+ return source
48
+ end
49
+
50
+ def source=(obj)
51
+ @source = obj
52
+ end
53
+ end
54
+
55
+ class Source < XML
56
+ def initialize(options_or_obj)
57
+ if options_or_obj.kind_of?(Hash)
58
+ @doc = Nokogiri::XML::Document.new()
59
+ node = @doc.create_element("source")
60
+ node.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
61
+ node.parent = @doc
62
+ super(node)
63
+ options_or_obj.each do |key,value|
64
+ self.send("#{key}=".to_sym, value)
65
+ end
66
+ else
67
+ super(options_or_obj)
68
+ end
69
+ end
70
+
71
+ def id
72
+ text("id")
73
+ end
74
+
75
+ def id=(value)
76
+ set_text("id", value)
77
+ end
78
+
79
+ # text
80
+ def title
81
+ text("title")
82
+ end
83
+
84
+ def title=(value)
85
+ set_text("title", value)
86
+ end
87
+
88
+ def updated
89
+ value = text("updated")
90
+ Time.parse(value) unless value.nil?
91
+ end
92
+
93
+ def updated=(value)
94
+ set_text("updated", value)
95
+ end
96
+
97
+ # text
98
+ def rights
99
+ text("rights")
100
+ end
101
+
102
+ def rights=(value)
103
+ set_text("rights", value)
104
+ end
105
+ end
106
+ end
107
+
@@ -0,0 +1,106 @@
1
+ module Restfulie::Common::Representation::Atom
2
+
3
+ class Feed < Base
4
+
5
+ def initialize(xml_obj = nil)
6
+ @generator = nil
7
+ @entries = nil
8
+ super(xml_obj)
9
+ @reserved = Base::ATOM_ATTRIBUTES[:feed][:required] + Base::ATOM_ATTRIBUTES[:feed][:recommended] + Base::ATOM_ATTRIBUTES[:feed][:optional] + [:entry]
10
+ end
11
+
12
+ def entries
13
+ unless @entries
14
+ @entries = TagCollection.new(@doc)
15
+ @doc.xpath("xmlns:entry").each do |entry|
16
+ @entries << Entry.new(entry)
17
+ end
18
+ end
19
+
20
+ return @entries
21
+ end
22
+
23
+ # comp: attr: uri, version (optionals); content (mandatory)
24
+ def generator
25
+ unless @generator
26
+ @doc.xpath("xmlns:generator").each do |generator|
27
+ @generator = Generator.new(generator)
28
+ end
29
+ end
30
+
31
+ return generator
32
+ end
33
+
34
+ def generator=(obj)
35
+ @generator = obj
36
+ end
37
+
38
+ # simple text
39
+ def icon
40
+ text("icon")
41
+ end
42
+
43
+ def icon=(value)
44
+ set_text("icon", value)
45
+ end
46
+
47
+ # simple text
48
+ def logo
49
+ text("logo")
50
+ end
51
+
52
+ def logo=(value)
53
+ set_text("logo", value)
54
+ end
55
+
56
+ # text
57
+ def subtitle
58
+ text("subtitle")
59
+ end
60
+
61
+ def subtitle=(value)
62
+ set_text("subtitle", value)
63
+ end
64
+ end
65
+
66
+ class Generator < XML
67
+ def initialize(options_or_obj)
68
+ if options_or_obj.kind_of?(Hash)
69
+ @doc = Nokogiri::XML::Document.new()
70
+ node = @doc.create_element("generator")
71
+ node.add_namespace_definition(nil, "http://www.w3.org/2005/Atom")
72
+ node.parent = @doc
73
+ super(node)
74
+ options_or_obj.each do |key,value|
75
+ self.send("#{key}=".to_sym, value)
76
+ end
77
+ else
78
+ super(options_or_obj)
79
+ end
80
+ end
81
+
82
+ def content
83
+ @doc.content
84
+ end
85
+
86
+ def content=(value)
87
+ @doc.content = value
88
+ end
89
+
90
+ def uri
91
+ @doc["uri"]
92
+ end
93
+
94
+ def uri=(value)
95
+ @doc["uri"] = value
96
+ end
97
+
98
+ def version
99
+ @doc["version"]
100
+ end
101
+
102
+ def version=(value)
103
+ @doc["version"] = value
104
+ end
105
+ end
106
+ end
@@ -1,42 +1,52 @@
1
- module Restfulie::Common::Representation
2
- # Implements the interface for unmarshal Atom media type responses (application/atom+xml) to ruby objects instantiated by rAtom library.
3
- #
4
- # Furthermore, this class extends rAtom behavior to enable client users to easily access link relationships.
5
- class Atom
6
-
7
- cattr_reader :media_type_name
8
- @@media_type_name = 'application/atom+xml'
9
-
10
- cattr_reader :headers
11
- @@headers = {
12
- :get => { 'Accept' => media_type_name },
13
- :post => { 'Content-Type' => media_type_name }
14
- }
15
-
16
- #Convert raw string to rAtom instances (client side)
17
- def unmarshal(content)
18
- begin
19
- ::Atom::Feed.load_feed(content)
20
- rescue ::ArgumentError
21
- ::Atom::Entry.load_entry(content)
22
- end
23
- end
1
+ require 'nokogiri'
24
2
 
25
- def marshal(entity, rel)
26
- return entity if entity.kind_of? String
27
- entity.to_xml
28
- entity
3
+ #initialize namespace
4
+ module Restfulie::Common::Representation::Atom
5
+
6
+ # Create a new Representation::Atom object using a +string_or_io+
7
+ # object.
8
+ #
9
+ # Examples
10
+ # xml = IO.read("spec/units/lib/atoms/full_atom.xml")
11
+ # atom = Restfulie::Common::Representation::Atom.new(xml)
12
+ class Factory
13
+ # RelaxNG file to validate atom
14
+ RELAXNG_ATOM = File.join(File.dirname(__FILE__), 'atom', 'atom.rng')
15
+
16
+ if Nokogiri::VERSION_INFO["libxml"]["loaded"] < "2.7.7"
17
+ puts "WARNING! In order to use schema validation on atom representations you need libxml version 2.7.7 or superior loaded in your system."
18
+ SCHEMA = nil
19
+ else
20
+ SCHEMA = ::Nokogiri::XML::RelaxNG(File.open(RELAXNG_ATOM))
29
21
  end
30
22
 
31
- # transforms this content into a parameter hash for rails (server-side usage)
32
- def self.to_hash(content)
33
- Hash.from_xml(content).with_indifferent_access
23
+ class << self
24
+ def create(string_or_io)
25
+ doc = string_or_io.kind_of?(Nokogiri::XML::Document) ? string_or_io : Nokogiri::XML(string_or_io)
26
+
27
+ if SCHEMA && !(errors = SCHEMA.validate(doc)).empty?
28
+ raise Restfulie::Common::Representation::Atom::AtomInvalid.new("Invalid Atom: "+ errors.join(", "))
29
+ end
30
+
31
+ if doc.root.name == "feed"
32
+ Restfulie::Common::Representation::Atom::Feed.new(doc)
33
+ elsif doc.root.name == "entry"
34
+ Restfulie::Common::Representation::Atom::Entry.new(doc)
35
+ end
36
+ end
34
37
  end
35
38
 
36
- def prepare_link_for(link)
37
- link
38
- end
39
39
  end
40
+
41
+ class AtomInvalid < StandardError; end
42
+
43
+ end
40
44
 
45
+ %w(
46
+ base
47
+ feed
48
+ entry
49
+ ).each do |file|
50
+ require File.join(File.dirname(__FILE__), 'atom', file)
41
51
  end
42
52
 
@@ -12,8 +12,7 @@ module Restfulie::Common::Representation
12
12
  }
13
13
 
14
14
  def unmarshal(string)
15
- base = JSON.parse(string)
16
- base == {} ? {} : base.values.first
15
+ JSON.parse(string)
17
16
  end
18
17
 
19
18
  def marshal(entity, rel)