Never been to DZone Snippets before?

Snippets is a public source code repository. Easily build up your personal collection of code snippets, categorize them with tags / keywords, and share them with the world

« Newer Snippets
Older Snippets »
Showing 1-10 of 39 total  RSS 

Exemple de flux RSS chez goodreads

Si on le parse en pur RSS, on n'obtient, grosso mode, que le tag description à la fin, qui est franchement moche, alors que goodreads ajoute plein de trucs vraiment utiles.

   1  
   2  <?xml version="1.0"?>
   3  <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
   4  	<channel>
   5  		<title>Nicolas's bookshelf: read </title>
   6  		<copyright><![CDATA[Copyright (C) 2008 Goodreads Inc. All rights reserved.]]>
   7  		</copyright>
   8  		<link><![CDATA[http://www.goodreads.com/review/list_rss/1156136?key=6e3f5ede71d718b58a0a4f72a9a630bb850e1a3b&shelf=]]></link>
   9      <atom:link href="http://www.goodreads.com/review/list_rss/1156136?key=6e3f5ede71d718b58a0a4f72a9a630bb850e1a3b&amp;shelf=" rel="self" type="application/rss+xml" />
  10  		<description><![CDATA[Nicolas's bookshelf: read ]]></description>
  11  		<language>en-US</language>
  12  		<lastBuildDate>Tue, 07 Oct 2008 02:37:44 -0700</lastBuildDate>
  13  		<ttl>60</ttl>
  14  		<image>
  15  			<title>Nicolas's bookshelf: read </title>
  16  			<link><![CDATA[http://www.goodreads.com/review/list_rss/1156136?key=6e3f5ede71d718b58a0a4f72a9a630bb850e1a3b&shelf=]]></link>
  17  			<width>144</width>
  18  			<height>41</height>
  19  			<url>http://www.goodreads.com/images/layout/gr_logo_144.jpg</url>
  20  		</image>
  21  	<item>
  22  		<guid>http://www.goodreads.com/review/show/26192996?utm_medium=api&amp;utm_source=rss</guid>
  23  		<pubDate>Tue, 07 Oct 2008 02:37:44 -0700</pubDate>
  24  		<title>
  25  			<![CDATA[Le Samouraï virtuel]]>
  26  		</title>
  27  		<link>
  28  		  http://www.goodreads.com/review/show/26192996?utm_medium=api&amp;utm_source=rss
  29  		</link>
  30  		<book_image_url>
  31  		  <![CDATA[http://photo.goodreads.com/books/1170278409s/45281.jpg]]>
  32  		</book_image_url>
  33  		<book_small_image_url>
  34  		  <![CDATA[http://photo.goodreads.com/books/1170278409s/45281.jpg]]>
  35  		</book_small_image_url>
  36  		<book_medium_image_url>
  37  		  <![CDATA[http://photo.goodreads.com/books/1170278409m/45281.jpg]]>
  38  		</book_medium_image_url>
  39  		<book_large_image_url>
  40  		  <![CDATA[http://photo.goodreads.com/books/1170278409l/45281.jpg]]>
  41  		</book_large_image_url>
  42  		<author_name><![CDATA[Neal Stephenson]]></author_name>
  43  		<book_id><![CDATA[45281]]></book_id>
  44  		<isbn><![CDATA[2253072214]]></isbn>
  45  		<user_name><![CDATA[Nicolas]]></user_name>
  46  		<user_rating><![CDATA[5]]></user_rating>
  47  		<user_read_at><![CDATA[07/00]]></user_read_at>
  48  		<user_date_added><![CDATA[Tue, 07 Oct 2008 02:37:44 -0700]]></user_date_added>
  49  		<user_date_created><![CDATA[Thu, 03 Jul 2008 04:59:31 -0700]]></user_date_created>
  50  		<user_shelves><![CDATA[combat, cyberpunk, top, voyage]]></user_shelves>
  51  		<user_review><![CDATA[Commencons tout de suite avec le cyberpunk. Alors que je lisais cette oeuvre une polémique assez vive agitait le forum à propos de la définition du cyberpunk. Or il se trouve que justement, le samouraï virtuel illustre parfaitement ce qu’est le cyberpunk : sur un terrain connu, l’état démocratique américain a abandonné ses prérogatives à des sociétés privées, dont la MAFIA qui ne se définit plus comme telle puisque la notion même d’état a complètement explosée. C’est là qu’on trouve la plus vive illustration du cyberpunk selon moi : non pas dans la présence d’implants, ou d’une matrice dont la réalité future n’est finalement qu’une extrapolation logique de l’existence d’Internet, mais bien dans l’explosion de la notion d’état pour un retour à un tribalisme, mais modifié par la transnationnalité qu’impose logiquement la mondialisation des échanges de culture.
  52  <br/>
  53  <br/>C’est à mon avis ça la vraie base de toutes les oeuvres cyberpunk : une négation de l’état, mais pas des structures sous-jacentes : la justice, le commerce sont toujours présents dans ces oeuvres, mais ne sont plus organisées sur un territoire physique continu, mais plutôt sur un territoire composé d’une mosaïque d’implantation, ce qui me fait soudainement penser aux mosaiques d’implantations de colons juifs en Palestine. Ne seraient-elles pas finalement une préfiguration d’un monde cyberpunk (ouah le troll !) ?
  54  <br/>
  55  <br/>Passons maintenant à l’autre point fondateur de ce roman : les Nams-Shubs, les En et la multiplication des langues. Là, je n’ai toujours que des questions. En effet, s’il est vrai que le langage conditionne non seulement notre façon de penser, mais également notre façon de penser, n’est-il pas effectivement envisageable de supposer, comme le fait l’auteur, qu’il existe une langue qui serait finalement l’équivalent de l’assembleur informatique : un langage dont le niveau est tel que son utilisation donne une puissance incroyable à celui qui le connait, mais qui n’existe qu’en tant que couche de base dont toues les autres langages se servent.
  56  <br/>
  57  <br/>Je n’ai qu’un très léger vernis philosophique, mais ne peut-on penser que ce langage serait le meilleur moyen de passer de notre monde à celui des idées, finalement un moyen de transformer au mieux les idées en réalités ? Sur ces quelques idées, j’aimerais bien l’avis éclairé des NooGurus, et de tous les autres penseurs du forum…]]></user_review>
  58  
  59  		<average_rating><![CDATA[6.00]]></average_rating>
  60  		<book_published><![CDATA[1992]]></book_published>
  61  		<description>
  62  			<![CDATA[
  63  	    <a href="http://www.goodreads.com/book/show/45281.Le_Samoura_virtuel?utm_medium=api&amp;utm_source=rss"><img alt="Le Samouraï virtuel" src="http://photo.goodreads.com/books/1170278409s/45281.jpg" /></a><br/>
  64  			
  65  			author: Neal Stephenson<br/>
  66  			name: Nicolas<br/>
  67  			average rating: 6.00<br/>
  68  			book published: 1992<br/>
  69  			rating: 5<br/>
  70  			read at: 07/00<br/>
  71  			date added: 10/07/08<br/>
  72  			shelves: combat, cyberpunk, top, voyage<br/>
  73  			review: <br/>Commencons tout de suite avec le cyberpunk. Alors que je lisais cette oeuvre une polémique assez vive agitait le forum à propos de la définition du cyberpunk. Or il se trouve que justement, le samouraï virtuel illustre parfaitement ce qu’est le cyberpunk : sur un terrain connu, l’état démocratique américain a abandonné ses prérogatives à des sociétés privées, dont la MAFIA qui ne se définit plus comme telle puisque la notion même d’état a complètement explosée. C’est là qu’on trouve la plus vive illustration du cyberpunk selon moi : non pas dans la présence d’implants, ou d’une matrice dont la réalité future n’est finalement qu’une extrapolation logique de l’existence d’Internet, mais bien dans l’explosion de la notion d’état pour un retour à un tribalisme, mais modifié par la transnationnalité qu’impose logiquement la mondialisation des échanges de culture.
  74  <br/>
  75  <br/>C’est à mon avis ça la vraie base de toutes les oeuvres cyberpunk : une négation de l’état, mais pas des structures sous-jacentes : la justice, le commerce sont toujours présents dans ces oeuvres, mais ne sont plus organisées sur un territoire physique continu, mais plutôt sur un territoire composé d’une mosaïque d’implantation, ce qui me fait soudainement penser aux mosaiques d’implantations de colons juifs en Palestine. Ne seraient-elles pas finalement une préfiguration d’un monde cyberpunk (ouah le troll !) ?
  76  <br/>
  77  <br/>Passons maintenant à l’autre point fondateur de ce roman : les Nams-Shubs, les En et la multiplication des langues. Là, je n’ai toujours que des questions. En effet, s’il est vrai que le langage conditionne non seulement notre façon de penser, mais également notre façon de penser, n’est-il pas effectivement envisageable de supposer, comme le fait l’auteur, qu’il existe une langue qui serait finalement l’équivalent de l’assembleur informatique : un langage dont le niveau est tel que son utilisation donne une puissance incroyable à celui qui le connait, mais qui n’existe qu’en tant que couche de base dont toues les autres langages se servent.
  78  <br/>
  79  <br/>Je n’ai qu’un très léger vernis philosophique, mais ne peut-on penser que ce langage serait le meilleur moyen de passer de notre monde à celui des idées, finalement un moyen de transformer au mieux les idées en réalités ? Sur ces quelques idées, j’aimerais bien l’avis éclairé des NooGurus, et de tous les autres penseurs du forum…<br/>
  80  			]]>
  81  		</description>
  82  	</item>
  83  </channel>
  84  </rss>

Supporting authenticated web feeds in rss2imbot

   1  
   2    def fetch_title(url)
   3      buffer = open(url, "UserAgent" => "Ruby-RSS2IMbot").read
   4      get_title(buffer)
   5    end
   6  
   7    def fetch_secure_title(url, username, password)
   8      client = HTTPClient.new
   9      client.set_auth(url, username, password)
  10      buffer = client.get(url)
  11      get_title(buffer.content)
  12    end


here is the modification to function 'action_msg'
   1  
   2      case action
   3        when 'add'
   4          remainder = $3
   5          rss_feed = remainder[/^(https?sec:\/\/.[^\s]+)/,1]
   6          unless rss_feed.nil?
   7            after_url = $'
   8  
   9            # check if there are authentation details to be included
  10            username = after_url[/-u\s+(\w+)\s+-p\s+(\w+)/,1]
  11            puts 'username : ' + username
  12            if username.nil?
  13              title = fetch_title(rss_feed)
  14            else
  15              password = $2
  16              puts 'password : ' + password
  17              title = fetch_secure_title(rss_feed, username, password) 
  18            end
  19  
  20            add_feed(title,rss_feed, username, password)
  21          else
  22             messenger.deliver(buddy,  "That web feed isn't valid'")
  23          end

   1  
   2    def fetch_feed(url5)
   3  
   4      buffer7 = open(url5, "UserAgent" => "Ruby-RSS2IMbot").read
   5      get_item(buffer7)
   6    end
   7  
   8    def fetch_secure_feed(url5, username, password)
   9  
  10      client = HTTPClient.new
  11      client.set_auth(url5, username, password)
  12      buffer7 = client.get(url5)
  13       
  14      get_item(buffer7.content)
  15    end
  16  
  17  
  18  
  19    # displays only the latest unread new message from each feed
  20    def check_feed(messenger)
  21      result = false
  22      puts 'check feed'
  23      buddy = @user
  24  
  25      url = URL_BASE + "select/rss2imbot.db/t#{@table}/column=*"
  26      buffer = open(url, "UserAgent" => "Ruby-RSS2IMbot").read
  27  
  28      doc = ''
  29      doc = Document.new(buffer)
  30      rows = ''
  31      rows = doc.root.elements['rows']
  32      puts 'rows : ' + rows.to_s
  33      unless rows.nil?
  34        puts 'rows exist'
  35        result = rows.elements.each('row'){}.map do |node|
  36          puts 'looking at a row'
  37  
  38          # check for a new item
  39          # if it's different alert the user and update the database, then go to next link,
  40          rss_title = node.elements["col[@name='title']"].text.to_s
  41          old_item_link = ''
  42          old_item_link = node.elements["col[@name='item_link']"].text.to_s + ''
  43          id = node.elements["col[@name='t1key']"].text.to_s
  44          rss_link = node.elements["col[@name='link']"].text.to_s
  45          username = node.elements["col[@name='username']"].text.to_s + ''
  46          password = node.elements["col[@name='password']"].text.to_s + ''
  47  
  48          if username.empty? then
  49            #get the latest item from the rss feed
  50            new_item_title, new_item_link = fetch_feed(rss_link)
  51          else
  52            new_item_title, new_item_link = fetch_secure_feed(rss_link, username, password)
  53          end
  54          #puts 'after get_item_title'
  55          unless new_item_title.empty?
  56            #puts 'comparing new_item_link ; *' + new_item_link + '*' 
  57            #puts 'with old_item_link ; *' + old_item_link + '*' 
  58  
  59            if new_item_link != old_item_link then
  60              #update record
  61              result = update_feed(id, new_item_link)
  62              messenger.deliver(@user,  '"' + new_item_title + '" ' + new_item_link)
  63            end
  64          end
  65  
  66        end
  67      end
  68    end


References:
- XMPP simple feed reader [dzone.com]
- Retrieve your Gmail messages as an XML feed [dzone.com]

Scrape Google search results into an RSS feed

   1  
   2  require 'cgi'
   3  require 'open-uri'
   4  require 'rexml/document'
   5  include REXML
   6  
   7  class String
   8    def to_doc()
   9      Document.new(self)
  10    end
  11  end
  12  
  13  query = 'ruby file copy site:snippets.dzone.com'
  14  url = "http://www.google.co.uk/search?hl=en&q=#{URI.escape(query)}&btnG=Google+Search&meta="
  15  buffer = open(url,"UserAgent" => "Ruby-IMBot").read
  16  
  17  a_tags = buffer.to_s.gsub(/<\/?em>/," ").scan(/<h3 class=r><a href=[^<]+/).map{|x| x.gsub(/<h3 class=r>|class=l/,'') + '</a>'}.join
  18  
  19  doc_master = "<links><summary><keywords>#{query}</keywords><link>#{CGI.escapeHTML(url)}</link></summary><records>#{a_tags}</records></links>".to_doc
  20  
  21  file = File.new('google_links.xml','w')
  22  file.puts doc_master
  23  file.close
  24  


Now let's convert it to RSS with the following XSLT file:

   1  <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
   2  
   3  	<xsl:output method="xml" encoding="iso-8859-1" indent="yes"  />
   4  
   5  	<xsl:template match="links">
   6  
   7  		<rss version="2.0">	
   8  		<channel>
   9  		<title>Google search results 1 -10</title>
  10  		<link><xsl:value-of select="summary/link"/></link>
  11  		<description>Unofficial Google RSS search results feed - keywords'<xsl:value-of select="summary/query"/>'</description>
  12  
  13    	<language>en</language>
  14  
  15  	<xsl:apply-templates select="records" />
  16  
  17  		</channel>
  18  		</rss>
  19  
  20  	</xsl:template>
  21  
  22  	<xsl:template match="records/a">
  23  
  24  	<item>
  25  		<title><xsl:value-of select="."/></title>
  26  		<link><xsl:value-of select="@href"/></link>
  27  		<description><xsl:value-of select="."/> <xsl:value-of select="@href"/></description>
  28  	</item>
  29  
  30  	</xsl:template>	
  31  
  32  </xsl:stylesheet>
  33  


apply the transformation ...
   1  xsltproc google_rss.xsl google_links.xml


Output:
   1  
   2  <?xml version="1.0" encoding="iso-8859-1"?>
   3  <rss version="2.0">
   4    <channel>
   5      <title>Google search results 1 -10</title>
   6      <link>http://www.google.co.uk/search?hl=en&amp;q=ruby%20file%20copy%20site:snippets.dzone.com&amp;btnG=Google+Search&amp;meta=</link>
   7      <description>Unofficial Google RSS search results feed - keywords''</description>
   8      <language>en</language>
   9      <item>
  10        <title>Using  Ruby  to  copy  a  file  [ ruby ] [ copy ] [ file ]</title>
  11        <link>http://snippets.dzone.com/posts/show/4701</link>
  12        <description>Using  Ruby  to  copy  a  file  [ ruby ] [ copy ] [ file ]http://snippets.dzone.com/posts/show/4701</description>
  13      </item>
  14      <item>
  15        <title>DZone Snippets: Store, sort and share source code, with tag goodness</title>
  16        <link>http://snippets.dzone.com/posts</link>
  17        <description>DZone Snippets: Store, sort and share source code, with tag goodnesshttp://snippets.dzone.com/posts</description>
  18      </item>
  19      <item>
  20        <title> copy  code</title>
  21        <link>http://snippets.dzone.com/tag/copy</link>
  22        <description> copy  codehttp://snippets.dzone.com/tag/copy</description>
  23      </item>
  24      <item>
  25        <title>Prepend a String to a  file  [ ruby ] [ file ]</title>
  26        <link>http://snippets.dzone.com/posts/show/4464</link>
  27        <description>Prepend a String to a  file  [ ruby ] [ file ]http://snippets.dzone.com/posts/show/4464</description>
  28      </item>
  29      <item>
  30        <title>Home-brewed  file  upload in  Ruby  on Rails [ ruby ] [rails </title>
  31        <link>http://snippets.dzone.com/posts/show/1805</link>
  32        <description>Home-brewed  file  upload in  Ruby  on Rails [ ruby ] [rails http://snippets.dzone.com/posts/show/1805</description>
  33      </item>
  34      <item>
  35        <title>Upload a  file  using  Ruby  [ ruby ] [form] [web] [cgi] [page] [upload </title>
  36        <link>http://snippets.dzone.com/posts/show/5165</link>
  37        <description>Upload a  file  using  Ruby  [ ruby ] [form] [web] [cgi] [page] [upload http://snippets.dzone.com/posts/show/5165</description>
  38      </item>
  39      <item>
  40        <title> Copy  all svn:* properties from one  file  to another [subversion </title>
  41        <link>http://snippets.dzone.com/posts/show/5501</link>
  42        <description> Copy  all svn:* properties from one  file  to another [subversion http://snippets.dzone.com/posts/show/5501</description>
  43      </item>
  44      <item>
  45        <title>Using Rio from  Ruby  to easily save a Web page to  file  [ ruby ] [web </title>
  46        <link>http://snippets.dzone.com/posts/show/2432</link>
  47        <description>Using Rio from  Ruby  to easily save a Web page to  file  [ ruby ] [web http://snippets.dzone.com/posts/show/2432</description>
  48      </item>
  49      <item>
  50        <title> file  code</title>
  51        <link>http://snippets.dzone.com/tag/file</link>
  52        <description> file  codehttp://snippets.dzone.com/tag/file</description>
  53      </item>
  54      <item>
  55        <title>bScan - Simple Web Aplications Scanner [ ruby ] [regex] [php] [web </title>
  56        <link>http://snippets.dzone.com/posts/show/5094</link>
  57        <description>bScan - Simple Web Aplications Scanner [ ruby ] [regex] [php] [web http://snippets.dzone.com/posts/show/5094</description>
  58      </item>
  59    </channel>
  60  </rss>


Try the Google => RSS feed [rorbuilder.info] web page

Search code from snippets.dzone.com with XMPP

Instead of googling for something like 'ruby file copy site:snippets.dzone.com' the following script runs an IM bot to search for the keywords on your behalf.

   1  
   2  #!/usr/bin/ruby
   3  
   4  #file: xmppserver_search1.rb
   5  
   6  require 'rubygems'  
   7  require 'open-uri'
   8  require 'xmpp4r-simple'
   9  require 'rexml/document'
  10  include REXML
  11  
  12  messenger = Jabber::Simple.new('ruby@jamesrobertson.eu', "password4ruby")
  13  
  14  def action_msg(messenger, buddy, message)
  15  
  16    action = message[/^(\w+|\?)(\s+)?(.*)?/,1]
  17  
  18    case action
  19      when '?'
  20        keywords = $3
  21        search_keywords = keywords.strip.gsub(/\s+/,'+')
  22  
  23        buffer = open("http://search.live.com/results.aspx?q=ruby+#{search_keywords}+site%3Asnippets.dzone.com&amp;go=&amp;form=QBLH&amp;format=rss&format=rss",
  24        "UserAgent" => "Ruby-IMBot").read
  25  
  26        doc = Document.new(buffer)
  27        node_item = doc.root.elements['channel/item[1]']
  28        unless node_item.nil?
  29          title = node_item.elements['title'].text.to_s
  30          link = node_item.elements['link'].text.to_s
  31          messenger.deliver(buddy,   'try ... \'' + title + '\' ' + link) 
  32        else
  33          messenger.deliver(buddy,   "that search didn't work :/") 
  34        end
  35    
  36      when 'help'
  37        messenger.deliver(buddy,   "Help: 'search' using Ruby keywords in a live search with snippets.dzone.com") 
  38    else
  39      messenger.deliver(buddy, 'sorry I don\'t know how to process that. Type \'help\' for a list of commands.')
  40    end
  41  end
  42  
  43  
  44  while true
  45  
  46    messenger.received_messages do |msg|  
  47  
  48      message = URI.unescape(msg.body).gsub(/&lt;/,'<').gsub(/&gt;/,'>').gsub(/&apos;/,'\'').gsub(/&quot;/,'"').gsub(/&amp;/,'&')
  49      buddy = msg.from
  50  
  51      messenger.deliver(buddy,  "you said ... " + message)    
  52      Thread.new{action_msg(messenger,buddy, message)}
  53  
  54    end  
  55    sleep 2
  56  end
  57  
  58  


Here's a conversation I had with the bot earlier ...

[12:32:48] ruby is now Available (Available)
[12:32:54] James: ? file copy
[12:32:54] ruby: you said ... ? file copy
[12:32:55] ruby: try ... 'Using Ruby to copy a file [ruby] [copy] [file]' http://snippets.dzone.com/posts/show/4701
[12:33:34] James: ? asterisk call
[12:33:35] ruby: you said ... ? asterisk call
[12:33:36] ruby: try ... 'Asterisk code' http://snippets.dzone.com/user/jrobertson/tag/Asterisk
[12:33:58] James: ? copy
[12:34:00] ruby: you said ... ? copy
[12:34:05] ruby: try ... 'Using Ruby to copy a file [ruby] [copy] [file]' http://snippets.dzone.com/posts/show/4701
[12:34:16] James: ? infinity
[12:34:17] ruby: you said ... ? infinity
[12:34:18] ruby: try ... 'Convert Unicode codepoints to UTF-8 characters with Module#const ... ' http://snippets.dzone.com/posts/show/4546
[12:34:38] James: ? blahblahblah
[12:34:40] ruby: you said ... ? blahblahblah
[12:34:42] ruby: try ... 'ruby code' http://snippets.dzone.com/user/413x/tag/ruby

XMPP simple feed reader

This Ruby script is based on the code from Build your own Twitter 'track' feature [dzone.com] but now the latest entry can be tracked for any RSS or Atom feed.

   1  #!/usr/bin/ruby
   2  
   3  #file: xmppserver_db1.rb
   4  
   5  require 'rubygems'  
   6  require 'open-uri'
   7  require 'xmpp4r-simple'
   8  require 'rexml/document'
   9  include REXML
  10  
  11  URL_BASE = 'http://yourwebsite.com/sqlite3/'
  12  messenger = Jabber::Simple.new('jeeves3@jamesrobertson.eu', "passwordsecret")
  13  $file = ''
  14  
  15  class String
  16    def escape()
  17      URI.escape(self).gsub(/\?/,'%3F')
  18    end
  19  end
  20  
  21  def get_title(url)
  22  
  23    title = ''
  24    buffer = open(url, "UserAgent" => "Ruby-RSS2IMbot").read
  25  
  26    doc = Document.new(buffer)
  27    # get the title
  28    node_title = doc.root.elements['channel/title|title']
  29    puts 'title : ' + node_title.to_s
  30    unless node_title.nil?
  31      title = node_title.text.to_s
  32    end
  33    title
  34  end
  35  
  36  # displays only the latest unread new message from each feed
  37  def check_feed(messenger)
  38    result = false
  39    puts 'check feed'
  40    buddy = 'james@jamesrobertson.eu'
  41  
  42    url = URL_BASE + "select/rss2imbot.db/t1/column=*"
  43    buffer = open(url, "UserAgent" => "Ruby-RSS2IMbot").read
  44    doc = Document.new(buffer)
  45    rows = doc.root.elements['rows']
  46    puts 'rows : ' + rows.to_s
  47    unless rows.nil?
  48      result = rows.elements.each('row'){}.map do |node|
  49        # check for a new item
  50        # if it's different alert the user and update the database, then go to next link,
  51        rss_title = node.elements["col[@name='title']"].text.to_s
  52        old_item_title = node.elements["col[@name='item_title']"].text.to_s
  53        id = node.elements["col[@name='t1key']"].text.to_s
  54        rss_link = node.elements["col[@name='link']"].text.to_s
  55  
  56        #get the latest item from the rss feed
  57        new_item_title, link = get_item_title(rss_link)
  58  
  59        if new_item_title != old_item_title then
  60  
  61          #update record
  62          result = update_feed(id, new_item_title)
  63          messenger.deliver(buddy,  '"' + new_item_title + '" ' + link)
  64        end
  65  
  66      end
  67    end
  68  end
  69  
  70  
  71  def update_feed(id, item_title)
  72    result = false
  73  
  74    url = URL_BASE + "update/rss2imbot.db/t1/set-column=item_title:#{item_title.escape}&t1key=#{id}"
  75    buffer = open(url, "UserAgent" => "Ruby-RSS2IMbot").read
  76    doc = Document.new(buffer)
  77    node_result = doc.root.attribute('method')
  78    result = true unless node_result.nil?
  79    result
  80  end
  81  
  82  def get_item_title(url)
  83  
  84    title = ''
  85    buffer = open(url, "UserAgent" => "Ruby-RSS2IMbot").read
  86  
  87    doc = Document.new(buffer)
  88    # get the title
  89    node_title = doc.root.elements['channel/item/title|entry/title']
  90    unless node_title.nil?
  91      title = node_title.text.to_s
  92      node_link = doc.root.elements['channel/item/link|entry/link']
  93      unless node_link.nil?
  94        unless node_link.text.to_s.empty? then
  95          link = node_link.text.to_s # it's an rss feed
  96        else
  97          link = node_link.attribute('href').to_s # it's an atom feed
  98        end
  99      end
 100    end
 101    return title, link
 102  end
 103  
 104  def action_msg(messenger, buddy, message)
 105  
 106    action = message[/^(\w+)(\s+)?(.*)?/,1]
 107  
 108    case action
 109      when 'add'
 110        rss_feed = $3
 111        if rss_feed.match(/^http:\/\/.*$/) then
 112          title = get_title(rss_feed)
 113          add_feed(title,rss_feed)
 114        else
 115           messenger.deliver(buddy,  "That web feed isn't valid'")
 116        end
 117  
 118      when 'list'
 119        url = URL_BASE + "select/rss2imbot.db/t1/column=*"
 120        buffer = open(url,"UserAgent" => "Ruby-IMBot").read
 121        doc = Document.new(buffer)
 122        rows = doc.root.elements['rows']
 123        unless rows.nil?
 124          result = rows.elements.each('row'){}.map do |node|
 125            node.attribute('id').to_s + '. ' + node.elements["col[@name='title']"].text.to_s
 126          end
 127          messenger.deliver(buddy,  result.inspect)
 128        end
 129  
 130      when 'remove'
 131        id = $3
 132  
 133        url = URL_BASE + 'select/rss2imbot.db/t1/column=title&t1key=1'
 134        buffer = open(url,"UserAgent" => "Ruby-IMBot").read
 135        doc = Document.new(buffer)
 136        node_col = doc.root.elements['rows/row/col']
 137        unless node_col.nil? 
 138    
 139          title = node_col.text.to_s
 140          messenger.deliver(buddy,   'remove \'' + title + '\' (y/n)') 
 141          elapsed = 0
 142          start_time = Time.now
 143          answered = false
 144          response = ''
 145  
 146          while (elapsed < 30 and not answered == true)
 147            messenger.received_messages do |msg|  
 148              puts msg.body
 149              if msg.body.match(/^(y|n)$/) then
 150                response = msg.body
 151                answered = true            
 152              end
 153            end
 154            elapsed = Time.now - start_time        
 155          end
 156          messenger.deliver(buddy, 'you took too long to answer, I\'m *not* removing any feed now!') if elapsed >= 30
 157          if response == 'y' then
 158            messenger.deliver(buddy,   ' will now remove ' + title)  
 159            url = URL_BASE + "delete/rss2imbot.db/t1/t1key=#{id}"
 160            result_buffer = open(url,"UserAgent" => "Ruby-IMBot").read
 161            doc_result = Document.new(result_buffer)
 162            node_result = doc_result.root.attribute('method')
 163            messenger.deliver(buddy,   '\'' + title + '\' has been removed.') unless node_result.nil?
 164          end
 165        end
 166  
 167      when 'help'
 168        messenger.deliver(buddy,   "Help: 'add' a feed, 'list' all feeds, or 'remove' a feed.") 
 169    else
 170      puts 'sorry I don\'t know how to process that. Type \'help\' for a list of commands.'
 171    end
 172  end
 173  
 174  def add_feed(title, link)
 175    result = false
 176  
 177    puts "insert/rss2imbot.db/t1/title=#{title.escape}&link=#{link.escape}"
 178    url = URL_BASE + "insert/rss2imbot.db/t1/title=#{title.escape}&link=#{link.escape}"
 179    buffer = open(url, "UserAgent" => "Ruby-RSS2IMbot").read
 180    doc = Document.new(buffer)
 181    node_result = doc.root.attribute('method')
 182    result = true unless node_result.nil?
 183    result
 184  end
 185  
 186  
 187  while true
 188  
 189    # check the feeds every 1 minute.
 190    check_feed(messenger) if Time.now.strftime("%S").to_i <= 3
 191    messenger.received_messages do |msg|  
 192  
 193      message = URI.unescape(msg.body).gsub(/&lt;/,'<').gsub(/&gt;/,'>').gsub(/&apos;/,'\'').gsub(/&quot;/,'"').gsub(/&amp;/,'&')
 194      buddy = msg.from
 195  
 196      messenger.deliver(buddy,  "you said ... " + message)    
 197      action_msg(messenger,buddy, message)
 198  
 199    end  
 200    sleep 2
 201  end


test:
[01:20:38] jeeves3 is now Available (Available)
[01:20:41] James: list
[01:20:42] jeeves3: you said ... list
[01:20:43] jeeves3: ["1. ruby - Twitter Search"]
[01:21:04] jeeves3: "babysitting Ruby while the missus gets some accupuncture.. now covered in vomit too - thanks Ruby!" http://twitter.com/gregdwyer/statuses/922733451
[01:21:39] James: add http://snippets.dzone.com/rss
[01:21:41] jeeves3: you said ... add http://snippets.dzone.com/rss
[01:22:16] jeeves3: "Test" http://feeds.dzone.com/~r/dzone/snippets/~3/393549326/6080
[01:22:20] James: list
[01:22:20] jeeves3: you said ... list
[01:22:21] jeeves3: ["1. ruby - Twitter Search", "2. DZone Snippets: Store, sort and share source code, with tag goodness"]
[01:22:49] James: remove 1
[01:22:49] jeeves3: you said ... remove 1
[01:22:51] jeeves3: remove 'ruby - Twitter Search' (y/n)
[01:22:53] James: y
[01:22:53] jeeves3: will now remove ruby - Twitter Search
[01:22:54] jeeves3: 'ruby - Twitter Search' has been removed.
[01:22:57] James: list
[01:22:58] jeeves3: you said ... list
[01:23:00] jeeves3: ["1. DZone Snippets: Store, sort and share source code, with tag goodness"]

Seamlessly return a string from http or https feeds

// This class uses URI module to detect regular or secure links, and returns the response as a st