LunaRss v1.0 – modificato da Antonio Carpentieri
La modifica precedente è stata Codice LunaRss 0_9, la prossima modifica sarà Codice LunaRss 1_1?
Implementazioni di antonio:
* creata la classe RssStore a cui fa riferimento il test scritto da gabriele, ed ho fatto in modo che passasse il test. (RED)class RssStore def initialize page @page = page end def load_feed_uris uris = Array.new uris << @page uris << @page uris << @page return uris end end
era la soluzione più semplice per far passare il test :P (GREEN), così ho scritto il secondo test:
def test_load_uris rss_store = RssStore.new(TestPages) uris=rss_store.load_feed_uris assert_equal ATOM_GURU, uris[0].to_s assert_equal RSS_ANTONIO, uris[1].to_s assert_equal RSS_COMMENTI_ANTONIO, uris[2].to_s endin questo modo ho evidenziato che la soluzione precedente, ovviamente, non era quella corretta ai nostri fini! (RED) ora posso scrivere qualcosa di più consono:
class RssStore def initialize page @page = page end def load_feed_uris uris = Array.new @page.each do |page| URI.extract(page.body,'http').each do |url| uris << url end end return uris end end
ecco fatto il test passa! (GREEN) Ho quasi la certezza che si possa fare un refactoring per semplificare questo codice… la famosa linea a cui accennava gabriele… ma la lascio a voi! :P
mancano ancora questi punti evidenziati da gabriele:
C’è un altro problema che sorge però: LunaRss gestisce davvero Rss? che Rss? Se la cava anche con Atom? per questo scrivo un test che lascio rosso al prossimo la palla della gestione del formato Atom e Rss 0.92—Antonio Carpentieri
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 class RssStore def initialize page @page = page end def load_feed_uris uris = Array.new @page.each do |page| URI.extract(page.body,'http').each do |url| uris << url end end return uris end end require 'test/unit' require 'stringio' class TestLunaRss < Test::Unit::TestCase TEST_DATA_RSS_20 = <<-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 TEST_DATA_RSS_092 = <<-HTML <rss version="0.92"> <channel> <title>PDI^2</title> <link>http://riffraff.blogsome.com</link> <description>Propulsione d'Improbabilità Infinita</description> <lastBuildDate>Wed, 24 May 2006 08:02:34 +0000</lastBuildDate> <docs>http://backend.userland.com/rss092</docs> <language>en</language> <item> <title>Summer of Code</title> <description> another description too long </description> <link>http://riffraff.blogsome.com/2006/05/24/summer-of-code/</link> </item> </channel> </rss> HTML TEST_DATA_ATOM = <<-HTML <?xml version="1.0" encoding="ISO-8859-1"?> <feed version="0.3" xmlns="http://purl.org/atom/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xml:lang="en"> <title>mozillaZine.org</title> <link rel="alternate" type="text/html" href="http://www.mozillazine.org/"/> <modified>2006-05-24T23:26:54-08:00</modified> <tagline>Your Source for Daily Mozilla News and Advocacy</tagline> <id>tag:mozillazine.org,2004:1</id> <copyright>Copyright (c) 2004, The Mozillazine Organization</copyright> <entry> <title>Opera Watch Soliciting Questions for Blake Ross Interview</title> <link rel="alternate" type="text/html" href="http://www.mozillazine.org/talkback.html?article=8583"/> <modified>2006-05-24T16:17:17-08:00</modified> <created>2006-05-24T16:17:17-08:00</created> <issued>2006-05-24T16:17:17-08:00</issued> <id>tag:mozillazine.org,2004:article8583</id> <author> <name>mozillaZine.org</name> </author> <content type="text/html" mode="escaped" xml:lang="en" xml:base="http://www.mozillazine.org/"> man! it's too long TOO LONG!!! </content> </entry> </feed> HTML def test_parser_rss_20 parser = RssParser.new(StringIO.new(TEST_DATA_RSS_20)) 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 def test_parser_rss_092 parser = RssParser.new(StringIO.new(TEST_DATA_RSS_092)) data = parser.parse assert_equal "PDI^2".to_s, data.channel[0].to_s assert_equal "Summer of Code".to_s, data.titles[0].to_s assert_equal "another description too long".to_s, data.descriptions[0].to_s assert_equal "http://riffraff.blogsome.com/2006/05/24/summer-of-code/".to_s, data.links[0].to_s end def test_parser_atom parser = RssParser.new(StringIO.new(TEST_DATA_ATOM)) data = parser.parse assert_equal "mozillaZine.org".to_s, data.channel[0].to_s assert_equal "Opera Watch Soliciting Questions for Blake Ross Interview".to_s, data.titles[0].to_s assert_equal "man! it's too long TOO LONG!!!".to_s, data.descriptions[0].to_s assert_equal "http://www.mozillazine.org/talkback.html?article=8583".to_s, data.links[0].to_s end end class TestLunaRssStore < Test::Unit::TestCase Page=Struct.new :title, :body ATOM_GURU = 'http://guragedev.blogspot.com/atom.xml' RSS_ANTONIO = 'http://www.antoniocangiano.com/xml/rss20/feed.xml' RSS_COMMENTI_ANTONIO = 'http://www.antoniocangiano.com/xml/rss20/comments/feed.xml' TestPages=[Page.new("Andrea",<<Andrea),Page.new("antonio", <<Antonio)] bla bla feed: #{ATOM_GURU} bla bla Andrea ble bn ble aleklena feed: #{RSS_ANTONIO} feed: #{RSS_COMMENTI_ANTONIO} Antonio def test_load_data rss_store = RssStore.new(TestPages) uris=rss_store.load_feed_uris assert_equal 3, uris.size end def test_load_uris rss_store = RssStore.new(TestPages) uris=rss_store.load_feed_uris assert_equal ATOM_GURU, uris[0].to_s assert_equal RSS_ANTONIO, uris[1].to_s assert_equal RSS_COMMENTI_ANTONIO, uris[2].to_s end end