feedtools 0.2.6 → 0.2.7
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.
- data/CHANGELOG +9 -2
- data/lib/feed_tools.rb +489 -62
- data/rakefile +1 -1
- metadata +2 -2
data/CHANGELOG
CHANGED
@@ -1,6 +1,13 @@
|
|
1
|
+
== FeedTools 0.2.7
|
2
|
+
* added support for Atom 1.0 output
|
3
|
+
* improved support for Atom parsing and handling
|
4
|
+
* added no content string option to keep the feed validator happy
|
5
|
+
* greatly improved handling of timestamps and feed item sorting
|
6
|
+
* added aliases for the Atom 1.0 elements that were renamed
|
7
|
+
* feed merging is now threaded
|
1
8
|
== FeedTools 0.2.6
|
2
|
-
*
|
3
|
-
*
|
9
|
+
* added support for merging feeds
|
10
|
+
* vastly improved handling of feed creation
|
4
11
|
== FeedTools 0.2.5
|
5
12
|
* fixed multiple rows being created in the cache after a 301 redirection
|
6
13
|
* fixed broken table creation for postgresql and sqlite
|
data/lib/feed_tools.rb
CHANGED
@@ -25,7 +25,7 @@ FEED_TOOLS_ENV = ENV['FEED_TOOLS_ENV'] ||
|
|
25
25
|
ENV['RAILS_ENV'] ||
|
26
26
|
'production' # :nodoc:
|
27
27
|
|
28
|
-
FEED_TOOLS_VERSION = "0.2.
|
28
|
+
FEED_TOOLS_VERSION = "0.2.7"
|
29
29
|
|
30
30
|
$:.unshift(File.dirname(__FILE__))
|
31
31
|
$:.unshift(File.dirname(__FILE__) + "/../../activerecord/lib")
|
@@ -305,6 +305,7 @@ module FeedTools
|
|
305
305
|
@feed_cache = DatabaseFeedCache
|
306
306
|
@user_agent = "FeedTools/#{FEED_TOOLS_VERSION} " +
|
307
307
|
"+http://www.sporkmonger.com/projects/feedtools/"
|
308
|
+
@no_content_string = "[no description]"
|
308
309
|
|
309
310
|
# Returns the current caching mechanism.
|
310
311
|
def FeedTools.feed_cache
|
@@ -377,6 +378,17 @@ module FeedTools
|
|
377
378
|
def FeedTools.user_agent=(new_user_agent)
|
378
379
|
@user_agent = new_user_agent
|
379
380
|
end
|
381
|
+
|
382
|
+
# Returns the currently used no content string.
|
383
|
+
def FeedTools.no_content_string
|
384
|
+
return @no_content_string
|
385
|
+
end
|
386
|
+
|
387
|
+
# Sets the no content string to use when a feed is missing a content element.
|
388
|
+
# Used only for xml output.
|
389
|
+
def FeedTools.no_content_string=(new_no_content_string)
|
390
|
+
@no_content_string = new_no_content_string
|
391
|
+
end
|
380
392
|
|
381
393
|
# Returns true if the html tidy module can be used.
|
382
394
|
#
|
@@ -548,11 +560,31 @@ module FeedTools
|
|
548
560
|
end
|
549
561
|
end
|
550
562
|
|
551
|
-
#
|
552
|
-
def FeedTools.
|
563
|
+
# Converts a url into a tag uri
|
564
|
+
def FeedTools.build_tag_uri(url, date)
|
565
|
+
unless url.kind_of? String
|
566
|
+
raise ArgumentError, "Expected String, got #{url.class.name}"
|
567
|
+
end
|
568
|
+
unless date.kind_of? Time
|
569
|
+
raise ArgumentError, "Expected Time, got #{date.class.name}"
|
570
|
+
end
|
571
|
+
tag_uri = normalize_url(url)
|
572
|
+
host = URI.parse(tag_uri).host
|
573
|
+
tag_uri.gsub!(/^(http|ftp|file):\/*/, "")
|
574
|
+
tag_uri.gsub!(/#/, "/")
|
575
|
+
tag_uri = "tag:#{host},#{date.strftime('%Y-%m-%d')}:" +
|
576
|
+
"#{tag_uri[(tag_uri.index(host) + host.size)..-1]}"
|
577
|
+
return tag_uri
|
578
|
+
end
|
579
|
+
|
580
|
+
# Returns true if the parameter appears to be a valid uri
|
581
|
+
def FeedTools.is_uri?(url)
|
553
582
|
return false if url.nil?
|
554
583
|
begin
|
555
584
|
uri = URI.parse(url)
|
585
|
+
if uri.scheme.nil? || uri.scheme == ""
|
586
|
+
return false
|
587
|
+
end
|
556
588
|
rescue URI::InvalidURIError
|
557
589
|
return false
|
558
590
|
end
|
@@ -699,8 +731,18 @@ module FeedTools
|
|
699
731
|
def FeedTools.build_merged_feed(url_array)
|
700
732
|
return nil if url_array.nil?
|
701
733
|
merged_feed = Feed.new
|
734
|
+
retrieved_feeds = []
|
735
|
+
feed_threads = []
|
702
736
|
url_array.each do |feed_url|
|
703
|
-
|
737
|
+
feed_threads << Thread.new do
|
738
|
+
feed = Feed.open(feed_url)
|
739
|
+
retrieved_feeds << feed
|
740
|
+
end
|
741
|
+
end
|
742
|
+
feed_threads.each do |thread|
|
743
|
+
thread.join
|
744
|
+
end
|
745
|
+
retrieved_feeds.each do |feed|
|
704
746
|
merged_feed.entries.concat(
|
705
747
|
feed.entries.collect do |entry|
|
706
748
|
entry.title = "#{feed.title}: #{entry.title}"
|
@@ -1508,7 +1550,7 @@ module FeedTools
|
|
1508
1550
|
end
|
1509
1551
|
end
|
1510
1552
|
if @link == "" || @link.nil?
|
1511
|
-
if FeedTools.
|
1553
|
+
if FeedTools.is_uri? self.guid
|
1512
1554
|
@link = self.guid
|
1513
1555
|
end
|
1514
1556
|
end
|
@@ -1562,7 +1604,7 @@ module FeedTools
|
|
1562
1604
|
if @icon == ""
|
1563
1605
|
@icon = FeedTools.unescape_entities(
|
1564
1606
|
XPath.first(icon_node, "text()").to_s)
|
1565
|
-
unless FeedTools.
|
1607
|
+
unless FeedTools.is_uri? @icon
|
1566
1608
|
@icon = ""
|
1567
1609
|
end
|
1568
1610
|
end
|
@@ -1581,19 +1623,20 @@ module FeedTools
|
|
1581
1623
|
def author
|
1582
1624
|
if @author.nil?
|
1583
1625
|
@author = FeedTools::Feed::Author.new
|
1584
|
-
|
1585
|
-
|
1586
|
-
|
1587
|
-
|
1588
|
-
|
1589
|
-
|
1590
|
-
|
1591
|
-
|
1592
|
-
|
1593
|
-
|
1594
|
-
|
1595
|
-
|
1596
|
-
|
1626
|
+
unless channel_node.nil?
|
1627
|
+
author_node = XPath.first(channel_node, "author")
|
1628
|
+
if author_node.nil?
|
1629
|
+
author_node = XPath.first(channel_node, "managingEditor")
|
1630
|
+
end
|
1631
|
+
if author_node.nil?
|
1632
|
+
author_node = XPath.first(channel_node, "dc:author")
|
1633
|
+
end
|
1634
|
+
if author_node.nil?
|
1635
|
+
author_node = XPath.first(channel_node, "dc:creator")
|
1636
|
+
end
|
1637
|
+
if author_node.nil?
|
1638
|
+
author_node = XPath.first(channel_node, "atom:author")
|
1639
|
+
end
|
1597
1640
|
end
|
1598
1641
|
unless author_node.nil?
|
1599
1642
|
@author.raw = FeedTools.unescape_entities(
|
@@ -1771,6 +1814,149 @@ module FeedTools
|
|
1771
1814
|
return @itunes_author
|
1772
1815
|
end
|
1773
1816
|
|
1817
|
+
# Returns the feed item time
|
1818
|
+
def time
|
1819
|
+
if @time.nil?
|
1820
|
+
unless channel_node.nil?
|
1821
|
+
time_string = XPath.first(channel_node, "pubDate/text()").to_s
|
1822
|
+
if time_string == ""
|
1823
|
+
time_string = XPath.first(channel_node, "dc:date/text()").to_s
|
1824
|
+
end
|
1825
|
+
if time_string == ""
|
1826
|
+
time_string = XPath.first(channel_node, "issued/text()").to_s
|
1827
|
+
end
|
1828
|
+
if time_string == ""
|
1829
|
+
time_string = XPath.first(channel_node, "updated/text()").to_s
|
1830
|
+
end
|
1831
|
+
if time_string == ""
|
1832
|
+
time_string = XPath.first(channel_node, "time/text()").to_s
|
1833
|
+
end
|
1834
|
+
end
|
1835
|
+
begin
|
1836
|
+
if time_string != nil && time_string != ""
|
1837
|
+
@time = Time.parse(time_string) rescue self.succ_time
|
1838
|
+
elsif time_string == nil
|
1839
|
+
@time = self.succ_time
|
1840
|
+
end
|
1841
|
+
if @time == nil
|
1842
|
+
@time = Time.now
|
1843
|
+
end
|
1844
|
+
rescue
|
1845
|
+
@time = Time.now
|
1846
|
+
end
|
1847
|
+
end
|
1848
|
+
return @time
|
1849
|
+
end
|
1850
|
+
|
1851
|
+
# Sets the feed item time
|
1852
|
+
def time=(new_time)
|
1853
|
+
@time = new_time
|
1854
|
+
end
|
1855
|
+
|
1856
|
+
# Returns 1 second after the previous item's time.
|
1857
|
+
def succ_time #:nodoc:
|
1858
|
+
begin
|
1859
|
+
if feed.nil?
|
1860
|
+
return nil
|
1861
|
+
end
|
1862
|
+
feed.items
|
1863
|
+
unsorted_items = feed.instance_variable_get("@items")
|
1864
|
+
item_index = unsorted_items.index(self)
|
1865
|
+
if item_index.nil?
|
1866
|
+
return nil
|
1867
|
+
end
|
1868
|
+
if item_index <= 0
|
1869
|
+
return Time.now
|
1870
|
+
end
|
1871
|
+
previous_item = unsorted_items[item_index - 1]
|
1872
|
+
return previous_item.time.succ
|
1873
|
+
rescue
|
1874
|
+
return nil
|
1875
|
+
end
|
1876
|
+
end
|
1877
|
+
private :succ_time
|
1878
|
+
|
1879
|
+
# Returns the feed item updated time
|
1880
|
+
def updated
|
1881
|
+
if @updated.nil?
|
1882
|
+
unless channel_node.nil?
|
1883
|
+
updated_string = XPath.first(channel_node, "updated/text()").to_s
|
1884
|
+
if updated_string == ""
|
1885
|
+
updated_string = XPath.first(channel_node, "modified/text()").to_s
|
1886
|
+
end
|
1887
|
+
end
|
1888
|
+
if updated_string != nil && updated_string != ""
|
1889
|
+
@updated = Time.parse(updated_string) rescue nil
|
1890
|
+
else
|
1891
|
+
@updated = nil
|
1892
|
+
end
|
1893
|
+
end
|
1894
|
+
return @updated
|
1895
|
+
end
|
1896
|
+
|
1897
|
+
# Sets the feed item updated time
|
1898
|
+
def updated=(new_updated)
|
1899
|
+
@updated = new_updated
|
1900
|
+
end
|
1901
|
+
|
1902
|
+
# Returns the feed item issued time
|
1903
|
+
def issued
|
1904
|
+
if @issued.nil?
|
1905
|
+
unless channel_node.nil?
|
1906
|
+
issued_string = XPath.first(channel_node, "issued/text()").to_s
|
1907
|
+
if issued_string == ""
|
1908
|
+
issued_string = XPath.first(channel_node, "pubDate/text()").to_s
|
1909
|
+
end
|
1910
|
+
if issued_string == ""
|
1911
|
+
issued_string = XPath.first(channel_node, "dc:date/text()").to_s
|
1912
|
+
end
|
1913
|
+
if issued_string == ""
|
1914
|
+
issued_string = XPath.first(channel_node, "published/text()").to_s
|
1915
|
+
end
|
1916
|
+
end
|
1917
|
+
if issued_string != nil && issued_string != ""
|
1918
|
+
@issued = Time.parse(issued_string) rescue nil
|
1919
|
+
else
|
1920
|
+
@issued = nil
|
1921
|
+
end
|
1922
|
+
end
|
1923
|
+
return @issued
|
1924
|
+
end
|
1925
|
+
|
1926
|
+
# Sets the feed item issued time
|
1927
|
+
def issued=(new_issued)
|
1928
|
+
@issued = new_issued
|
1929
|
+
end
|
1930
|
+
|
1931
|
+
# Returns the feed item published time
|
1932
|
+
def published
|
1933
|
+
if @published.nil?
|
1934
|
+
unless channel_node.nil?
|
1935
|
+
published_string = XPath.first(channel_node, "published/text()").to_s
|
1936
|
+
if published_string == ""
|
1937
|
+
published_string = XPath.first(channel_node, "pubDate/text()").to_s
|
1938
|
+
end
|
1939
|
+
if published_string == ""
|
1940
|
+
published_string = XPath.first(channel_node, "dc:date/text()").to_s
|
1941
|
+
end
|
1942
|
+
if published_string == ""
|
1943
|
+
published_string = XPath.first(channel_node, "issued/text()").to_s
|
1944
|
+
end
|
1945
|
+
end
|
1946
|
+
if published_string != nil && published_string != ""
|
1947
|
+
@published = Time.parse(published_string) rescue nil
|
1948
|
+
else
|
1949
|
+
@published = nil
|
1950
|
+
end
|
1951
|
+
end
|
1952
|
+
return @published
|
1953
|
+
end
|
1954
|
+
|
1955
|
+
# Sets the feed item published time
|
1956
|
+
def published=(new_published)
|
1957
|
+
@published = new_published
|
1958
|
+
end
|
1959
|
+
|
1774
1960
|
# Returns a list of the feed's categories
|
1775
1961
|
def categories
|
1776
1962
|
if @categories.nil?
|
@@ -1889,15 +2075,20 @@ module FeedTools
|
|
1889
2075
|
# Returns the feed's copyright information
|
1890
2076
|
def copyright
|
1891
2077
|
if @copyright.nil?
|
1892
|
-
|
1893
|
-
|
1894
|
-
@copyright
|
1895
|
-
|
1896
|
-
|
1897
|
-
@copyright
|
2078
|
+
unless channel_node.nil?
|
2079
|
+
@copyright = XPath.first(channel_node, "copyright/text()").to_s
|
2080
|
+
if @copyright == ""
|
2081
|
+
@copyright = XPath.first(channel_node, "rights/text()").to_s
|
2082
|
+
end
|
2083
|
+
if @copyright == ""
|
2084
|
+
@copyright = XPath.first(channel_node, "dc:rights/text()").to_s
|
2085
|
+
end
|
2086
|
+
if @copyright == ""
|
2087
|
+
@copyright = XPath.first(channel_node, "copyrights/text()").to_s
|
2088
|
+
end
|
2089
|
+
@copyright = FeedTools.sanitize_html(@copyright, :strip)
|
2090
|
+
@copyright = nil if @copyright == ""
|
1898
2091
|
end
|
1899
|
-
@copyright = FeedTools.sanitize_html(@copyright, :strip)
|
1900
|
-
@copyright = nil if @copyright == ""
|
1901
2092
|
end
|
1902
2093
|
return @copyright
|
1903
2094
|
end
|
@@ -2335,7 +2526,7 @@ module FeedTools
|
|
2335
2526
|
end
|
2336
2527
|
end
|
2337
2528
|
end
|
2338
|
-
elsif feed_type == "atom"
|
2529
|
+
elsif feed_type == "atom" && version == 0.3
|
2339
2530
|
# normal atom format
|
2340
2531
|
return xml_builder.feed("xmlns" => "http://purl.org/atom/ns#",
|
2341
2532
|
"version" => version,
|
@@ -2345,6 +2536,19 @@ module FeedTools
|
|
2345
2536
|
"mode" => "escaped",
|
2346
2537
|
"type" => "text/html")
|
2347
2538
|
end
|
2539
|
+
xml_builder.author do
|
2540
|
+
unless self.author.nil? || self.author.name.nil?
|
2541
|
+
xml_builder.name(self.author.name)
|
2542
|
+
else
|
2543
|
+
xml_builder.name("n/a")
|
2544
|
+
end
|
2545
|
+
unless self.author.nil? || self.author.email.nil?
|
2546
|
+
xml_builder.email(self.author.email)
|
2547
|
+
end
|
2548
|
+
unless self.author.nil? || self.author.url.nil?
|
2549
|
+
xml_builder.url(self.author.url)
|
2550
|
+
end
|
2551
|
+
end
|
2348
2552
|
unless link.nil? || link == ""
|
2349
2553
|
xml_builder.link("href" => link,
|
2350
2554
|
"rel" => "alternate",
|
@@ -2365,6 +2569,74 @@ module FeedTools
|
|
2365
2569
|
end
|
2366
2570
|
end
|
2367
2571
|
end
|
2572
|
+
elsif feed_type == "atom" && version == 1.0
|
2573
|
+
# normal atom format
|
2574
|
+
return xml_builder.feed("xmlns" => "http://www.w3.org/2005/Atom",
|
2575
|
+
"xml:lang" => language) do
|
2576
|
+
unless title.nil? || title == ""
|
2577
|
+
xml_builder.title(title,
|
2578
|
+
"type" => "html")
|
2579
|
+
end
|
2580
|
+
xml_builder.author do
|
2581
|
+
unless self.author.nil? || self.author.name.nil?
|
2582
|
+
xml_builder.name(self.author.name)
|
2583
|
+
else
|
2584
|
+
xml_builder.name("n/a")
|
2585
|
+
end
|
2586
|
+
unless self.author.nil? || self.author.email.nil?
|
2587
|
+
xml_builder.email(self.author.email)
|
2588
|
+
end
|
2589
|
+
unless self.author.nil? || self.author.url.nil?
|
2590
|
+
xml_builder.url(self.author.url)
|
2591
|
+
end
|
2592
|
+
end
|
2593
|
+
unless self.url.nil? || self.url == ""
|
2594
|
+
xml_builder.link("href" => self.url,
|
2595
|
+
"rel" => "self",
|
2596
|
+
"type" => "application/atom+xml")
|
2597
|
+
end
|
2598
|
+
unless self.link.nil? || self.link == ""
|
2599
|
+
xml_builder.link("href" => self.link,
|
2600
|
+
"rel" => "alternate",
|
2601
|
+
"type" => "text/html",
|
2602
|
+
"title" => self.title)
|
2603
|
+
end
|
2604
|
+
unless description.nil? || description == ""
|
2605
|
+
xml_builder.subtitle(description,
|
2606
|
+
"type" => "html")
|
2607
|
+
else
|
2608
|
+
xml_builder.subtitle(FeedTools.no_content_string,
|
2609
|
+
"type" => "html")
|
2610
|
+
end
|
2611
|
+
if self.updated != nil
|
2612
|
+
xml_builder.updated(self.updated.iso8601)
|
2613
|
+
elsif self.time != nil
|
2614
|
+
# Not technically correct, but a heck of a lot better
|
2615
|
+
# than the Time.now fall-back.
|
2616
|
+
xml_builder.updated(self.time.iso8601)
|
2617
|
+
else
|
2618
|
+
xml_builder.updated(Time.now.iso8601)
|
2619
|
+
end
|
2620
|
+
unless self.published.nil?
|
2621
|
+
xml_builder.published(self.published.iso8601)
|
2622
|
+
end
|
2623
|
+
xml_builder.generator("FeedTools - " +
|
2624
|
+
"http://www.sporkmonger.com/projects/feedtools")
|
2625
|
+
unless self.id.nil?
|
2626
|
+
unless FeedTools.is_uri? self.id
|
2627
|
+
raise "The unique id must be a URI."
|
2628
|
+
end
|
2629
|
+
xml_builder.id(self.id)
|
2630
|
+
else
|
2631
|
+
raise "Cannot build feed, missing feed unique id."
|
2632
|
+
end
|
2633
|
+
build_xml_hook(feed_type, version, xml_builder)
|
2634
|
+
unless items.nil?
|
2635
|
+
for item in items
|
2636
|
+
item.build_xml(feed_type, version, xml_builder)
|
2637
|
+
end
|
2638
|
+
end
|
2639
|
+
end
|
2368
2640
|
end
|
2369
2641
|
end
|
2370
2642
|
|
@@ -2678,6 +2950,15 @@ module FeedTools
|
|
2678
2950
|
unless root_node.nil?
|
2679
2951
|
repair_entities = false
|
2680
2952
|
description_node = XPath.first(root_node, "description")
|
2953
|
+
if description_node.nil?
|
2954
|
+
description_node = XPath.first(root_node, "content:encoded")
|
2955
|
+
end
|
2956
|
+
if description_node.nil?
|
2957
|
+
description_node = XPath.first(root_node, "content")
|
2958
|
+
end
|
2959
|
+
if description_node.nil?
|
2960
|
+
description_node = XPath.first(root_node, "fullitem")
|
2961
|
+
end
|
2681
2962
|
if description_node.nil?
|
2682
2963
|
description_node = XPath.first(root_node, "xhtml:body")
|
2683
2964
|
end
|
@@ -2699,15 +2980,6 @@ module FeedTools
|
|
2699
2980
|
if description_node.nil?
|
2700
2981
|
description_node = XPath.first(root_node, "ABSTRACT")
|
2701
2982
|
end
|
2702
|
-
if description_node.nil?
|
2703
|
-
description_node = XPath.first(root_node, "content:encoded")
|
2704
|
-
end
|
2705
|
-
if description_node.nil?
|
2706
|
-
description_node = XPath.first(root_node, "content")
|
2707
|
-
end
|
2708
|
-
if description_node.nil?
|
2709
|
-
description_node = XPath.first(root_node, "fullitem")
|
2710
|
-
end
|
2711
2983
|
if description_node.nil?
|
2712
2984
|
description_node = XPath.first(root_node, "info")
|
2713
2985
|
@bozo = true unless description_node.nil?
|
@@ -2853,7 +3125,7 @@ module FeedTools
|
|
2853
3125
|
end
|
2854
3126
|
end
|
2855
3127
|
if @link == "" || @link.nil?
|
2856
|
-
if FeedTools.
|
3128
|
+
if FeedTools.is_uri? self.guid
|
2857
3129
|
@link = self.guid
|
2858
3130
|
end
|
2859
3131
|
end
|
@@ -3016,9 +3288,20 @@ module FeedTools
|
|
3016
3288
|
# Returns the feed item's copyright information
|
3017
3289
|
def copyright
|
3018
3290
|
if @copyright.nil?
|
3019
|
-
|
3020
|
-
|
3021
|
-
|
3291
|
+
unless root_node.nil?
|
3292
|
+
@copyright = XPath.first(root_node, "dc:rights/text()").to_s
|
3293
|
+
if @copyright == ""
|
3294
|
+
@copyright = XPath.first(root_node, "rights/text()").to_s
|
3295
|
+
end
|
3296
|
+
if @copyright == ""
|
3297
|
+
@copyright = XPath.first(root_node, "copyright/text()").to_s
|
3298
|
+
end
|
3299
|
+
if @copyright == ""
|
3300
|
+
@copyright = XPath.first(root_node, "copyrights/text()").to_s
|
3301
|
+
end
|
3302
|
+
@copyright = FeedTools.sanitize_html(@copyright, :strip)
|
3303
|
+
@copyright = nil if @copyright == ""
|
3304
|
+
end
|
3022
3305
|
end
|
3023
3306
|
return @copyright
|
3024
3307
|
end
|
@@ -3400,19 +3683,20 @@ module FeedTools
|
|
3400
3683
|
def author
|
3401
3684
|
if @author.nil?
|
3402
3685
|
@author = FeedTools::Feed::Author.new
|
3403
|
-
|
3404
|
-
|
3405
|
-
|
3406
|
-
|
3407
|
-
|
3408
|
-
|
3409
|
-
|
3410
|
-
|
3411
|
-
|
3412
|
-
|
3413
|
-
|
3414
|
-
|
3415
|
-
|
3686
|
+
unless root_node.nil?
|
3687
|
+
author_node = XPath.first(root_node, "author")
|
3688
|
+
if author_node.nil?
|
3689
|
+
author_node = XPath.first(root_node, "managingEditor")
|
3690
|
+
end
|
3691
|
+
if author_node.nil?
|
3692
|
+
author_node = XPath.first(root_node, "dc:author")
|
3693
|
+
end
|
3694
|
+
if author_node.nil?
|
3695
|
+
author_node = XPath.first(root_node, "dc:creator")
|
3696
|
+
end
|
3697
|
+
if author_node.nil?
|
3698
|
+
author_node = XPath.first(root_node, "atom:author")
|
3699
|
+
end
|
3416
3700
|
end
|
3417
3701
|
unless author_node.nil?
|
3418
3702
|
@author.raw = FeedTools.unescape_entities(
|
@@ -3621,14 +3905,22 @@ module FeedTools
|
|
3621
3905
|
# Returns the feed item time
|
3622
3906
|
def time
|
3623
3907
|
if @time.nil?
|
3624
|
-
|
3625
|
-
|
3626
|
-
time_string
|
3627
|
-
|
3628
|
-
|
3629
|
-
time_string
|
3908
|
+
unless root_node.nil?
|
3909
|
+
time_string = XPath.first(root_node, "pubDate/text()").to_s
|
3910
|
+
if time_string == ""
|
3911
|
+
time_string = XPath.first(root_node, "dc:date/text()").to_s
|
3912
|
+
end
|
3913
|
+
if time_string == ""
|
3914
|
+
time_string = XPath.first(root_node, "issued/text()").to_s
|
3915
|
+
end
|
3916
|
+
if time_string == ""
|
3917
|
+
time_string = XPath.first(root_node, "updated/text()").to_s
|
3918
|
+
end
|
3919
|
+
if time_string == ""
|
3920
|
+
time_string = XPath.first(root_node, "time/text()").to_s
|
3921
|
+
end
|
3630
3922
|
end
|
3631
|
-
if time_string != ""
|
3923
|
+
if time_string != nil && time_string != ""
|
3632
3924
|
@time = Time.parse(time_string) rescue Time.now
|
3633
3925
|
elsif time_string == nil
|
3634
3926
|
@time = Time.now
|
@@ -3641,7 +3933,59 @@ module FeedTools
|
|
3641
3933
|
def time=(new_time)
|
3642
3934
|
@time = new_time
|
3643
3935
|
end
|
3936
|
+
|
3937
|
+
# Returns the feed item updated time
|
3938
|
+
def updated
|
3939
|
+
if @updated.nil?
|
3940
|
+
unless root_node.nil?
|
3941
|
+
updated_string = XPath.first(root_node, "updated/text()").to_s
|
3942
|
+
if updated_string == ""
|
3943
|
+
updated_string = XPath.first(root_node, "modified/text()").to_s
|
3944
|
+
end
|
3945
|
+
end
|
3946
|
+
if updated_string != nil && updated_string != ""
|
3947
|
+
@updated = Time.parse(updated_string) rescue nil
|
3948
|
+
else
|
3949
|
+
@updated = nil
|
3950
|
+
end
|
3951
|
+
end
|
3952
|
+
return @updated
|
3953
|
+
end
|
3954
|
+
|
3955
|
+
# Sets the feed item updated time
|
3956
|
+
def updated=(new_updated)
|
3957
|
+
@updated = new_updated
|
3958
|
+
end
|
3959
|
+
|
3960
|
+
# Returns the feed item issued time
|
3961
|
+
def issued
|
3962
|
+
if @issued.nil?
|
3963
|
+
unless root_node.nil?
|
3964
|
+
issued_string = XPath.first(root_node, "issued/text()").to_s
|
3965
|
+
if issued_string == ""
|
3966
|
+
issued_string = XPath.first(root_node, "published/text()").to_s
|
3967
|
+
end
|
3968
|
+
if issued_string == ""
|
3969
|
+
issued_string = XPath.first(root_node, "pubDate/text()").to_s
|
3970
|
+
end
|
3971
|
+
if issued_string == ""
|
3972
|
+
issued_string = XPath.first(root_node, "dc:date/text()").to_s
|
3973
|
+
end
|
3974
|
+
end
|
3975
|
+
if issued_string != nil && issued_string != ""
|
3976
|
+
@issued = Time.parse(issued_string) rescue nil
|
3977
|
+
else
|
3978
|
+
@issued = nil
|
3979
|
+
end
|
3980
|
+
end
|
3981
|
+
return @issued
|
3982
|
+
end
|
3644
3983
|
|
3984
|
+
# Sets the feed item issued time
|
3985
|
+
def issued=(new_issued)
|
3986
|
+
@issued = new_issued
|
3987
|
+
end
|
3988
|
+
|
3645
3989
|
# Returns the url for posting comments
|
3646
3990
|
def comments
|
3647
3991
|
if @comments.nil?
|
@@ -3837,7 +4181,7 @@ module FeedTools
|
|
3837
4181
|
end
|
3838
4182
|
build_xml_hook(feed_type, version, xml_builder)
|
3839
4183
|
end
|
3840
|
-
elsif feed_type == "atom"
|
4184
|
+
elsif feed_type == "atom" && version == 0.3
|
3841
4185
|
# normal atom format
|
3842
4186
|
return xml_builder.entry("xmlns" => "http://purl.org/atom/ns#") do
|
3843
4187
|
unless title.nil? || title == ""
|
@@ -3845,6 +4189,19 @@ module FeedTools
|
|
3845
4189
|
"mode" => "escaped",
|
3846
4190
|
"type" => "text/html")
|
3847
4191
|
end
|
4192
|
+
xml_builder.author do
|
4193
|
+
unless self.author.nil? || self.author.name.nil?
|
4194
|
+
xml_builder.name(self.author.name)
|
4195
|
+
else
|
4196
|
+
xml_builder.name("n/a")
|
4197
|
+
end
|
4198
|
+
unless self.author.nil? || self.author.email.nil?
|
4199
|
+
xml_builder.email(self.author.email)
|
4200
|
+
end
|
4201
|
+
unless self.author.nil? || self.author.url.nil?
|
4202
|
+
xml_builder.url(self.author.url)
|
4203
|
+
end
|
4204
|
+
end
|
3848
4205
|
unless link.nil? || link == ""
|
3849
4206
|
xml_builder.link("href" => link,
|
3850
4207
|
"rel" => "alternate",
|
@@ -3866,6 +4223,74 @@ module FeedTools
|
|
3866
4223
|
end
|
3867
4224
|
build_xml_hook(feed_type, version, xml_builder)
|
3868
4225
|
end
|
4226
|
+
elsif feed_type == "atom" && version == 1.0
|
4227
|
+
# normal atom format
|
4228
|
+
return xml_builder.entry("xmlns" => "http://www.w3.org/2005/Atom") do
|
4229
|
+
unless title.nil? || title == ""
|
4230
|
+
xml_builder.title(title,
|
4231
|
+
"type" => "html")
|
4232
|
+
end
|
4233
|
+
xml_builder.author do
|
4234
|
+
unless self.author.nil? || self.author.name.nil?
|
4235
|
+
xml_builder.name(self.author.name)
|
4236
|
+
else
|
4237
|
+
xml_builder.name("n/a")
|
4238
|
+
end
|
4239
|
+
unless self.author.nil? || self.author.email.nil?
|
4240
|
+
xml_builder.email(self.author.email)
|
4241
|
+
end
|
4242
|
+
unless self.author.nil? || self.author.url.nil?
|
4243
|
+
xml_builder.url(self.author.url)
|
4244
|
+
end
|
4245
|
+
end
|
4246
|
+
unless link.nil? || link == ""
|
4247
|
+
xml_builder.link("href" => link,
|
4248
|
+
"rel" => "alternate",
|
4249
|
+
"type" => "text/html",
|
4250
|
+
"title" => title)
|
4251
|
+
end
|
4252
|
+
unless description.nil? || description == ""
|
4253
|
+
xml_builder.content(description,
|
4254
|
+
"type" => "html")
|
4255
|
+
else
|
4256
|
+
xml_builder.content(FeedTools.no_content_string,
|
4257
|
+
"type" => "html")
|
4258
|
+
end
|
4259
|
+
if self.updated != nil
|
4260
|
+
xml_builder.updated(self.updated.iso8601)
|
4261
|
+
elsif self.time != nil
|
4262
|
+
# Not technically correct, but a heck of a lot better
|
4263
|
+
# than the Time.now fall-back.
|
4264
|
+
xml_builder.updated(self.time.iso8601)
|
4265
|
+
else
|
4266
|
+
xml_builder.updated(Time.now.iso8601)
|
4267
|
+
end
|
4268
|
+
unless self.published.nil?
|
4269
|
+
xml_builder.published(self.published.iso8601)
|
4270
|
+
end
|
4271
|
+
if self.id != nil
|
4272
|
+
unless FeedTools.is_uri? self.id
|
4273
|
+
if self.time != nil && self.link != nil
|
4274
|
+
xml_builder.id(FeedTools.build_tag_uri(self.link, self.time))
|
4275
|
+
else
|
4276
|
+
raise "The unique id must be a URI. " +
|
4277
|
+
"(Attempted to generate id, but failed.)"
|
4278
|
+
end
|
4279
|
+
else
|
4280
|
+
xml_builder.id(self.id)
|
4281
|
+
end
|
4282
|
+
elsif self.time != nil && self.link != nil
|
4283
|
+
xml_builder.id(FeedTools.build_tag_uri(self.link, self.time))
|
4284
|
+
else
|
4285
|
+
raise "Cannot build feed, missing feed unique id."
|
4286
|
+
end
|
4287
|
+
unless self.tags.nil? || self.tags.size == 0
|
4288
|
+
for tag in self.tags
|
4289
|
+
xml_builder.category("term" => tag)
|
4290
|
+
end
|
4291
|
+
end
|
4292
|
+
build_xml_hook(feed_type, version, xml_builder)
|
4293
|
+
end
|
3869
4294
|
end
|
3870
4295
|
end
|
3871
4296
|
|
@@ -3881,6 +4306,8 @@ module FeedTools
|
|
3881
4306
|
alias_method :content=, :description=
|
3882
4307
|
alias_method :guid, :id
|
3883
4308
|
alias_method :guid=, :id=
|
4309
|
+
alias_method :published, :issued
|
4310
|
+
alias_method :published=, :issued=
|
3884
4311
|
end
|
3885
4312
|
end
|
3886
4313
|
|
data/rakefile
CHANGED
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.11
|
|
3
3
|
specification_version: 1
|
4
4
|
name: feedtools
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.2.
|
7
|
-
date: 2005-09-
|
6
|
+
version: 0.2.7
|
7
|
+
date: 2005-09-02 00:00:00 -04:00
|
8
8
|
summary: "Parsing, generation, and caching system for xml news feeds."
|
9
9
|
require_paths:
|
10
10
|
- lib
|