restfulie 0.7.2 → 0.8.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 (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)