rubysl-rss 1.0.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.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +8 -0
- data/Gemfile +4 -0
- data/LICENSE +25 -0
- data/README.md +29 -0
- data/Rakefile +1 -0
- data/lib/rss.rb +1 -0
- data/lib/rss/0.9.rb +428 -0
- data/lib/rss/1.0.rb +452 -0
- data/lib/rss/2.0.rb +111 -0
- data/lib/rss/atom.rb +749 -0
- data/lib/rss/content.rb +31 -0
- data/lib/rss/content/1.0.rb +10 -0
- data/lib/rss/content/2.0.rb +12 -0
- data/lib/rss/converter.rb +162 -0
- data/lib/rss/dublincore.rb +161 -0
- data/lib/rss/dublincore/1.0.rb +13 -0
- data/lib/rss/dublincore/2.0.rb +13 -0
- data/lib/rss/dublincore/atom.rb +17 -0
- data/lib/rss/image.rb +193 -0
- data/lib/rss/itunes.rb +410 -0
- data/lib/rss/maker.rb +44 -0
- data/lib/rss/maker/0.9.rb +467 -0
- data/lib/rss/maker/1.0.rb +434 -0
- data/lib/rss/maker/2.0.rb +223 -0
- data/lib/rss/maker/atom.rb +172 -0
- data/lib/rss/maker/base.rb +868 -0
- data/lib/rss/maker/content.rb +21 -0
- data/lib/rss/maker/dublincore.rb +124 -0
- data/lib/rss/maker/entry.rb +163 -0
- data/lib/rss/maker/feed.rb +429 -0
- data/lib/rss/maker/image.rb +111 -0
- data/lib/rss/maker/itunes.rb +242 -0
- data/lib/rss/maker/slash.rb +33 -0
- data/lib/rss/maker/syndication.rb +18 -0
- data/lib/rss/maker/taxonomy.rb +118 -0
- data/lib/rss/maker/trackback.rb +61 -0
- data/lib/rss/parser.rb +541 -0
- data/lib/rss/rexmlparser.rb +54 -0
- data/lib/rss/rss.rb +1312 -0
- data/lib/rss/slash.rb +49 -0
- data/lib/rss/syndication.rb +67 -0
- data/lib/rss/taxonomy.rb +145 -0
- data/lib/rss/trackback.rb +288 -0
- data/lib/rss/utils.rb +111 -0
- data/lib/rss/xml-stylesheet.rb +105 -0
- data/lib/rss/xml.rb +71 -0
- data/lib/rss/xmlparser.rb +93 -0
- data/lib/rss/xmlscanner.rb +121 -0
- data/lib/rubysl/rss.rb +2 -0
- data/lib/rubysl/rss/rss.rb +19 -0
- data/lib/rubysl/rss/version.rb +5 -0
- data/rubysl-rss.gemspec +23 -0
- metadata +153 -0
data/lib/rss/atom.rb
ADDED
@@ -0,0 +1,749 @@
|
|
1
|
+
require 'base64'
|
2
|
+
require 'rss/parser'
|
3
|
+
|
4
|
+
module RSS
|
5
|
+
module Atom
|
6
|
+
URI = "http://www.w3.org/2005/Atom"
|
7
|
+
XHTML_URI = "http://www.w3.org/1999/xhtml"
|
8
|
+
|
9
|
+
module CommonModel
|
10
|
+
NSPOOL = {}
|
11
|
+
ELEMENTS = []
|
12
|
+
|
13
|
+
def self.append_features(klass)
|
14
|
+
super
|
15
|
+
klass.install_must_call_validator("atom", URI)
|
16
|
+
[
|
17
|
+
["lang", :xml],
|
18
|
+
["base", :xml],
|
19
|
+
].each do |name, uri, required|
|
20
|
+
klass.install_get_attribute(name, uri, required, [nil, :inherit])
|
21
|
+
end
|
22
|
+
klass.class_eval do
|
23
|
+
class << self
|
24
|
+
def required_uri
|
25
|
+
URI
|
26
|
+
end
|
27
|
+
|
28
|
+
def need_parent?
|
29
|
+
true
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
module ContentModel
|
37
|
+
module ClassMethods
|
38
|
+
def content_type
|
39
|
+
@content_type ||= nil
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
class << self
|
44
|
+
def append_features(klass)
|
45
|
+
super
|
46
|
+
klass.extend(ClassMethods)
|
47
|
+
klass.content_setup(klass.content_type, klass.tag_name)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def maker_target(target)
|
52
|
+
target
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
def setup_maker_element_writer
|
57
|
+
"#{self.class.name.split(/::/).last.downcase}="
|
58
|
+
end
|
59
|
+
|
60
|
+
def setup_maker_element(target)
|
61
|
+
target.__send__(setup_maker_element_writer, content)
|
62
|
+
super
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
module URIContentModel
|
67
|
+
class << self
|
68
|
+
def append_features(klass)
|
69
|
+
super
|
70
|
+
klass.class_eval do
|
71
|
+
@content_type = [nil, :uri]
|
72
|
+
include(ContentModel)
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
module TextConstruct
|
79
|
+
def self.append_features(klass)
|
80
|
+
super
|
81
|
+
klass.class_eval do
|
82
|
+
[
|
83
|
+
["type", ""],
|
84
|
+
].each do |name, uri, required|
|
85
|
+
install_get_attribute(name, uri, required, :text_type)
|
86
|
+
end
|
87
|
+
|
88
|
+
content_setup
|
89
|
+
add_need_initialize_variable("xhtml")
|
90
|
+
|
91
|
+
class << self
|
92
|
+
def xml_getter
|
93
|
+
"xhtml"
|
94
|
+
end
|
95
|
+
|
96
|
+
def xml_setter
|
97
|
+
"xhtml="
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
attr_writer :xhtml
|
104
|
+
def xhtml
|
105
|
+
return @xhtml if @xhtml.nil?
|
106
|
+
if @xhtml.is_a?(XML::Element) and
|
107
|
+
[@xhtml.name, @xhtml.uri] == ["div", XHTML_URI]
|
108
|
+
return @xhtml
|
109
|
+
end
|
110
|
+
|
111
|
+
children = @xhtml
|
112
|
+
children = [children] unless children.is_a?(Array)
|
113
|
+
XML::Element.new("div", nil, XHTML_URI,
|
114
|
+
{"xmlns" => XHTML_URI}, children)
|
115
|
+
end
|
116
|
+
|
117
|
+
def have_xml_content?
|
118
|
+
@type == "xhtml"
|
119
|
+
end
|
120
|
+
|
121
|
+
def atom_validate(ignore_unknown_element, tags, uri)
|
122
|
+
if have_xml_content?
|
123
|
+
if @xhtml.nil?
|
124
|
+
raise MissingTagError.new("div", tag_name)
|
125
|
+
end
|
126
|
+
unless [@xhtml.name, @xhtml.uri] == ["div", XHTML_URI]
|
127
|
+
raise NotExpectedTagError.new(@xhtml.name, @xhtml.uri, tag_name)
|
128
|
+
end
|
129
|
+
end
|
130
|
+
end
|
131
|
+
|
132
|
+
private
|
133
|
+
def maker_target(target)
|
134
|
+
target.__send__(self.class.name.split(/::/).last.downcase) {|x| x}
|
135
|
+
end
|
136
|
+
|
137
|
+
def setup_maker_attributes(target)
|
138
|
+
target.type = type
|
139
|
+
target.content = content
|
140
|
+
target.xml_content = @xhtml
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
module PersonConstruct
|
145
|
+
def self.append_features(klass)
|
146
|
+
super
|
147
|
+
klass.class_eval do
|
148
|
+
[
|
149
|
+
["name", nil],
|
150
|
+
["uri", "?"],
|
151
|
+
["email", "?"],
|
152
|
+
].each do |tag, occurs|
|
153
|
+
install_have_attribute_element(tag, URI, occurs, nil, :content)
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
def maker_target(target)
|
159
|
+
target.__send__("new_#{self.class.name.split(/::/).last.downcase}")
|
160
|
+
end
|
161
|
+
|
162
|
+
class Name < RSS::Element
|
163
|
+
include CommonModel
|
164
|
+
include ContentModel
|
165
|
+
end
|
166
|
+
|
167
|
+
class Uri < RSS::Element
|
168
|
+
include CommonModel
|
169
|
+
include URIContentModel
|
170
|
+
end
|
171
|
+
|
172
|
+
class Email < RSS::Element
|
173
|
+
include CommonModel
|
174
|
+
include ContentModel
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
module DateConstruct
|
179
|
+
def self.append_features(klass)
|
180
|
+
super
|
181
|
+
klass.class_eval do
|
182
|
+
@content_type = :w3cdtf
|
183
|
+
include(ContentModel)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
def atom_validate(ignore_unknown_element, tags, uri)
|
188
|
+
raise NotAvailableValueError.new(tag_name, "") if content.nil?
|
189
|
+
end
|
190
|
+
end
|
191
|
+
|
192
|
+
module DuplicateLinkChecker
|
193
|
+
def validate_duplicate_links(links)
|
194
|
+
link_infos = {}
|
195
|
+
links.each do |link|
|
196
|
+
rel = link.rel || "alternate"
|
197
|
+
next unless rel == "alternate"
|
198
|
+
key = [link.hreflang, link.type]
|
199
|
+
if link_infos.has_key?(key)
|
200
|
+
raise TooMuchTagError.new("link", tag_name)
|
201
|
+
end
|
202
|
+
link_infos[key] = true
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
207
|
+
class Feed < RSS::Element
|
208
|
+
include RootElementMixin
|
209
|
+
include CommonModel
|
210
|
+
include DuplicateLinkChecker
|
211
|
+
|
212
|
+
install_ns('', URI)
|
213
|
+
|
214
|
+
[
|
215
|
+
["author", "*", :children],
|
216
|
+
["category", "*", :children, "categories"],
|
217
|
+
["contributor", "*", :children],
|
218
|
+
["generator", "?"],
|
219
|
+
["icon", "?", nil, :content],
|
220
|
+
["id", nil, nil, :content],
|
221
|
+
["link", "*", :children],
|
222
|
+
["logo", "?"],
|
223
|
+
["rights", "?"],
|
224
|
+
["subtitle", "?", nil, :content],
|
225
|
+
["title", nil, nil, :content],
|
226
|
+
["updated", nil, nil, :content],
|
227
|
+
["entry", "*", :children, "entries"],
|
228
|
+
].each do |tag, occurs, type, *args|
|
229
|
+
type ||= :child
|
230
|
+
__send__("install_have_#{type}_element",
|
231
|
+
tag, URI, occurs, tag, *args)
|
232
|
+
end
|
233
|
+
|
234
|
+
def initialize(version=nil, encoding=nil, standalone=nil)
|
235
|
+
super("1.0", version, encoding, standalone)
|
236
|
+
@feed_type = "atom"
|
237
|
+
@feed_subtype = "feed"
|
238
|
+
end
|
239
|
+
|
240
|
+
alias_method :items, :entries
|
241
|
+
|
242
|
+
def have_author?
|
243
|
+
authors.any? {|author| !author.to_s.empty?} or
|
244
|
+
entries.any? {|entry| entry.have_author?(false)}
|
245
|
+
end
|
246
|
+
|
247
|
+
private
|
248
|
+
def atom_validate(ignore_unknown_element, tags, uri)
|
249
|
+
unless have_author?
|
250
|
+
raise MissingTagError.new("author", tag_name)
|
251
|
+
end
|
252
|
+
validate_duplicate_links(links)
|
253
|
+
end
|
254
|
+
|
255
|
+
def have_required_elements?
|
256
|
+
super and have_author?
|
257
|
+
end
|
258
|
+
|
259
|
+
def maker_target(maker)
|
260
|
+
maker.channel
|
261
|
+
end
|
262
|
+
|
263
|
+
def setup_maker_element(channel)
|
264
|
+
prev_dc_dates = channel.dc_dates.to_a.dup
|
265
|
+
super
|
266
|
+
channel.about = id.content if id
|
267
|
+
channel.dc_dates.replace(prev_dc_dates)
|
268
|
+
end
|
269
|
+
|
270
|
+
def setup_maker_elements(channel)
|
271
|
+
super
|
272
|
+
items = channel.maker.items
|
273
|
+
entries.each do |entry|
|
274
|
+
entry.setup_maker(items)
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class Author < RSS::Element
|
279
|
+
include CommonModel
|
280
|
+
include PersonConstruct
|
281
|
+
end
|
282
|
+
|
283
|
+
class Category < RSS::Element
|
284
|
+
include CommonModel
|
285
|
+
|
286
|
+
[
|
287
|
+
["term", "", true],
|
288
|
+
["scheme", "", false, [nil, :uri]],
|
289
|
+
["label", ""],
|
290
|
+
].each do |name, uri, required, type|
|
291
|
+
install_get_attribute(name, uri, required, type)
|
292
|
+
end
|
293
|
+
|
294
|
+
private
|
295
|
+
def maker_target(target)
|
296
|
+
target.new_category
|
297
|
+
end
|
298
|
+
end
|
299
|
+
|
300
|
+
class Contributor < RSS::Element
|
301
|
+
include CommonModel
|
302
|
+
include PersonConstruct
|
303
|
+
end
|
304
|
+
|
305
|
+
class Generator < RSS::Element
|
306
|
+
include CommonModel
|
307
|
+
include ContentModel
|
308
|
+
|
309
|
+
[
|
310
|
+
["uri", "", false, [nil, :uri]],
|
311
|
+
["version", ""],
|
312
|
+
].each do |name, uri, required, type|
|
313
|
+
install_get_attribute(name, uri, required, type)
|
314
|
+
end
|
315
|
+
|
316
|
+
private
|
317
|
+
def setup_maker_attributes(target)
|
318
|
+
target.generator do |generator|
|
319
|
+
generator.uri = uri if uri
|
320
|
+
generator.version = version if version
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
class Icon < RSS::Element
|
326
|
+
include CommonModel
|
327
|
+
include URIContentModel
|
328
|
+
end
|
329
|
+
|
330
|
+
class Id < RSS::Element
|
331
|
+
include CommonModel
|
332
|
+
include URIContentModel
|
333
|
+
end
|
334
|
+
|
335
|
+
class Link < RSS::Element
|
336
|
+
include CommonModel
|
337
|
+
|
338
|
+
[
|
339
|
+
["href", "", true, [nil, :uri]],
|
340
|
+
["rel", ""],
|
341
|
+
["type", ""],
|
342
|
+
["hreflang", ""],
|
343
|
+
["title", ""],
|
344
|
+
["length", ""],
|
345
|
+
].each do |name, uri, required, type|
|
346
|
+
install_get_attribute(name, uri, required, type)
|
347
|
+
end
|
348
|
+
|
349
|
+
private
|
350
|
+
def maker_target(target)
|
351
|
+
target.new_link
|
352
|
+
end
|
353
|
+
end
|
354
|
+
|
355
|
+
class Logo < RSS::Element
|
356
|
+
include CommonModel
|
357
|
+
include URIContentModel
|
358
|
+
|
359
|
+
def maker_target(target)
|
360
|
+
target.maker.image
|
361
|
+
end
|
362
|
+
|
363
|
+
private
|
364
|
+
def setup_maker_element_writer
|
365
|
+
"url="
|
366
|
+
end
|
367
|
+
end
|
368
|
+
|
369
|
+
class Rights < RSS::Element
|
370
|
+
include CommonModel
|
371
|
+
include TextConstruct
|
372
|
+
end
|
373
|
+
|
374
|
+
class Subtitle < RSS::Element
|
375
|
+
include CommonModel
|
376
|
+
include TextConstruct
|
377
|
+
end
|
378
|
+
|
379
|
+
class Title < RSS::Element
|
380
|
+
include CommonModel
|
381
|
+
include TextConstruct
|
382
|
+
end
|
383
|
+
|
384
|
+
class Updated < RSS::Element
|
385
|
+
include CommonModel
|
386
|
+
include DateConstruct
|
387
|
+
end
|
388
|
+
|
389
|
+
class Entry < RSS::Element
|
390
|
+
include CommonModel
|
391
|
+
include DuplicateLinkChecker
|
392
|
+
|
393
|
+
[
|
394
|
+
["author", "*", :children],
|
395
|
+
["category", "*", :children, "categories"],
|
396
|
+
["content", "?", :child],
|
397
|
+
["contributor", "*", :children],
|
398
|
+
["id", nil, nil, :content],
|
399
|
+
["link", "*", :children],
|
400
|
+
["published", "?", :child, :content],
|
401
|
+
["rights", "?", :child],
|
402
|
+
["source", "?"],
|
403
|
+
["summary", "?", :child],
|
404
|
+
["title", nil],
|
405
|
+
["updated", nil, :child, :content],
|
406
|
+
].each do |tag, occurs, type, *args|
|
407
|
+
type ||= :attribute
|
408
|
+
__send__("install_have_#{type}_element",
|
409
|
+
tag, URI, occurs, tag, *args)
|
410
|
+
end
|
411
|
+
|
412
|
+
def have_author?(check_parent=true)
|
413
|
+
authors.any? {|author| !author.to_s.empty?} or
|
414
|
+
(check_parent and @parent and @parent.have_author?) or
|
415
|
+
(source and source.have_author?)
|
416
|
+
end
|
417
|
+
|
418
|
+
private
|
419
|
+
def atom_validate(ignore_unknown_element, tags, uri)
|
420
|
+
unless have_author?
|
421
|
+
raise MissingTagError.new("author", tag_name)
|
422
|
+
end
|
423
|
+
validate_duplicate_links(links)
|
424
|
+
end
|
425
|
+
|
426
|
+
def have_required_elements?
|
427
|
+
super and have_author?
|
428
|
+
end
|
429
|
+
|
430
|
+
def maker_target(items)
|
431
|
+
if items.respond_to?("items")
|
432
|
+
# For backward compatibility
|
433
|
+
items = items.items
|
434
|
+
end
|
435
|
+
items.new_item
|
436
|
+
end
|
437
|
+
|
438
|
+
Author = Feed::Author
|
439
|
+
Category = Feed::Category
|
440
|
+
|
441
|
+
class Content < RSS::Element
|
442
|
+
include CommonModel
|
443
|
+
|
444
|
+
class << self
|
445
|
+
def xml_setter
|
446
|
+
"xml="
|
447
|
+
end
|
448
|
+
|
449
|
+
def xml_getter
|
450
|
+
"xml"
|
451
|
+
end
|
452
|
+
end
|
453
|
+
|
454
|
+
[
|
455
|
+
["type", ""],
|
456
|
+
["src", "", false, [nil, :uri]],
|
457
|
+
].each do |name, uri, required, type|
|
458
|
+
install_get_attribute(name, uri, required, type)
|
459
|
+
end
|
460
|
+
|
461
|
+
content_setup
|
462
|
+
add_need_initialize_variable("xml")
|
463
|
+
|
464
|
+
attr_writer :xml
|
465
|
+
def have_xml_content?
|
466
|
+
inline_xhtml? or inline_other_xml?
|
467
|
+
end
|
468
|
+
|
469
|
+
def xml
|
470
|
+
return @xml unless inline_xhtml?
|
471
|
+
return @xml if @xml.nil?
|
472
|
+
if @xml.is_a?(XML::Element) and
|
473
|
+
[@xml.name, @xml.uri] == ["div", XHTML_URI]
|
474
|
+
return @xml
|
475
|
+
end
|
476
|
+
|
477
|
+
children = @xml
|
478
|
+
children = [children] unless children.is_a?(Array)
|
479
|
+
XML::Element.new("div", nil, XHTML_URI,
|
480
|
+
{"xmlns" => XHTML_URI}, children)
|
481
|
+
end
|
482
|
+
|
483
|
+
def xhtml
|
484
|
+
if inline_xhtml?
|
485
|
+
xml
|
486
|
+
else
|
487
|
+
nil
|
488
|
+
end
|
489
|
+
end
|
490
|
+
|
491
|
+
def atom_validate(ignore_unknown_element, tags, uri)
|
492
|
+
if out_of_line?
|
493
|
+
raise MissingAttributeError.new(tag_name, "type") if @type.nil?
|
494
|
+
unless (content.nil? or content.empty?)
|
495
|
+
raise NotAvailableValueError.new(tag_name, content)
|
496
|
+
end
|
497
|
+
elsif inline_xhtml?
|
498
|
+
if @xml.nil?
|
499
|
+
raise MissingTagError.new("div", tag_name)
|
500
|
+
end
|
501
|
+
unless @xml.name == "div" and @xml.uri == XHTML_URI
|
502
|
+
raise NotExpectedTagError.new(@xml.name, @xml.uri, tag_name)
|
503
|
+
end
|
504
|
+
end
|
505
|
+
end
|
506
|
+
|
507
|
+
def inline_text?
|
508
|
+
!out_of_line? and [nil, "text", "html"].include?(@type)
|
509
|
+
end
|
510
|
+
|
511
|
+
def inline_html?
|
512
|
+
return false if out_of_line?
|
513
|
+
@type == "html" or mime_split == ["text", "html"]
|
514
|
+
end
|
515
|
+
|
516
|
+
def inline_xhtml?
|
517
|
+
!out_of_line? and @type == "xhtml"
|
518
|
+
end
|
519
|
+
|
520
|
+
def inline_other?
|
521
|
+
return false if out_of_line?
|
522
|
+
media_type, subtype = mime_split
|
523
|
+
return false if media_type.nil? or subtype.nil?
|
524
|
+
true
|
525
|
+
end
|
526
|
+
|
527
|
+
def inline_other_text?
|
528
|
+
return false unless inline_other?
|
529
|
+
return false if inline_other_xml?
|
530
|
+
|
531
|
+
media_type, subtype = mime_split
|
532
|
+
return true if "text" == media_type.downcase
|
533
|
+
false
|
534
|
+
end
|
535
|
+
|
536
|
+
def inline_other_xml?
|
537
|
+
return false unless inline_other?
|
538
|
+
|
539
|
+
media_type, subtype = mime_split
|
540
|
+
normalized_mime_type = "#{media_type}/#{subtype}".downcase
|
541
|
+
if /(?:\+xml|^xml)$/ =~ subtype or
|
542
|
+
%w(text/xml-external-parsed-entity
|
543
|
+
application/xml-external-parsed-entity
|
544
|
+
application/xml-dtd).find {|x| x == normalized_mime_type}
|
545
|
+
return true
|
546
|
+
end
|
547
|
+
false
|
548
|
+
end
|
549
|
+
|
550
|
+
def inline_other_base64?
|
551
|
+
inline_other? and !inline_other_text? and !inline_other_xml?
|
552
|
+
end
|
553
|
+
|
554
|
+
def out_of_line?
|
555
|
+
not @src.nil?
|
556
|
+
end
|
557
|
+
|
558
|
+
def mime_split
|
559
|
+
media_type = subtype = nil
|
560
|
+
if /\A\s*([a-z]+)\/([a-z\+]+)\s*(?:;.*)?\z/i =~ @type.to_s
|
561
|
+
media_type = $1.downcase
|
562
|
+
subtype = $2.downcase
|
563
|
+
end
|
564
|
+
[media_type, subtype]
|
565
|
+
end
|
566
|
+
|
567
|
+
def need_base64_encode?
|
568
|
+
inline_other_base64?
|
569
|
+
end
|
570
|
+
|
571
|
+
private
|
572
|
+
def empty_content?
|
573
|
+
out_of_line? or super
|
574
|
+
end
|
575
|
+
end
|
576
|
+
|
577
|
+
Contributor = Feed::Contributor
|
578
|
+
Id = Feed::Id
|
579
|
+
Link = Feed::Link
|
580
|
+
|
581
|
+
class Published < RSS::Element
|
582
|
+
include CommonModel
|
583
|
+
include DateConstruct
|
584
|
+
end
|
585
|
+
|
586
|
+
Rights = Feed::Rights
|
587
|
+
|
588
|
+
class Source < RSS::Element
|
589
|
+
include CommonModel
|
590
|
+
|
591
|
+
[
|
592
|
+
["author", "*", :children],
|
593
|
+
["category", "*", :children, "categories"],
|
594
|
+
["contributor", "*", :children],
|
595
|
+
["generator", "?"],
|
596
|
+
["icon", "?"],
|
597
|
+
["id", "?", nil, :content],
|
598
|
+
["link", "*", :children],
|
599
|
+
["logo", "?"],
|
600
|
+
["rights", "?"],
|
601
|
+
["subtitle", "?"],
|
602
|
+
["title", "?"],
|
603
|
+
["updated", "?", nil, :content],
|
604
|
+
].each do |tag, occurs, type, *args|
|
605
|
+
type ||= :attribute
|
606
|
+
__send__("install_have_#{type}_element",
|
607
|
+
tag, URI, occurs, tag, *args)
|
608
|
+
end
|
609
|
+
|
610
|
+
def have_author?
|
611
|
+
!author.to_s.empty?
|
612
|
+
end
|
613
|
+
|
614
|
+
Author = Feed::Author
|
615
|
+
Category = Feed::Category
|
616
|
+
Contributor = Feed::Contributor
|
617
|
+
Generator = Feed::Generator
|
618
|
+
Icon = Feed::Icon
|
619
|
+
Id = Feed::Id
|
620
|
+
Link = Feed::Link
|
621
|
+
Logo = Feed::Logo
|
622
|
+
Rights = Feed::Rights
|
623
|
+
Subtitle = Feed::Subtitle
|
624
|
+
Title = Feed::Title
|
625
|
+
Updated = Feed::Updated
|
626
|
+
end
|
627
|
+
|
628
|
+
class Summary < RSS::Element
|
629
|
+
include CommonModel
|
630
|
+
include TextConstruct
|
631
|
+
end
|
632
|
+
|
633
|
+
Title = Feed::Title
|
634
|
+
Updated = Feed::Updated
|
635
|
+
end
|
636
|
+
end
|
637
|
+
|
638
|
+
class Entry < RSS::Element
|
639
|
+
include RootElementMixin
|
640
|
+
include CommonModel
|
641
|
+
include DuplicateLinkChecker
|
642
|
+
|
643
|
+
[
|
644
|
+
["author", "*", :children],
|
645
|
+
["category", "*", :children, "categories"],
|
646
|
+
["content", "?"],
|
647
|
+
["contributor", "*", :children],
|
648
|
+
["id", nil, nil, :content],
|
649
|
+
["link", "*", :children],
|
650
|
+
["published", "?", :child, :content],
|
651
|
+
["rights", "?"],
|
652
|
+
["source", "?"],
|
653
|
+
["summary", "?"],
|
654
|
+
["title", nil],
|
655
|
+
["updated", nil, nil, :content],
|
656
|
+
].each do |tag, occurs, type, *args|
|
657
|
+
type ||= :attribute
|
658
|
+
__send__("install_have_#{type}_element",
|
659
|
+
tag, URI, occurs, tag, *args)
|
660
|
+
end
|
661
|
+
|
662
|
+
def initialize(version=nil, encoding=nil, standalone=nil)
|
663
|
+
super("1.0", version, encoding, standalone)
|
664
|
+
@feed_type = "atom"
|
665
|
+
@feed_subtype = "entry"
|
666
|
+
end
|
667
|
+
|
668
|
+
def items
|
669
|
+
[self]
|
670
|
+
end
|
671
|
+
|
672
|
+
def setup_maker(maker)
|
673
|
+
maker = maker.maker if maker.respond_to?("maker")
|
674
|
+
super(maker)
|
675
|
+
end
|
676
|
+
|
677
|
+
def have_author?
|
678
|
+
authors.any? {|author| !author.to_s.empty?} or
|
679
|
+
(source and source.have_author?)
|
680
|
+
end
|
681
|
+
|
682
|
+
private
|
683
|
+
def atom_validate(ignore_unknown_element, tags, uri)
|
684
|
+
unless have_author?
|
685
|
+
raise MissingTagError.new("author", tag_name)
|
686
|
+
end
|
687
|
+
validate_duplicate_links(links)
|
688
|
+
end
|
689
|
+
|
690
|
+
def have_required_elements?
|
691
|
+
super and have_author?
|
692
|
+
end
|
693
|
+
|
694
|
+
def maker_target(maker)
|
695
|
+
maker.items.new_item
|
696
|
+
end
|
697
|
+
|
698
|
+
Author = Feed::Entry::Author
|
699
|
+
Category = Feed::Entry::Category
|
700
|
+
Content = Feed::Entry::Content
|
701
|
+
Contributor = Feed::Entry::Contributor
|
702
|
+
Id = Feed::Entry::Id
|
703
|
+
Link = Feed::Entry::Link
|
704
|
+
Published = Feed::Entry::Published
|
705
|
+
Rights = Feed::Entry::Rights
|
706
|
+
Source = Feed::Entry::Source
|
707
|
+
Summary = Feed::Entry::Summary
|
708
|
+
Title = Feed::Entry::Title
|
709
|
+
Updated = Feed::Entry::Updated
|
710
|
+
end
|
711
|
+
end
|
712
|
+
|
713
|
+
Atom::CommonModel::ELEMENTS.each do |name|
|
714
|
+
BaseListener.install_get_text_element(Atom::URI, name, "#{name}=")
|
715
|
+
end
|
716
|
+
|
717
|
+
module ListenerMixin
|
718
|
+
private
|
719
|
+
def initial_start_feed(tag_name, prefix, attrs, ns)
|
720
|
+
check_ns(tag_name, prefix, ns, Atom::URI)
|
721
|
+
|
722
|
+
@rss = Atom::Feed.new(@version, @encoding, @standalone)
|
723
|
+
@rss.do_validate = @do_validate
|
724
|
+
@rss.xml_stylesheets = @xml_stylesheets
|
725
|
+
@rss.lang = attrs["xml:lang"]
|
726
|
+
@rss.base = attrs["xml:base"]
|
727
|
+
@last_element = @rss
|
728
|
+
pr = Proc.new do |text, tags|
|
729
|
+
@rss.validate_for_stream(tags) if @do_validate
|
730
|
+
end
|
731
|
+
@proc_stack.push(pr)
|
732
|
+
end
|
733
|
+
|
734
|
+
def initial_start_entry(tag_name, prefix, attrs, ns)
|
735
|
+
check_ns(tag_name, prefix, ns, Atom::URI)
|
736
|
+
|
737
|
+
@rss = Atom::Entry.new(@version, @encoding, @standalone)
|
738
|
+
@rss.do_validate = @do_validate
|
739
|
+
@rss.xml_stylesheets = @xml_stylesheets
|
740
|
+
@rss.lang = attrs["xml:lang"]
|
741
|
+
@rss.base = attrs["xml:base"]
|
742
|
+
@last_element = @rss
|
743
|
+
pr = Proc.new do |text, tags|
|
744
|
+
@rss.validate_for_stream(tags) if @do_validate
|
745
|
+
end
|
746
|
+
@proc_stack.push(pr)
|
747
|
+
end
|
748
|
+
end
|
749
|
+
end
|