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
data/lib/vendor/atom.rb DELETED
@@ -1,771 +0,0 @@
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
-
8
- require 'forwardable'
9
- require 'delegate'
10
- require 'rubygems'
11
- gem 'libxml-ruby', '>= 1.1.2'
12
- require 'xml/libxml'
13
- require 'vendor/atom/xml/parser.rb'
14
-
15
- module Atom # :nodoc:
16
- NAMESPACE = 'http://www.w3.org/2005/Atom' unless defined?(NAMESPACE)
17
- module Pub
18
- NAMESPACE = 'http://www.w3.org/2007/app'
19
- end
20
-
21
- # Raised when a Serialization Error occurs.
22
- class SerializationError < StandardError; end
23
-
24
- # Provides support for reading and writing simple extensions as defined by the Atom Syndication Format.
25
- #
26
- # A Simple extension is an element from a non-atom namespace that has no attributes and only contains
27
- # text content. It is interpreted as a key-value pair when the namespace and the localname of the
28
- # extension make up the key. Since in XML you can have many instances of an element, the values are
29
- # represented as an array of strings, so to manipulate the values manipulate the array returned by
30
- # +[ns, localname]+.
31
- #
32
- module SimpleExtensions
33
- attr_reader :simple_extensions
34
-
35
- # Gets a simple extension value for a given namespace and local name.
36
- #
37
- # +ns+:: The namespace.
38
- # +localname+:: The local name of the extension element.
39
- #
40
- def [](namespace, localname=nil)
41
- @simple_extensions ||= {}
42
-
43
- localname.nil? ? namespace_hash(namespace) : element_values(namespace, localname)
44
- end
45
-
46
- protected
47
-
48
- def namespace_hash(namespace)
49
- namespace_keys = @simple_extensions.keys.select { |key| key =~ /^\{#{namespace},/ }
50
-
51
- elements = {}
52
- namespace_keys.each do |key|
53
- attribute_name = key.match(/\{.*,(.*)\}/)[1]
54
- elements[attribute_name] = @simple_extensions[key]
55
- end
56
- elements
57
- end
58
-
59
- def element_values(namespace, localname)
60
- key = "{#{namespace},#{localname}}"
61
- @simple_extensions[key] ||= ValueProxy.new
62
- end
63
-
64
- class ValueProxy < DelegateClass(Array)
65
- attr_accessor :as_attribute
66
- def initialize
67
- super([])
68
- @as_attribute = false
69
- end
70
- end
71
- end
72
-
73
- # Represents a Generator as defined by the Atom Syndication Format specification.
74
- #
75
- # The generator identifies an agent or engine used to a produce a feed.
76
- #
77
- # See also http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.generator
78
- class Generator
79
- include Xml::Parseable
80
-
81
- attr_accessor :name
82
- attribute :uri, :version
83
-
84
- # Initialize a new Generator.
85
- #
86
- # +xml+:: An XML::Reader object.
87
- #
88
- def initialize(o = {})
89
- case o
90
- when XML::Reader
91
- @name = o.read_string.strip
92
- parse(o, :once => true)
93
- when Hash
94
- o.each do |k, v|
95
- self.send("#{k.to_s}=", v)
96
- end
97
- else
98
- raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
99
- end
100
-
101
- yield(self) if block_given?
102
- end
103
-
104
- def to_xml(nodeonly = true, name = 'generator', namespace = nil, namespace_map = Atom::Xml::NamespaceMap.new)
105
- node = XML::Node.new("#{namespace_map.prefix(Atom::NAMESPACE, name)}")
106
- node << @name if @name
107
- node['uri'] = @uri if @uri
108
- node['version'] = @version if @version
109
- node
110
- end
111
- end
112
-
113
- # Represents a Category as defined by the Atom Syndication Format specification.
114
- #
115
- #
116
- class Category
117
- include Atom::Xml::Parseable
118
- include SimpleExtensions
119
- attribute :label, :scheme, :term
120
-
121
- def initialize(o = {})
122
- case o
123
- when XML::Reader
124
- parse(o, :once => true)
125
- when Hash
126
- o.each do |k, v|
127
- self.send("#{k.to_s}=", v)
128
- end
129
- else
130
- raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
131
- end
132
-
133
- yield(self) if block_given?
134
- end
135
- end
136
-
137
- # Represents a Person as defined by the Atom Syndication Format specification.
138
- #
139
- # A Person is used for all author and contributor attributes.
140
- #
141
- # See also http://www.atomenabled.org/developers/syndication/atom-format-spec.php#atomPersonConstruct
142
- #
143
- class Person
144
- include Xml::Parseable
145
- element :name, :uri, :email
146
-
147
- # Initialize a new person.
148
- #
149
- # +o+:: An XML::Reader object or a hash. Valid hash keys are +:name+, +:uri+ and +:email+.
150
- def initialize(o = {})
151
- case o
152
- when XML::Reader
153
- o.read
154
- parse(o)
155
- when Hash
156
- o.each do |k, v|
157
- self.send("#{k.to_s}=", v)
158
- end
159
- else
160
- raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
161
- end
162
-
163
- yield(self) if block_given?
164
- end
165
-
166
- def inspect
167
- "<Atom::Person name:'#{name}' uri:'#{uri}' email:'#{email}"
168
- end
169
- end
170
-
171
- class Content # :nodoc:
172
- def self.parse(xml)
173
- case xml['type']
174
- when "xhtml"
175
- Xhtml.new(xml)
176
- when "html"
177
- Html.new(xml)
178
- else
179
- Text.new(xml)
180
- end
181
- end
182
-
183
- # This is the base class for all content within an atom document.
184
- #
185
- # Content can be Text, Html or Xhtml.
186
- #
187
- # A Content object can be treated as a String with type and xml_lang
188
- # attributes.
189
- #
190
- # For a thorough discussion of atom content see
191
- # http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.content
192
- class Base < DelegateClass(String)
193
- include Xml::Parseable
194
-
195
- def initialize(c)
196
- __setobj__(c)
197
- end
198
-
199
- def ==(o)
200
- if o.is_a?(self.class)
201
- self.type == o.type &&
202
- self.xml_lang == o.xml_lang &&
203
- self.to_s == o.to_s
204
- elsif o.is_a?(String)
205
- self.to_s == o
206
- end
207
- end
208
-
209
- protected
210
- def set_content(c) # :nodoc:
211
- __setobj__(c)
212
- end
213
- end
214
-
215
- # Text content within an Atom document.
216
- class Text < Base
217
- attribute :type, :'xml:lang'
218
- def initialize(o)
219
- case o
220
- when String
221
- super(o)
222
- @type = "text"
223
- when XML::Reader
224
- super(o.read_string)
225
- parse(o, :once => true)
226
- else
227
- raise ArgumentError, "Got #{o} which isn't a String or XML::Reader"
228
- end
229
- end
230
-
231
- def to_xml(nodeonly = true, name = 'content', namespace = nil, namespace_map = Atom::Xml::NamespaceMap.new)
232
- node = XML::Node.new("#{namespace_map.prefix(Atom::NAMESPACE, name)}")
233
- node << self.to_s
234
- node
235
- end
236
- end
237
-
238
- # Html content within an Atom document.
239
- class Html < Base
240
- attribute :type, :'xml:lang'
241
- # Creates a new Content::Html.
242
- #
243
- # +o+:: An XML::Reader or a HTML string.
244
- #
245
- def initialize(o)
246
- case o
247
- when XML::Reader
248
- super(o.read_string)
249
- parse(o, :once => true)
250
- when String
251
- super(o)
252
- @type = 'html'
253
- else
254
- raise ArgumentError, "Got #{o} which isn't a String or XML::Reader"
255
- end
256
- end
257
-
258
- def to_xml(nodeonly = true, name = 'content', namespace = nil, namespace_map = Atom::Xml::NamespaceMap.new) # :nodoc:
259
- require 'iconv'
260
- # Convert from utf-8 to utf-8 as a way of making sure the content is UTF-8.
261
- #
262
- # This is a pretty crappy way to do it but if we don't check libxml just
263
- # fails silently and outputs the content element without any content. At
264
- # least checking here and raising an exception gives the caller a chance
265
- # to try and recitfy the situation.
266
- #
267
- begin
268
- node = XML::Node.new("#{namespace_map.prefix(Atom::NAMESPACE, name)}")
269
- node << Iconv.iconv('utf-8', 'utf-8', self.to_s)
270
- node['type'] = 'html'
271
- node['xml:lang'] = self.xml_lang if self.xml_lang
272
- node
273
- rescue Iconv::IllegalSequence => e
274
- raise SerializationError, "Content must be converted to UTF-8 before attempting to serialize to XML: #{e.message}."
275
- end
276
- end
277
- end
278
-
279
- # XHTML content within an Atom document.
280
- class Xhtml < Base
281
- XHTML = 'http://www.w3.org/1999/xhtml'
282
- attribute :type, :'xml:lang'
283
-
284
- def initialize(o)
285
- case o
286
- when String
287
- super(o)
288
- @type = "xhtml"
289
- when XML::Reader
290
- super("")
291
- xml = o
292
- parse(xml, :once => true)
293
- starting_depth = xml.depth
294
-
295
- # Get the next element - should be a div according to the atom spec
296
- while xml.read && xml.node_type != XML::Reader::TYPE_ELEMENT; end
297
-
298
- if xml.local_name == 'div' && xml.namespace_uri == XHTML
299
- set_content(xml.read_inner_xml.strip.gsub(/\s+/, ' '))
300
- else
301
- set_content(xml.read_outer_xml)
302
- end
303
-
304
- # get back to the end of the element we were created with
305
- while xml.read == 1 && xml.depth > starting_depth; end
306
- else
307
- raise ArgumentError, "Got #{o} which isn't a String or XML::Reader"
308
- end
309
- end
310
-
311
- def to_xml(nodeonly = true, name = 'content', namespace = nil, namespace_map = Atom::Xml::NamespaceMap.new)
312
- node = XML::Node.new("#{namespace_map.prefix(Atom::NAMESPACE, name)}")
313
- node['type'] = 'xhtml'
314
- node['xml:lang'] = self.xml_lang.to_s
315
-
316
- div = XML::Node.new('div')
317
- div['xmlns'] = XHTML
318
-
319
- p = XML::Parser.string(to_s)
320
- content = p.parse.root.copy(true)
321
- div << content
322
-
323
- node << div
324
- node
325
- end
326
- end
327
- end
328
-
329
- # Represents a Source as defined by the Atom Syndication Format specification.
330
- #
331
- # See also http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.source
332
- class Source
333
- extend Forwardable
334
- def_delegators :@links, :alternate, :self, :alternates, :enclosures
335
- include Xml::Parseable
336
-
337
- element :id
338
- element :updated, :class => Time, :content_only => true
339
- element :title, :subtitle, :class => Content
340
- elements :authors, :contributors, :class => Person
341
- elements :links
342
-
343
- def initialize(o = {})
344
- @authors, @contributors, @links = [], [], Links.new
345
-
346
- case o
347
- when XML::Reader
348
- unless current_node_is?(o, 'source', NAMESPACE)
349
- raise ArgumentError, "Invalid node for atom:source - #{o.name}(#{o.namespace})"
350
- end
351
-
352
- o.read
353
- parse(o)
354
- when Hash
355
- o.each do |k, v|
356
- self.send("#{k.to_s}=", v)
357
- end
358
- else
359
- raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
360
- end
361
-
362
- yield(self) if block_given?
363
- end
364
- end
365
-
366
- # Represents a Feed as defined by the Atom Syndication Format specification.
367
- #
368
- # A feed is the top level element in an atom document. It is a container for feed level
369
- # metadata and for each entry in the feed.
370
- #
371
- # This supports pagination as defined in RFC 5005, see http://www.ietf.org/rfc/rfc5005.txt
372
- #
373
- # == Parsing
374
- #
375
- # A feed can be parsed using the Feed.load_feed method. This method accepts a String containing
376
- # a valid atom document, an IO object, or an URI to a valid atom document. For example:
377
- #
378
- # # Using a File
379
- # feed = Feed.load_feed(File.open("/path/to/myfeed.atom"))
380
- #
381
- # # Using a URL
382
- # feed = Feed.load_feed(URI.parse("http://example.org/afeed.atom"))
383
- #
384
- # == Encoding
385
- #
386
- # A feed can be converted to XML using, the to_xml method that returns a valid atom document in a String.
387
- #
388
- # == Attributes
389
- #
390
- # A feed has the following attributes:
391
- #
392
- # +id+:: A unique id for the feed.
393
- # +updated+:: The Time the feed was updated.
394
- # +title+:: The title of the feed.
395
- # +subtitle+:: The subtitle of the feed.
396
- # +authors+:: An array of Atom::Person objects that are authors of this feed.
397
- # +contributors+:: An array of Atom::Person objects that are contributors to this feed.
398
- # +generator+:: A Atom::Generator.
399
- # +categories+:: A list of Atom:Category objects for the feed.
400
- # +rights+:: A string describing the rights associated with this feed.
401
- # +entries+:: An array of Atom::Entry objects.
402
- # +links+:: An array of Atom:Link objects. (This is actually an Atom::Links array which is an Array with some sugar).
403
- #
404
- # == References
405
- # See also http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.feed
406
- #
407
- class Feed
408
- include Xml::Parseable
409
- include SimpleExtensions
410
- extend Forwardable
411
- def_delegators :@links, :alternate, :self, :via, :first_page, :last_page, :next_page, :prev_page
412
-
413
- loadable!
414
-
415
- namespace Atom::NAMESPACE
416
- element :id, :rights
417
- element :generator, :class => Generator
418
- element :title, :subtitle, :class => Content
419
- element :updated, :class => Time, :content_only => true
420
- elements :links
421
- elements :authors, :contributors, :class => Person
422
- elements :categories
423
- elements :entries
424
-
425
- # Initialize a Feed.
426
- #
427
- # This will also yield itself, so a feed can be constructed like this:
428
- #
429
- # feed = Feed.new do |feed|
430
- # feed.title = "My Cool feed"
431
- # end
432
- #
433
- # +o+:: An XML Reader or a Hash of attributes.
434
- #
435
- def initialize(o = {})
436
- @links, @entries, @authors, @contributors, @categories = Links.new, [], [], [], []
437
-
438
- case o
439
- when XML::Reader
440
- if next_node_is?(o, 'feed', Atom::NAMESPACE)
441
- o.read
442
- parse(o)
443
- else
444
- raise ArgumentError, "XML document was missing atom:feed: #{o.read_outer_xml}"
445
- end
446
- when Hash
447
- o.each do |k, v|
448
- self.send("#{k.to_s}=", v)
449
- end
450
- else
451
- raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
452
- end
453
-
454
- yield(self) if block_given?
455
- end
456
-
457
- # Return true if this is the first feed in a paginated set.
458
- def first?
459
- links.self == links.first_page
460
- end
461
-
462
- # Returns true if this is the last feed in a paginated set.
463
- def last?
464
- links.self == links.last_page
465
- end
466
-
467
- # Reloads the feed by fetching the self uri.
468
- def reload!(opts = {})
469
- if links.self
470
- Feed.load_feed(URI.parse(links.self.href), opts)
471
- end
472
- end
473
-
474
- # Iterates over each entry in the feed.
475
- #
476
- # ==== Options
477
- #
478
- # +paginate+:: If true and the feed supports pagination this will fetch each page of the feed.
479
- # +since+:: If a Time object is provided each_entry will iterate over all entries that were updated since that time.
480
- # +user+:: User name for HTTP Basic Authentication.
481
- # +pass+:: Password for HTTP Basic Authentication.
482
- #
483
- def each_entry(options = {}, &block)
484
- if options[:paginate]
485
- since_reached = false
486
- feed = self
487
- loop do
488
- feed.entries.each do |entry|
489
- if options[:since] && entry.updated && options[:since] > entry.updated
490
- since_reached = true
491
- break
492
- else
493
- block.call(entry)
494
- end
495
- end
496
-
497
- if since_reached || feed.next_page.nil?
498
- break
499
- else feed.next_page
500
- feed = feed.next_page.fetch(options)
501
- end
502
- end
503
- else
504
- self.entries.each(&block)
505
- end
506
- end
507
- end
508
-
509
- # Represents an Entry as defined by the Atom Syndication Format specification.
510
- #
511
- # An Entry represents an individual entry within a Feed.
512
- #
513
- # == Parsing
514
- #
515
- # An Entry can be parsed using the Entry.load_entry method. This method accepts a String containing
516
- # a valid atom entry document, an IO object, or an URI to a valid atom entry document. For example:
517
- #
518
- # # Using a File
519
- # entry = Entry.load_entry(File.open("/path/to/myfeedentry.atom"))
520
- #
521
- # # Using a URL
522
- # Entry = Entry.load_entry(URI.parse("http://example.org/afeedentry.atom"))
523
- #
524
- # The document must contain a stand alone entry element as described in the Atom Syndication Format.
525
- #
526
- # == Encoding
527
- #
528
- # A Entry can be converted to XML using, the to_xml method that returns a valid atom entry document in a String.
529
- #
530
- # == Attributes
531
- #
532
- # An entry has the following attributes:
533
- #
534
- # +id+:: A unique id for the entry.
535
- # +updated+:: The Time the entry was updated.
536
- # +published+:: The Time the entry was published.
537
- # +title+:: The title of the entry.
538
- # +summary+:: A short textual summary of the item.
539
- # +authors+:: An array of Atom::Person objects that are authors of this entry.
540
- # +contributors+:: An array of Atom::Person objects that are contributors to this entry.
541
- # +rights+:: A string describing the rights associated with this entry.
542
- # +links+:: An array of Atom:Link objects. (This is actually an Atom::Links array which is an Array with some sugar).
543
- # +source+:: Metadata of a feed that was the source of this item, for feed aggregators, etc.
544
- # +categories+:: Array of Atom::Categories.
545
- # +content+:: The content of the entry. This will be one of Atom::Content::Text, Atom::Content:Html or Atom::Content::Xhtml.
546
- #
547
- # == References
548
- # See also http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.entry for more detailed
549
- # definitions of the attributes.
550
- #
551
- class Entry
552
- include Xml::Parseable
553
- include SimpleExtensions
554
- extend Forwardable
555
- def_delegators :@links, :alternate, :self, :alternates, :enclosures, :edit_link, :via
556
-
557
- loadable!
558
- namespace Atom::NAMESPACE
559
- element :title, :id, :summary
560
- element :updated, :published, :class => Time, :content_only => true
561
- element :source, :class => Source
562
- elements :links
563
- elements :authors, :contributors, :class => Person
564
- elements :categories, :class => Category
565
- element :content, :class => Content
566
-
567
- # Initialize an Entry.
568
- #
569
- # This will also yield itself, so an Entry can be constructed like this:
570
- #
571
- # entry = Entry.new do |entry|
572
- # entry.title = "My Cool entry"
573
- # end
574
- #
575
- # +o+:: An XML Reader or a Hash of attributes.
576
- #
577
- def initialize(o = {})
578
- @links = Links.new
579
- @authors = []
580
- @contributors = []
581
- @categories = []
582
-
583
- case o
584
- when XML::Reader
585
- if current_node_is?(o, 'entry', Atom::NAMESPACE) || next_node_is?(o, 'entry', Atom::NAMESPACE)
586
- o.read
587
- parse(o)
588
- else
589
- raise ArgumentError, "Entry created with node other than atom:entry: #{o.name}"
590
- end
591
- when Hash
592
- o.each do |k,v|
593
- send("#{k.to_s}=", v)
594
- end
595
- else
596
- raise ArgumentError, "Got #{o.class} but expected a Hash or XML::Reader"
597
- end
598
-
599
- yield(self) if block_given?
600
- end
601
-
602
- # Reload the Entry by fetching the self link.
603
- def reload!(opts = {})
604
- if links.self
605
- Entry.load_entry(URI.parse(links.self.href), opts)
606
- end
607
- end
608
- end
609
-
610
- # Links provides an Array of Link objects belonging to either a Feed or an Entry.
611
- #
612
- # Some additional methods to get specific types of links are provided.
613
- #
614
- # == References
615
- #
616
- # See also http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.link
617
- # for details on link selection and link attributes.
618
- #
619
- class Links < DelegateClass(Array)
620
- include Enumerable
621
-
622
- # Initialize an empty Links array.
623
- def initialize
624
- super([])
625
- end
626
-
627
- # Get the alternate.
628
- #
629
- # Returns the first link with rel == 'alternate' that matches the given type.
630
- def alternate(type = nil)
631
- detect { |link|
632
- (link.rel.nil? || link.rel == Link::Rel::ALTERNATE) && (type.nil? || type == link.type) && (link.hreflang.nil?)
633
- } || detect { |link|
634
- (link.rel.nil? || link.rel == Link::Rel::ALTERNATE) && (type.nil? || type == link.type)
635
- }
636
- end
637
-
638
- # Get all alternates.
639
- def alternates
640
- select { |link| link.rel.nil? || link.rel == Link::Rel::ALTERNATE }
641
- end
642
-
643
- # Gets the self link.
644
- def self
645
- detect { |link| link.rel == Link::Rel::SELF }
646
- end
647
-
648
- # Gets the via link.
649
- def via
650
- detect { |link| link.rel == Link::Rel::VIA }
651
- end
652
-
653
- # Gets all links with rel == 'enclosure'
654
- def enclosures
655
- select { |link| link.rel == Link::Rel::ENCLOSURE }
656
- end
657
-
658
- # Gets the link with rel == 'first'.
659
- #
660
- # This is defined as the first page in a pagination set.
661
- def first_page
662
- detect { |link| link.rel == Link::Rel::FIRST }
663
- end
664
-
665
- # Gets the link with rel == 'last'.
666
- #
667
- # This is defined as the last page in a pagination set.
668
- def last_page
669
- detect { |link| link.rel == Link::Rel::LAST }
670
- end
671
-
672
- # Gets the link with rel == 'next'.
673
- #
674
- # This is defined as the next page in a pagination set.
675
- def next_page
676
- detect { |link| link.rel == Link::Rel::NEXT }
677
- end
678
-
679
- # Gets the link with rel == 'prev'.
680
- #
681
- # This is defined as the previous page in a pagination set.
682
- def prev_page
683
- detect { |link| link.rel == Link::Rel::PREVIOUS }
684
- end
685
-
686
- # Gets the edit link.
687
- #
688
- # This is the link which can be used for posting updates to an item using the Atom Publishing Protocol.
689
- #
690
- def edit_link
691
- detect { |link| link.rel == 'edit' }
692
- end
693
- end
694
-
695
- # Represents a link in an Atom document.
696
- #
697
- # A link defines a reference from an Atom document to a web resource.
698
- #
699
- # == References
700
- # See http://www.atomenabled.org/developers/syndication/atom-format-spec.php#element.link for
701
- # a description of the different types of links.
702
- #
703
- class Link
704
- module Rel # :nodoc:
705
- ALTERNATE = 'alternate'
706
- SELF = 'self'
707
- VIA = 'via'
708
- ENCLOSURE = 'enclosure'
709
- FIRST = 'first'
710
- LAST = 'last'
711
- PREVIOUS = 'prev'
712
- NEXT = 'next'
713
- end
714
-
715
- include Xml::Parseable
716
- attribute :href, :rel, :type, :length, :hreflang, :title
717
-
718
- # Create a link.
719
- #
720
- # +o+:: An XML::Reader containing a link element or a Hash of attributes.
721
- #
722
- def initialize(o)
723
- case o
724
- when XML::Reader
725
- if current_node_is?(o, 'link')
726
- parse(o, :once => true)
727
- else
728
- raise ArgumentError, "Link created with node other than atom:link: #{o.name}"
729
- end
730
- when Hash
731
- [:href, :rel, :type, :length, :hreflang, :title].each do |attr|
732
- self.send("#{attr}=", o[attr])
733
- end
734
- else
735
- raise ArgumentError, "Don't know how to handle #{o}"
736
- end
737
- end
738
-
739
- remove_method :length=
740
- def length=(v)
741
- @length = v.to_i
742
- end
743
-
744
- def to_s
745
- self.href
746
- end
747
-
748
- def ==(o)
749
- [:href, :rel, :type].all? { |k| o.respond_to?(k) && o.send(k) == self.send(k) }
750
- end
751
-
752
- # This will fetch the URL referenced by the link.
753
- #
754
- # If the URL contains a valid feed, a Feed will be returned, otherwise,
755
- # the body of the response will be returned.
756
- #
757
- # TODO: Handle redirects.
758
- #
759
- def fetch(options = {})
760
- begin
761
- Atom::Feed.load_feed(URI.parse(self.href), options)
762
- rescue ArgumentError
763
- Net::HTTP.get_response(URI.parse(self.href)).body
764
- end
765
- end
766
-
767
- def inspect
768
- "<Atom::Link rel:'#{rel}' href:'#{href}' type:'#{type}'>"
769
- end
770
- end
771
- end