<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Développement Web Libre &#187; ruby</title>
	<atom:link href="http://www.sbnet.fr/tag/ruby/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.sbnet.fr</link>
	<description>xhtml, css, javascript, php et ruby</description>
	<lastBuildDate>Wed, 21 Jul 2010 11:57:47 +0000</lastBuildDate>
	<generator>http://wordpress.org/?v=2.9.2</generator>
	<language>fr</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
			<item>
		<title>Un robot qui parcourt le web à votre place</title>
		<link>http://www.sbnet.fr/2007/04/27/un-robot-qui-parcourt-le-web-a-votre-place/</link>
		<comments>http://www.sbnet.fr/2007/04/27/un-robot-qui-parcourt-le-web-a-votre-place/#comments</comments>
		<pubDate>Fri, 27 Apr 2007 09:31:20 +0000</pubDate>
		<dc:creator>Stéphane</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Qui n&#8217;a pas un jour eu besoin d&#8217;un robot effectuant une action répétitive sur un site web. C&#8217;est ce que nous allons réaliser sous la forme d&#8217;un simple script Ruby.

Pièces détachées
Pour construire notre robot nous avons besoin des ces divers éléments :

Ruby
La bibliothèque Mechanize
Un éditeur de texte, si vous êtes sous windows je vous conseille [...]]]></description>
			<content:encoded><![CDATA[<p>Qui n&#8217;a pas un jour eu besoin d&#8217;un robot effectuant une action répétitive sur un site web. C&#8217;est ce que nous allons réaliser sous la forme d&#8217;un simple script Ruby.<br />
<span id="more-110"></span></p>
<h3>Pièces détachées</h3>
<p>Pour construire notre robot nous avons besoin des ces divers éléments :</p>
<ul>
<li><a href="http://www.ruby-lang.org/fr/" hreflang="fr">Ruby</a></li>
<li>La bibliothèque <a href="http://mechanize.rubyforge.org/" hreflang="en">Mechanize</a></li>
<li>Un éditeur de texte, si vous êtes sous windows je vous conseille d&#8217;aller voir du côté de chez <a href="http://www.e-texteditor.com/" hreflang="en">e-texteditor</a></li>
</ul>
<h3>Assemblage</h3>
<p>Nous allons étudier un exemple fourni dans la documentation de Mechanize : celui qui permet d&#8217;envoyer automatiquement une image sur le site Flickr.</p>
<div style="overflow: auto;"><pre class="ruby" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;"><span class="kw3">require</span> <span class="st0">'rubygems'</span>
<span class="kw3">require</span> <span class="st0">'mechanize'</span>
agent = <span class="re2">WWW::Mechanize</span>.<span class="me1">new</span>
 
<span class="co1"># Page de connexion à Flickr</span>
page  = agent.<span class="me1">get</span><span class="br0">(</span><span class="st0">'http://flickr.com/signin/flickr/'</span><span class="br0">)</span>
 
<span class="co1"># Remplissage du formulaire de connexion</span>
form  = page.<span class="me1">forms</span>.<span class="me1">name</span><span class="br0">(</span><span class="st0">'flickrloginform'</span><span class="br0">)</span>.<span class="me1">first</span>
form.<span class="me1">email</span> = ARGV<span class="br0">[</span><span class="nu0">0</span><span class="br0">]</span>
form.<span class="me1">password</span> = ARGV<span class="br0">[</span><span class="nu0">1</span><span class="br0">]</span>
page  = agent.<span class="me1">submit</span><span class="br0">(</span>form<span class="br0">)</span>
 
<span class="co1"># Page de transfert</span>
page  = agent.<span class="me1">click</span> page.<span class="me1">links</span>.<span class="me1">text</span><span class="br0">(</span><span class="st0">'Upload'</span><span class="br0">)</span>
 
<span class="co1"># Remplissage du formulaire de transfert</span>
form  = page.<span class="me1">forms</span>.<span class="me1">action</span><span class="br0">(</span><span class="st0">'/photos_upload_process.gne'</span><span class="br0">)</span>.<span class="me1">first</span>
form.<span class="me1">file_uploads</span>.<span class="me1">name</span><span class="br0">(</span><span class="st0">'file1'</span><span class="br0">)</span>.<span class="me1">first</span>.<span class="me1">file_name</span> = ARGV<span class="br0">[</span><span class="nu0">2</span><span class="br0">]</span>
agent.<span class="me1">submit</span><span class="br0">(</span>form<span class="br0">)</span></pre></div>
<p>Rien qu&#8217;en lisant le code on arrive déjà à comprendre le fonctionnement général de cet exemple. On retrouve les classiques inclusions de bibliothèque et initialisations d&#8217;objets au début du script.</p>
<p>Mechanize permet d&#8217;effectuer toutes les actions que ferrait un visiteur <em>humain</em> sur une page web. Notre robot commence donc par ouvrir la page de connexion de Flicker en utilisant le fonction <em>get</em>. Puis il trouve le formulaire avec <em>forms.name(&#8216;nom_du_formulaire&#8217;).first</em> et remplis chaque champs : la fonction précédente nous à retourné un objet initialisé avec tous les champs du formulaire, on peut y accéder directement. Il ne nous reste plus qu&#8217;a soumettre ce formulaire, c&#8217;est ce que fait la méthode <em>submit</em>, ça reviendrait à cliquer sur le bouton <em>Get in there</em> si on était un vrai visiteur en chair et en os.</p>
<p>Voila, on est connecté, pour transférer une image il faut simuler un clic sur le lien texte <em>Upload</em>, c&#8217;est ce que fait le morceau de script qui suit (Le <em>agent.clic &#8230;</em>) et remplir le nouveau formulaire, celui du transfert. On notera la fonction <em>file_uploads</em> qui facilite bien les choses &#8230;</p>
<p>Le transfert commence dès qu&#8217;on valide ce dernier formulaire.</p>
<p>Vous avez vu, c&#8217;est vraiment très simple. Il ne vous reste plus qu&#8217;a créer votre propre script pour automatiser vos tâches de navigation qui seraient un peut trop rébarbatives. Vous pouvez vous en servir pour exemple mettre à jour un site de façon régulière en plaçant votre script dans une tâche cron.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sbnet.fr/2007/04/27/un-robot-qui-parcourt-le-web-a-votre-place/feed/</wfw:commentRss>
		<slash:comments>14</slash:comments>
		</item>
		<item>
		<title>Lire un flux RSS avec Ruby on Rails</title>
		<link>http://www.sbnet.fr/2007/03/16/lire-un-flux-rss-avec-ruby-on-rails/</link>
		<comments>http://www.sbnet.fr/2007/03/16/lire-un-flux-rss-avec-ruby-on-rails/#comments</comments>
		<pubDate>Fri, 16 Mar 2007 10:21:56 +0000</pubDate>
		<dc:creator>Stéphane</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[J&#8217;ai récemment eu besoin d&#8217;intégrer les données d&#8217;un flux RSS dans 36000.fr, Ruby nous facilite tellement la tâche que c&#8217;est presque trop simple&#8230;

Lecture du flux
Commençons par ajouter les bibliothèques utilisées :
require 'rss'
require 'open-uri'
Voici un exemple de code qui va récupérer les informations dans le fichier RSS et préparer une chaine pour l&#8217;affichage :
feed_url = &#34;http://www.url_du_flux&#34;
output [...]]]></description>
			<content:encoded><![CDATA[<p>J&#8217;ai récemment eu besoin d&#8217;intégrer les données d&#8217;un flux RSS dans <a href="http://www.36000.fr/" hreflang="fr">36000.fr</a>, Ruby nous facilite tellement la tâche que c&#8217;est presque <em>trop</em> simple&#8230;<br />
<span id="more-108"></span></p>
<h3>Lecture du flux</h3>
<p>Commençons par ajouter les bibliothèques utilisées :</p>
<div style="overflow: auto;"><pre class="ruby" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;"><span class="kw3">require</span> <span class="st0">'rss'</span>
<span class="kw3">require</span> <span class="st0">'open-uri'</span></pre></div>
<p>Voici un exemple de code qui va récupérer les informations dans le fichier RSS et préparer une chaine pour l&#8217;affichage :</p>
<div style="overflow: auto;"><pre class="ruby" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;">feed_url = <span class="st0">&quot;http://www.url_du_flux&quot;</span>
output = <span class="st0">&quot;&lt;h1&gt;Lecture d'un flux RSS&lt;/h1&gt;&quot;</span>
<span class="kw3">open</span><span class="br0">(</span>feed_url<span class="br0">)</span> <span class="kw1">do</span> |http|
  response = http.<span class="me1">read</span>
  result = <span class="re2">RSS::Parser</span>.<span class="me1">parse</span><span class="br0">(</span>response, <span class="kw2">false</span><span class="br0">)</span>
  output += <span class="st0">&quot;Titre du flux : #{result.channel.title}&lt;br /&gt;&quot;</span>
  result.<span class="me1">items</span>.<span class="me1">each_with_index</span> <span class="kw1">do</span> |item, i|
    output += <span class="st0">&quot;#{i+1}. #{item.title}&lt;br /&gt;&quot;</span> <span class="kw1">if</span> i &lt; <span class="nu0">10</span>
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div>
<p>Explications :</p>
<ul>
<li>feed_url est bien sûr l&#8217;adresse du flux</li>
<li>output est une chaine qui contiendra le code à afficher dans notre page web</li>
</ul>
<p>On commence par lire le flux avec <em>http.read</em> puis on le parse avec <em>RSS::Parser.parse</em>, cette étape permet de transformer le flux en un objet simple d&#8217;utilisation, par exemple, pour obtenir le titre du flux, un <em>result.channel.title</em> suffit.</p>
<p>Ce n&#8217;est pas plus compliqué que ça et de plus il existe un <a href="http://cozmixng.sgk.iwate-u.ac.jp/~rwiki/?cmd=view;name=RSS+Parser%3A%3ATutorial.en" hreflang="en">tutoriel en anglais</a> pour RSS Parser si vous voulez approfondir.</p>
<h3>Mise en cache</h3>
<p>Pourquoi pas utiliser le petit <a href="http://www.sbnet.fr/blog/index.php/2007/02/22/17-un-systeme-de-cache-simple-en-base-de-donnees" hreflang="fr">système de cache</a> que j&#8217;ai présenté dernièrement ? Voici comment faire :</p>
<div style="overflow: auto;"><pre class="ruby" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;"><span class="kw1">if</span> CachedItem.<span class="me1">check_for</span><span class="br0">(</span><span class="st0">&quot;RSS&quot;</span><span class="br0">)</span>
  <span class="co1"># Disponible depuis le cache</span>
  flux_rss = CachedItem.<span class="me1">get_cached</span><span class="br0">(</span><span class="st0">&quot;RSS&quot;</span><span class="br0">)</span>
<span class="kw1">else</span>
  feed_url = <span class="st0">&quot;http://www.url_du_flux...&quot;</span>
  <span class="kw3">open</span><span class="br0">(</span>feed_url<span class="br0">)</span> <span class="kw1">do</span> |http|
    flux_rss = http.<span class="me1">read</span>
    flux_rss = <span class="re2">RSS::Parser</span>.<span class="me1">parse</span><span class="br0">(</span>flux_rss, <span class="kw2">false</span><span class="br0">)</span>
    CachedItem.<span class="me1">store_data</span><span class="br0">(</span><span class="st0">&quot;RSS&quot;</span>, flux_rss<span class="br0">)</span>
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div>
<p>On commence par vérifier si le flux à déjà été parsé récemment et si ce n&#8217;est pas le cas, on le récupère et on le stocke dans le cache.</p>
<p>Je me suis inspiré d&#8217;un article de <a href="http://www.robbyonrails.com/" hreflang="en">Robby</a> pour le sujet de ce billet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sbnet.fr/2007/03/16/lire-un-flux-rss-avec-ruby-on-rails/feed/</wfw:commentRss>
		<slash:comments>3</slash:comments>
		</item>
		<item>
		<title>Un système de cache simple en base de données</title>
		<link>http://www.sbnet.fr/2007/02/22/un-systeme-de-cache-simple-en-base-de-donnees/</link>
		<comments>http://www.sbnet.fr/2007/02/22/un-systeme-de-cache-simple-en-base-de-donnees/#comments</comments>
		<pubDate>Thu, 22 Feb 2007 11:21:46 +0000</pubDate>
		<dc:creator>Stéphane</dc:creator>
				<category><![CDATA[Informatique]]></category>
		<category><![CDATA[ruby]]></category>

		<guid isPermaLink="false"></guid>
		<description><![CDATA[Quand on n&#8217;a pas la possibilité d&#8217;avoir un serveur memcache à disposition, on peut mettre en place un système de cache en base de données simplement. Voici comment faire.

Il faut commencer par créer la table qui va stocker les données, voici les commandes sql pour mySQL :
CREATE TABLE `cached_items` (
  `id` int(11) NOT NULL [...]]]></description>
			<content:encoded><![CDATA[<p>Quand on n&#8217;a pas la possibilité d&#8217;avoir un serveur <a href="http://www.danga.com/memcached/" hreflang="en">memcache</a> à disposition, on peut mettre en place un système de cache en base de données simplement. Voici comment faire.<br />
<span id="more-107"></span></p>
<p>Il faut commencer par créer la table qui va stocker les données, voici les commandes sql pour mySQL :</p>
<div style="overflow: auto;"><pre class="sql" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;"><span class="kw1">CREATE</span> <span class="kw1">TABLE</span> <span class="st0">`cached_items`</span> <span class="br0">(</span>
  <span class="st0">`id`</span> int<span class="br0">(</span><span class="nu0">11</span><span class="br0">)</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span> <span class="kw1">AUTO_INCREMENT</span>,
  <span class="st0">`cachekey`</span> varchar<span class="br0">(</span><span class="nu0">255</span><span class="br0">)</span> <span class="kw1">DEFAULT</span> <span class="kw1">NULL</span>,
  <span class="st0">`created`</span> datetime <span class="kw1">DEFAULT</span> <span class="kw1">NULL</span>,
  <span class="st0">`expires`</span> datetime <span class="kw1">DEFAULT</span> <span class="kw1">NULL</span>,
  <span class="st0">`content`</span> longblob,
  <span class="st0">`cachehit`</span> int<span class="br0">(</span><span class="nu0">11</span><span class="br0">)</span> <span class="kw1">NOT</span> <span class="kw1">NULL</span>,
  <span class="kw1">PRIMARY</span> <span class="kw1">KEY</span>  <span class="br0">(</span><span class="st0">`id`</span><span class="br0">)</span>,
  <span class="kw1">KEY</span> <span class="st0">`cacheditems_cachekey_index`</span> <span class="br0">(</span><span class="st0">`cachekey`</span><span class="br0">)</span>,
  <span class="kw1">KEY</span> <span class="st0">`cacheditems_created_index`</span> <span class="br0">(</span><span class="st0">`created`</span><span class="br0">)</span>,
  <span class="kw1">KEY</span> <span class="st0">`cacheditems_expires_index`</span> <span class="br0">(</span><span class="st0">`expires`</span><span class="br0">)</span>
<span class="br0">)</span>;</pre></div>
<p>Ensuite, il faut créer un modèle appelé <em>CachedItem</em> dans <em>app/models/cached_item.rb</em> c&#8217;est grâce à lui qu&#8217;on pourra accéder aux données cachées :</p>
<div style="overflow: auto; height: 300px;"><pre class="ruby" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;"><span class="kw3">require</span> <span class="st0">'digest/sha1'</span>
 
<span class="kw1">class</span> CachedItem &lt; <span class="re2">ActiveRecord::Base</span>
  <span class="kw1">def</span> <span class="kw2">self</span>.<span class="me1">check_for</span><span class="br0">(</span>item<span class="br0">)</span>
    key = <span class="re2">Digest::MD5</span>.<span class="me1">hexdigest</span><span class="br0">(</span><span class="kw4">Marshal</span>.<span class="me1">dump</span><span class="br0">(</span>item<span class="br0">)</span><span class="br0">)</span>
    logger.<span class="me1">info</span> <span class="st0">&quot;Cache checking for key #{key}&quot;</span>
    <span class="kw2">self</span>.<span class="me1">find</span><span class="br0">(</span><span class="re3">:first</span>, <span class="re3">:conditions</span> =&gt; <span class="br0">[</span><span class="st0">&quot;cachekey = ? AND expires &gt; NOW()&quot;</span>, key<span class="br0">]</span><span class="br0">)</span>
  <span class="kw1">end</span>
 
  <span class="kw1">def</span> <span class="kw2">self</span>.<span class="me1">get_cached</span><span class="br0">(</span>item<span class="br0">)</span>
    key = <span class="re2">Digest::MD5</span>.<span class="me1">hexdigest</span><span class="br0">(</span><span class="kw4">Marshal</span>.<span class="me1">dump</span><span class="br0">(</span>item<span class="br0">)</span><span class="br0">)</span>
    logger.<span class="me1">info</span> <span class="st0">&quot;Cache getting by key #{key}&quot;</span>
    getc = <span class="kw2">self</span>.<span class="me1">find</span><span class="br0">(</span> <span class="re3">:first</span>, <span class="re3">:conditions</span> =&gt; <span class="br0">[</span><span class="st0">&quot;cachekey = ?&quot;</span>, key<span class="br0">]</span> <span class="br0">)</span>
    hitcount = getc.<span class="me1">cachehit</span> + <span class="nu0">1</span>
    <span class="kw2">self</span>.<span class="me1">update</span><span class="br0">(</span>getc.<span class="me1">id</span>, <span class="br0">{</span>:cachehit =&gt; hitcount<span class="br0">}</span><span class="br0">)</span>
    <span class="kw2">self</span>.<span class="me1">delete_all</span> <span class="st0">&quot;expires &lt; NOW()&quot;</span>  <span class="co1"># Efface les données trop vieilles</span>
    <span class="kw2">return</span> <span class="kw4">Marshal</span>.<span class="kw3">load</span><span class="br0">(</span>getc.<span class="me1">content</span><span class="br0">)</span>
 <span class="kw1">end</span>
 
  <span class="kw1">def</span> <span class="kw2">self</span>.<span class="me1">store_data</span><span class="br0">(</span>item, data<span class="br0">)</span>
    key = <span class="re2">Digest::MD5</span>.<span class="me1">hexdigest</span><span class="br0">(</span><span class="kw4">Marshal</span>.<span class="me1">dump</span><span class="br0">(</span>item<span class="br0">)</span><span class="br0">)</span>
    logger.<span class="me1">info</span> <span class="st0">&quot;%%% storing by key #{key}&quot;</span>
    content = <span class="kw4">Marshal</span>.<span class="me1">dump</span><span class="br0">(</span>data<span class="br0">)</span>
    logger.<span class="me1">level</span> = <span class="br0">(</span><span class="nu0">4</span><span class="br0">)</span> <span class="co1"># Empêche d'afficher les données de Marshal dans le log</span>
    ci = new<span class="br0">(</span><span class="br0">)</span>
    ci.<span class="me1">cachekey</span> = key
    ci.<span class="me1">created</span> = <span class="kw4">Time</span>.<span class="me1">now</span><span class="br0">(</span><span class="br0">)</span>
    ci.<span class="me1">expires</span> = <span class="nu0">30</span>.<span class="me1">minutes</span>.<span class="me1">from_now</span><span class="br0">(</span><span class="br0">)</span> <span class="co1"># durée de vie de la donnée cachée</span>
    ci.<span class="me1">content</span> = content
    ci.<span class="me1">cachehit</span> = <span class="nu0">0</span>
    ci.<span class="me1">save</span>
    <span class="kw2">return</span> data
  <span class="kw1">end</span>
<span class="kw1">end</span></pre></div>
<p>Voila, le plus dur est fait. Faites attention au type de données que vous stockez, <a href="http://www.ruby-doc.org/core/classes/Marshal.html" hreflang="en">Marshal</a> ne supporte pas tous les types. Vous pouvez sans problème stocker une chaîne, par exemple pour du XML vous pouvez faire :</p>
<div style="overflow: auto;"><pre class="ruby" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;">donnees = <span class="re2">REXML::Document</span>.<span class="me1">new</span><span class="br0">(</span>mes_donnees_xml<span class="br0">)</span>.<span class="me1">root</span>
CachedItem.<span class="me1">store_data</span><span class="br0">(</span>donnees_id, donnees.<span class="me1">to_s</span><span class="br0">)</span></pre></div>
<p>Pour stoker des donnes xml. Pour les relire :</p>
<div style="overflow: auto;"><pre class="ruby" id="geshi" style="color: #fff; border-left: 5px solid #900; background-color:#000;">donnees = <span class="re2">REXML::Document</span>.<span class="me1">new</span><span class="br0">(</span>CachedItem.<span class="me1">get_cached</span><span class="br0">(</span>mes_donnees_xml_id<span class="br0">)</span><span class="br0">)</span>.<span class="me1">root</span></pre></div>
<p>Les données trop vieilles sont automatiquement effacée lors d&#8217;une lecture quelconque (voir <em>get_cached</em>) et la durée de vie d&#8217;une donnée est définie lors de l&#8217;écriture dans <em>store_data</em>.</p>
<p>Merci à joeldg pour son <a href="http://snippets.dzone.com/posts/show/3286" hreflang="en">code</a> qui a servi de base à ce billet.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.sbnet.fr/2007/02/22/un-systeme-de-cache-simple-en-base-de-donnees/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
