Note:
Testo rimosso dalla rev 7 e
Testo aggiunto nella rev8
h1.LunaRss
LunaRss v0.9 – modificato da Gabriele Renzi
La modifica precedente è stata Codice LunaRss 0_8, la prossima modifica sarà Codice LunaRss 1_0 congratulazioni :)
Piccolo refactoring di gabriele renzi:
- usiamo
open-uri.rb, semplifica tutto - usiamo costanti per le
Regexp, sono più veloci, più corte e più appropriate (le espressioni regolari sono costanti) Get_feedsdiventaget_feedsesegui_parsediventaparsee conseguentemente il metodoparseviene rinominato inextract, in quanto è quello che in effetti fa.- non ho capito perché venisse usato il blocco con
scanquindi l’ho levato, e i test passano ancora, quindi o non serviva o abbiamo bisogno di più test - fatto sparire di nuovo
align, reso privato inRssMaker
Ho aggiunto un secondo piccolissimo TestCase, in quanto io vorrei integrare questo codice nel wiki.. il problema da risolvere è di facile soluzione, estrarre dalle pagine i metadati relativi ai feed, dovrebbe farsi con una istruzione. C’è un altro problema che sorge però: LunaRss gestisce davvero Rss? che Rss? Se la cava anche con Atom?
E poi, e per questo non c’è anora il TestCase, come facciamo ad aggiornare il feed globale inserendo solo i nuovi item? Sinceramente non ho idea di come fare ma forse si potrebbe usare la data di creazione. Si assuma di poter usare un backend ActiveRecord nel quale infilare gli oggetti che volete, con le api base:aFoo.save->trueo erroreFoo.find_by_attributo(attr)->aFooonil
require 'net/http' require 'uri' class Feed def initialize(url, opts = { }) @uri = URI.parse(url) end def read @uri.read end end FeedData = Struct.new( :channel, :titles, :descriptions, :links ) class RssParser CHANNEL_TITLE=%r{<channel(?!s).*?>.*?(?:<title>(?:<!\[CDATA\[)*(.*?)(?:\]\]>)*</title>.*?)?</channel>}m ITEM_TITLE=%r{<item(?!s).*?>.*?(?:<title>(?:<!\[CDATA\[)*(.*?)(?:\]\]>)*</title>.*?)?</item>}m ITEM_LINKS=%r{<item(?!s).*?>.*?(?:<link>(?:<!\[CDATA\[)*(.*?)(?:\]\]>)*</link>.*?)?</item>}m ITEM_DESCRIPTION=%r{<item(?!s).*?>.*?(?:<description>(?:<!\[CDATA\[)*(.*?)(?:\]\]>)*</description>.*?)?</item>}m def initialize(feed) @feed = feed end def parse FeedData.new( extract( CHANNEL_TITLE ), extract( ITEM_TITLE ), extract( ITEM_DESCRIPTION ), extract( ITEM_LINKS ) ) end private def rss_data @data ||= @feed.read end def extract pattern rss_data.scan pattern end end class RssMaker def align text text.gsub(/^\s*\./m, '') end private :align def header align <<-HTML .Content-type: text/html\r\n\r\n .<html> .<body> HTML end def footer align <<-HTML .</body> .</html> HTML end def channel name align <<-HTML .<h3>#{name}</h3> HTML end def entry titolo, descrizione, link align <<-HTML .<strong> . <a href="#{link}"> #{titolo} </a> .</strong><br/> . .<font size="-1"> #{descrizione} </font> .<p/> HTML end end ############################## # Configurations feeds=[ 'http://www.repubblica.it/rss/scienza_e_tecnologia/rss2.0.xml', 'http://programmazione.it/rss.xml', 'http://www.hwupgrade.it/rss_news.xml', 'http://www.hwupgrade.it/rss_articoli.xml', 'http://www.beppegrillo.it/index.xml' ] NEED_PROXY = false #switch this if you have a proxy proxy_url = "http://10.0.0.2:8080" #put here your proxy, if you have one ############################## class LunaRss def get_feeds rss_make = RssMaker.new puts rss_make.header feeds.each do |feed| parser = RssParser.new feed data = parser.parse puts rss_make.channel( data.channel ) 0.upto data.titles.length do|i| puts rss_make.entry( data.titles[i], data.descriptions[i], data.links[i] ) end end puts rss_make.footer end end require 'test/unit' require 'stringio' class TestLunaRss < Test::Unit::TestCase TEST_DATA = <<-HTML <?xml version="1.0"?> <rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"> <channel> <title>Ruby Italia</title> <link>http://ruby-it.org/</link> <description>Tracking all versions for Ruby Italia</description> <language>it-it</language> <ttl>40</ttl> <item> <title>Chiaroscuro</title> <description>description too long</description> <pubDate>Mon, 08 May 2006 13:33:54 +0200</pubDate> <guid>http://ruby-it.org/pages/Chiaroscuro#936</guid> <link>http://ruby-it.org/pages/Chiaroscuro#936</link> <dc:creator>Chiaroscuro</dc:creator> </item> </channel> </rss> HTML def test_parser parser = RssParser.new(StringIO.new(TEST_DATA)) data = parser.parse assert_equal "Ruby Italia".to_s, data.channel[0].to_s assert_equal "Chiaroscuro".to_s, data.titles[0].to_s assert_equal "description too long".to_s, data.descriptions[0].to_s assert_equal "http://ruby-it.org/pages/Chiaroscuro#936".to_s, data.links[0].to_s end end class TestLunaRssStore < Test::Unit::TestCase Page=Struct.new :title, :body TestPages=[Page.new("Andrea",<<Andrea),Page.new("antonio", <<Antonio)] bla bla feed: http://guragedev.blogspot.com/atom.xml bla bla Andrea ble bn ble aleklena feed: http://www.antoniocangiano.com/xml/rss20/feed.xml feed: http://www.antoniocangiano.com/xml/rss20/comments/feed.xml Antonio def test_load_data RssStore.new(TestPages) uris=RssStore.load_feed_uris assert_equal 3, uris.size end end