<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <title>Think in code - Home</title>
  <id>tag:thinkincode.net,2008:mephisto/</id>
  <generator version="0.7.3" uri="http://mephistoblog.com">Mephisto Noh-Varr</generator>
  <link href="http://thinkincode.net/feed/atom.xml" rel="self" type="application/atom+xml"/>
  <link href="http://thinkincode.net/" rel="alternate" type="text/html"/>
  <updated>2008-07-24T21:04:22Z</updated>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-07-24:185</id>
    <published>2008-07-24T20:59:00Z</published>
    <updated>2008-07-24T21:04:22Z</updated>
    <category term="Atom Publishing Protocol"/>
    <category term="Java"/>
    <link href="http://thinkincode.net/2008/7/24/apache-abdera-supports-atompub-multipart" rel="alternate" type="text/html"/>
    <title>Apache Abdera supports AtomPub-multipart creation</title>
<content type="html">
            &lt;p&gt;One of the most weird stuff in the AtomPub specification is the media creation flow. First, you need to send a request in order to post the new media resource and once the response is correct you can update the media link entry related with it.&lt;/p&gt;

&lt;p&gt;In order to avoid the second step, the Picassa team added to their api a &lt;a href='http://code.google.com/apis/picasaweb/developers_guide_protocol.html#Add_Photo'&gt;new way to add photos&lt;/a&gt;, and now, they allow to send a multipart file that wraps the photo and its metadata. &lt;/p&gt;

&lt;p&gt;This atom extension is been covered by &lt;a href='http://atompub-mulitpart-spec.googlecode.com/svn/trunk/draft-gregorio-atompub-multipart-02.txt'&gt;an IEFT draft that Joe Gregorio published&lt;/a&gt;, and this morning I've updated the &lt;a href='http://svn.apache.org/repos/asf/incubator/abdera/java/trunk/'&gt;Abdera trunk&lt;/a&gt; in order to implement this specification. &lt;/p&gt;

&lt;p&gt;You can read more into &lt;a href='http://cwiki.apache.org/confluence/display/ABDERA/Support+for+AtomPub-multipart'&gt;the Abdera wiki&lt;/a&gt;. Enjoy it.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-07-16:133</id>
    <published>2008-07-16T11:47:00Z</published>
    <updated>2008-07-16T13:26:06Z</updated>
    <category term="Atom Publishing Protocol"/>
    <link href="http://thinkincode.net/2008/7/16/atompub-at-gtac-08" rel="alternate" type="text/html"/>
    <title>Speaking: AtomPub at GTAC 08</title>
<content type="html">
            &lt;p&gt;This October I'll be presenting at &lt;a href='http://googletesting.blogspot.com/2008/07/call-for-attendance-gtac-2008.html'&gt;Google Test Automation Conference&lt;/a&gt; on testing of AtomPub implementations. The talk will discuss the best practices in order to test AtomPub implementations, why testing an extensible standard could become painful and how to get started with some useful tools.&lt;/p&gt;

&lt;p&gt;GTAC is one of my favorites conferences, people talking about testing, just one track and no fees. If you are considering applying for attendance, I suggest it. But if you are actually interested in testing and you didn't know it, you should consider applying.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-07-02:67</id>
    <published>2008-07-02T21:31:00Z</published>
    <updated>2008-07-02T21:37:28Z</updated>
    <category term="Atom Publishing Protocol"/>
    <link href="http://thinkincode.net/2008/7/2/the-ape-1-5-released" rel="alternate" type="text/html"/>
    <title>The ape 1.5 released</title>
<content type="html">
            &lt;p&gt;Yesterday I released a new version of &lt;a href='http://rubyforge.org/projects/ape'&gt;The atom protocol exerciser&lt;/a&gt;. We have been working in order to simplify its architecture and create a modular system that anyone may extend.&lt;/p&gt;

&lt;p&gt;Now it works from the command line as well the web interface. We've added some rake tasks that you can use for exercise your server implementation and you can select the output format just invoking the correct option:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
 $ rake ape:go:text['service document uri']
 $ rake ape:go:html['service document uri']
 $ rake ape:go:atom['service document uri']
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It allows some configuration options through its config file &lt;em&gt;$APE_HOME/aperc&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Ape.conf[:REQUESTED_ENTRY_COLLECTION] = 'collection name'
Ape.conf[:REQUESTED_MEDIA_COLLECTION] = 'collection name'
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And finally, this last release allows to create and add new tests easily. The test cases must to extend the Ape Validator class and override the validate method.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
module Ape
  class CustomValidator &amp;lt; Validator
    def validate(opts = {}) end
  end
end
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;We've implemented a little system for select the variables to use in your tests, just call the &lt;strong&gt;requires_presence_of&lt;/strong&gt; method into the class declaration and pass the variable name that you require.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
module Ape
  class CustomValidator &amp;lt; Validator
    requires_presence_of :entry_collection #OR
    requires_presence_of :entry_collection =&gt; 'comments' #OR
    requires_presence_of :media_collection =&gt; {:accept =&gt; 'image/png'}
    #...
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Once your custom validator is ready you just need to move it to &lt;em&gt;$APE_HOME/validators&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;But if you really want to learn how to write your custom validator you just need to take a look at the &lt;a href='http://ape.rubyforge.org/svn/trunk/lib/ape/validators/media_posts_validator.rb'&gt;source&lt;/a&gt; &lt;a href='http://ape.rubyforge.org/svn/trunk/lib/ape/validators/sanitization_validator.rb'&gt;code&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-05-22:62</id>
    <published>2008-05-22T11:05:00Z</published>
    <updated>2008-05-22T15:30:44Z</updated>
    <category term="Desarrollo"/>
    <category term="Java"/>
    <category term="Ruby on rails"/>
    <link href="http://thinkincode.net/2008/5/22/using-hudson-as-rails-ci-server" rel="alternate" type="text/html"/>
    <title>Using Hudson as Rails CI server</title>
<content type="html">
            &lt;p&gt;For some time, &lt;a href='http://hudson.dev.java.net'&gt;Hudson&lt;/a&gt; has become my favorite continuous integration server. It's easy to configure and provides a handful of really interesting plug-ins. The only thing that I missed was the possibility of use &lt;a href='http://rake.rubyforge.org'&gt;Rake&lt;/a&gt; as a project build tool and thus I'll be able to take my java, ruby or rails projects into the same CI server.&lt;/p&gt;

&lt;p&gt;Well, past weekend I had too much spare time so I decided to develop my first Hudson plugin and this morning I've released the first version of the &lt;a href='http://hudson.gotdns.com/wiki/display/HUDSON/Rake+plugin'&gt;Hudson Rake plugin&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;Once you have &lt;a href='http://hudson.gotdns.com/wiki/display/HUDSON/Installation+and+Execution'&gt;installed Hudson&lt;/a&gt; you just need to &lt;a href='https://hudson.dev.java.net/servlets/ProjectDocumentList?folderID=9255&amp;amp;expandFolder=9255&amp;amp;folderID=0'&gt;donwload the plug-in&lt;/a&gt; and upload it from the &lt;strong&gt;&lt;em&gt;Manage Hudson&lt;/strong&gt;&lt;/em&gt; section:&lt;/p&gt;

&lt;p&gt;&lt;img src='/assets/2008/5/22/hudsonPluginUpload.png' /&gt;&lt;/p&gt;

&lt;p&gt;When the plugin is avalable it detects your ruby instances installed from your &lt;strong&gt;PATH&lt;/strong&gt; but it allows you to add other ruby or jruby paths:&lt;/p&gt;

&lt;p&gt;&lt;img src='/assets/2008/5/22/rubyConfigurationOptions.png' width='90%' /&gt;&lt;/p&gt;

&lt;p&gt;Finally you just need to select the &lt;strong&gt;&lt;em&gt;Invoke Rake&lt;/strong&gt;&lt;/em&gt; option into the project configuration and select the tasks that you want to Hudson executes:&lt;/p&gt;

&lt;p&gt;&lt;img src='/assets/2008/5/22/jobRakeConfiguration.png' width='100%' /&gt;&lt;/p&gt;

&lt;p&gt;That's it, you are ready to go with Rake, Hudson and &lt;a href='http://clintshank.javadevelopersjournal.com/ci_build_game.htm'&gt;the Continuous&lt;/a&gt; &lt;a href='http://redsolo.blogspot.com/2008/04/start-playing-continuous-integration.html'&gt;Integration Game&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-04-28:60</id>
    <published>2008-04-28T08:09:00Z</published>
    <updated>2008-04-28T08:35:09Z</updated>
    <link href="http://thinkincode.net/2008/4/28/2-cosas-que-acabo-de-aprender-sobre-rake" rel="alternate" type="text/html"/>
    <title>2 cosas que acabo de aprender sobre Rake</title>
<content type="html">
            &lt;ol&gt;
&lt;li&gt;&lt;p&gt;Que si creas una carpera llamada &lt;strong&gt;rakelib&lt;/strong&gt; en el raiz de tu proyecto, rake carga todos los ficheros con la extensión &lt;strong&gt;&lt;em&gt;.rake&lt;/strong&gt;&lt;/em&gt; que encuentre dentro de ella. Con lo que supongo que esta feature no estaba en las primeras versiones porque Rails se está cargando toda la convención de esta librería al hacer esto dentro del fichero &lt;strong&gt;&lt;em&gt;railties/lib/tasks/rails.rb&lt;/strong&gt;&lt;/em&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
Dir[&quot;#{File.dirname(__FILE__)}/*.rake&quot;].each { |ext| load ext }
Dir[&quot;#{RAILS_ROOT}/lib/tasks/**/*.rake&quot;].sort.each { |ext| load ext }
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Que puedes pasarle argumentos a tus tareas. No puede ser una lista variable de argumentos y no pueden tener valor por defecto:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
task :go, :uri, :username, :password do |task, args|
end
&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;
$ rake -T
rake go[uri,username,password]
&lt;/code&gt;&lt;/pre&gt;&lt;/li&gt;
&lt;/ol&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-04-26:59</id>
    <published>2008-04-26T21:19:00Z</published>
    <updated>2008-04-26T21:22:32Z</updated>
    <link href="http://thinkincode.net/2008/4/26/shoes-promete-pero-tampoco-cumple" rel="alternate" type="text/html"/>
    <title>Shoes promete pero tampoco cumple</title>
<content type="html">
            &lt;p&gt;El jueves pasado celebramos en la ofi un &lt;a href='http://11870.com/blog/cronica-del-taller-de-la-api-de-11870com/'&gt;pequeño workshop sobre nuestra api&lt;/a&gt;. Nuestra idea inicial era hacer una pequeña introducción y plantear un par de ejercicios previamente preperados por nosotros para que los asistentes picaran algo de código. Por desgracia, tampoco teníamos demasiado tiempo y al final decidimos exponer los ejercicios y comentar el código que nosotros habíamos escrito.&lt;/p&gt;

&lt;p&gt;Personalmente, mi principal objetivo era dejar muy claro que es muy fácil de usar más allá de lo pone en la documentación y que se pueden hacer más cosas a parte de integraciones de búsqueda de sitios y servicios. &lt;/p&gt;

&lt;p&gt;Como hacía tiempo que quería probar &lt;a href='http://code.whytheluckystiff.net/shoes'&gt;Shoes&lt;/a&gt; decidí hacer una pequeña aplicación que se conectaba con la cuenta de un usuario en 11870.com, se descargaba los últimos servicios que se habían guardado sus contactos y permitía que ese usuario se los guardara y los comentara. Para el que no conozca Shoes decir que es un pequeño framework para escribir pequeñas aplicaciones de escritorio multiplataforma de una forma sencilla. Mientras desarrollaba la aplicación ya me quedó claro que lo de &quot;forma sencilla&quot; ya no era cierto, ya que además de tener una documentación pésima (&lt;a href='http://whytheluckystiff.net'&gt;su autor&lt;/a&gt;, aunque es un desarrollador muy brillante, se dedica a hacer pdfs llenos de dibujitos sin sentido y no explicar como usar sus frameworks), el feedback que te da el framework es inexistente, no muestra excepciones si las hay y creo que tiene una consola de log pero no he encontrado como usarla ni como verla. Como punto final, cuando más o menos tenía la aplicación terminada decidí probarla en mi powerbook, la había desarrollado en mi sobremesa con ubuntu, y por supuesto el resultado fue el esperado después de dos días peleandome con el framework, la aplicación no llegó a arrancar.&lt;/p&gt;

&lt;p&gt;Como tenía una cuenta de github sin estrenar he subido el código fuente ahí por si alguien quiere echarle un vistazo, si usas git simplemente ejecuta este comando:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;
  git clone git://github.com/calavera/oos-with-shoes.git
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;si no, puedes ver el código en &lt;a href='http://github.com/calavera/oos-with-shoes'&gt;el proyecto que he abierto&lt;/a&gt;. &lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-02-22:45</id>
    <published>2008-02-22T21:05:00Z</published>
    <updated>2008-02-25T08:18:16Z</updated>
    <category term="Atom Publishing Protocol"/>
    <link href="http://thinkincode.net/2008/2/22/the-ape-meets-ruby-gems" rel="alternate" type="text/html"/>
    <title>The APE meets RubyGems</title>
<content type="html">
            &lt;p&gt;When I talked about &lt;a href='http://tbray.org/ape'&gt;the ape&lt;/a&gt; in the past &lt;a href='http://thinkincode.net/2007/11/22/atompub-ruby-y-la-api-de-11870-com'&gt;Conferencia Rails 07&lt;/a&gt; I remarked that it wasn't quite easy to install and configure. Today I can announce that this is no longer true.&lt;/p&gt;

&lt;p&gt;We've transformed a lot of scripts in a ruby gem that provides a Mongrel based server. Once the ape gem is installed and this server is running, the web interface is available in the port 4000 of your localhost.&lt;/p&gt;

&lt;pre class='bash'&gt;
&lt;code&gt;
  $ sudo gem install ape &amp;&amp; ape_server
&lt;/code&gt;
&lt;/pre&gt;

&lt;p&gt;Moreover, the &lt;a href='http://rubyforge.org/projects/ape'&gt;new ape gem&lt;/a&gt; uses the &lt;a href='http://www.kuwata-lab.com/erubis/'&gt;erubis&lt;/a&gt; library to load the atom entry templates that it uses to test the atomPub server. These templates can be overrided by the user, the gem searchs the &lt;em&gt;APE_HOME&lt;/em&gt; enviromment variable or the &lt;em&gt;.ape&lt;/em&gt; directory into the user home directory. Within this directory the user can leave his atom entry templates with the names &lt;em&gt;mini_entry.eruby&lt;/em&gt;, &lt;em&gt;basic_entry.eruby&lt;/em&gt; or &lt;em&gt;unclean_xhtml_entry.eruby&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;We are excited with this release and we are working hard to &lt;a href='http://atonie.org/2008/02/ape-test.html'&gt;eliminate possible bugs&lt;/a&gt; and add documentation in addition to new capabilities in order to test any atomPub server behaviour.&lt;/p&gt;

&lt;p&gt;Enjoy it!&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-01-10:32</id>
    <published>2008-01-10T22:47:00Z</published>
    <updated>2008-01-10T22:47:44Z</updated>
    <link href="http://thinkincode.net/2008/1/10/la-charla-de-los-viernes" rel="alternate" type="text/html"/>
    <title>La charla de los viernes</title>
<content type="html">
            &lt;p&gt;Hace unos meses instauramos una costumbre en &lt;a href='http://11870.com/pro/11870'&gt;la ofi&lt;/a&gt;, los viernes un miembro del equipo de tecnología debía dar una charla sobre algún tema que le pareciera interesante. En este tiempo hemos hablado sobre behaviour driven development, atom publishing protocol, amazon s3, python, metodología ágiles...&lt;/p&gt;

&lt;p&gt;Pero como tampoco somos tanta gente, y ya nos estamos quedando sin ideas, hemos decidido abrir nuestras puertas a la gente de la calle. Así, si alguien se encuentra por Madrid un viernes y le apetece pasarse a evangelizarnos sobre algún tema en concreto puede enviarme un correo a &lt;em&gt;david.calavera&lt;/em&gt; arroba &lt;em&gt;11870.com&lt;/em&gt; contando un poquillo de lo que nos quiere hablar y proponiendo una fecha. &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Aclaraciones&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;En principio debería ser un viernes antes de comer, a eso de las 13h (luego podemos organizar un comida familiar), aunque podríamos buscar otro día por la tarde si es imposible ese día. Por problemas de espacio, de momento, no podemos aceptar público externo, aunque podemos hacer alguna excepción.&lt;/p&gt;

&lt;p&gt;Por cierto, mañana tenemos nuestro primer invitado, con una charla muy interesante sobre &lt;a href='http://en.wikipedia.org/wiki/Grid_computing'&gt;grid computing&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2008-01-07:30</id>
    <published>2008-01-07T22:27:00Z</published>
    <updated>2008-01-07T22:49:59Z</updated>
    <category term="Desarrollo"/>
    <category term="Java"/>
    <category term="Ruby on rails"/>
    <link href="http://thinkincode.net/2008/1/7/usa-ruby-para-testear-tu-c&#243;digo-java" rel="alternate" type="text/html"/>
    <title>Usa ruby para testear tu c&#243;digo java</title>
<content type="html">
            &lt;p&gt;Aunque navegando por la web se pueden encontrar artículos sobre cómo usar &lt;a href='http://www.infoq.com/news/2006/11/RSpecOnJRuby'&gt;rspec para testear código java&lt;/a&gt; y ya existe algún &lt;a href='http://jbehave.org'&gt;framework de bdd para java&lt;/a&gt;, desde hace unas semanas existe una librería que nos da las mejores herramentas de test que ruby posee para aplicarlas con nuestro código java.&lt;/p&gt;

&lt;p&gt;&lt;a href='http://jtestr.codehaus.org'&gt;JtestR&lt;/a&gt; es una librería que integra jruby con rspec, dust, mocha y ActiveSuport, y permite ejecutar nuestros test escritos en ruby con herramentas de automatización como Ant o Maven.&lt;/p&gt;

&lt;p&gt;Para ejecutarlos con Ant es tan facil como incluir una nueva tarea en nuestro fichero de configuración:&lt;/p&gt;

&lt;pre class='codeBlock xml'&gt;
&lt;span&gt;&amp;lt;target name=&quot;test&quot; description=&quot;Runs all tests&quot;&amp;gt;&lt;/span&gt;
&lt;span&gt;  &amp;lt;taskdef name=&quot;jtestr&quot; classname=&quot;org.jtestr.ant.JtestRAntRunner&quot; classpath=&quot;lib/jtestr.jar&quot;/&amp;gt;&lt;/span&gt;

&lt;span&gt;  &amp;lt;jtestr tests=&quot;test/ruby&quot;/&amp;gt&lt;/span&gt;
&lt;span&gt;&amp;lt;/target&amp;gt;&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Pero lo que más me gusta de este framework es poder usar rspec para testear mis clases java, un sencillo ejemplo podría ser este:&lt;/p&gt;

&lt;pre class='codeBlock jruby'&gt;
&lt;span&gt;import java.util.HashMap&lt;/span&gt;

&lt;span&gt;describe HashMap, &quot;is empty&quot; do&lt;/span&gt;
&lt;span&gt;  before :each do&lt;/span&gt;
&lt;span&gt;    @map = mock(HashMap)&lt;/span&gt;
&lt;span&gt;  end&lt;/span&gt;

&lt;span&gt;  it &quot;should be empty&quot; do&lt;/span&gt;
&lt;span&gt;    @map.stubs(:size).returns(0)&lt;/span&gt;

&lt;span&gt;    @map.should be_empty&lt;/span&gt;
&lt;span&gt;  end&lt;/span&gt;
&lt;span&gt;end&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Una herramienta a tener en cuenta si, como yo, pasas el día entre código java y código ruby :-).&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2007-12-23:29</id>
    <published>2007-12-23T11:00:00Z</published>
    <updated>2007-12-23T11:53:18Z</updated>
    <category term="Desarrollo"/>
    <category term="Ruby on rails"/>
    <link href="http://thinkincode.net/2007/12/23/bdd-rspec-rulez" rel="alternate" type="text/html"/>
    <title>BDD &amp; RSpec rulez</title>
<content type="html">
            &lt;p&gt;¿Por qué deberías pensar en usar &lt;a href='http://behaviour-driven.org/'&gt;BDD&lt;/a&gt; y &lt;a href='http://rspec.info/'&gt;RSpec&lt;/a&gt;?&lt;/p&gt;

&lt;p&gt;&lt;a href='http://addressable.rubyforge.org/specdoc/'&gt;Un ejemplo vale más que mil palabras&lt;/a&gt;&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2007-11-22:26</id>
    <published>2007-11-22T12:30:00Z</published>
    <updated>2007-11-26T14:55:42Z</updated>
    <category term="Atom Publishing Protocol"/>
    <category term="Ruby on rails"/>
    <link href="http://thinkincode.net/2007/11/22/atompub-ruby-y-la-api-de-11870-com" rel="alternate" type="text/html"/>
    <title>AtomPub, ruby y la api de 11870.com</title>
<content type="html">
            &lt;p&gt;Así se titula la charla que imparto en la segunda conferencia rails. Pretende ser una introducción a atomPub, la api de 11870 y todo esto mezclado con un poco de ruby.&lt;/p&gt;

&lt;p&gt;Ya podéis descargar &lt;a href='http://thinkincode.net/assets/2007/11/21/david-calavera-atomPub-ruby-y-la-api-de-11870.pdf'&gt;la presentación en formato pdf&lt;/a&gt;. Agradezco cualquier comentario, espero que sea útil.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Actualización:&lt;/strong&gt; he subido la presentación a SlideShare para que se pueda ver desde aquí.&lt;/p&gt;

&lt;div&gt;&amp;lt;object height='355' width='425' style='margin:0px'&gt;&amp;lt;param name='movie' value='http://static.slideshare.net/swf/ssplayer2.swf?doc=atompub-ruby-y-la-api-de-11870-1196087387827307-3' /&gt;&amp;lt;param name='allowFullScreen' value='true' /&gt;&amp;lt;param name='allowScriptAccess' value='always' /&gt;&amp;lt;embed allowfullscreen='true' type='application/x-shockwave-flash' src='http://static.slideshare.net/swf/ssplayer2.swf?doc=atompub-ruby-y-la-api-de-11870-1196087387827307-3' allowscriptaccess='always' height='355' width='425'&gt;&amp;lt;/embed&gt;&amp;lt;/object&gt;&lt;div&gt;&lt;a href='http://www.slideshare.net/?src=embed'&gt;&lt;img src='http://static.slideshare.net/swf/logo_embd.png' alt='SlideShare' /&gt;&lt;/a&gt; | &lt;a href='http://www.slideshare.net/calavera/atompub-ruby-y-la-api-de-11870' title='View \'atomPub, ruby y la api de 11870\' on SlideShare'&gt;View&lt;/a&gt; | &lt;a href='http://www.slideshare.net/upload'&gt;Upload your own&lt;/a&gt;&lt;/div&gt;&lt;/div&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2007-11-20:25</id>
    <published>2007-11-20T22:44:00Z</published>
    <updated>2007-11-20T23:19:34Z</updated>
    <category term="Atom Publishing Protocol"/>
    <category term="Ruby on rails"/>
    <link href="http://thinkincode.net/2007/11/20/conferencia-rails-2007" rel="alternate" type="text/html"/>
    <title>Conferencia Rails 2007</title>
<content type="html">
            &lt;p&gt;Este jueves comienza la segunda &lt;a href='http://conferenciarails.org'&gt;Conferencia Rails Hispana&lt;/a&gt;. Este año estaré hablando sobre &lt;a href='http://ietfreport.isoc.org/idref/rfc5023/'&gt;AtomPub&lt;/a&gt;, &lt;a href='http://www.ruby.org'&gt;ruby&lt;/a&gt; y &lt;a href='http://11870.com/api'&gt;la api de 11870.com&lt;/a&gt;. Cuando acabe subiré la presentación aqui para uso y disfrute.
&lt;br /&gt;&lt;br /&gt;&lt;img src='http://thinkincode.net/assets/2007/11/20/ponente.png' alt='ponente' /&gt;&lt;br /&gt;&lt;br /&gt;
Nos vemos allí.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2007-11-02:24</id>
    <published>2007-11-02T23:42:00Z</published>
    <updated>2007-11-03T00:00:23Z</updated>
    <category term="Atom Publishing Protocol"/>
    <category term="Desarrollo"/>
    <category term="Ruby on rails"/>
    <link href="http://thinkincode.net/2007/11/2/rails-plugin-atompubserver" rel="alternate" type="text/html"/>
    <title>Rails plugin: atom_pub_server</title>
<content type="html">
            &lt;p&gt;Coincidiendo con el lanzamiento de la &lt;a href='http://11870.com/blog/11870-libera-su-api'&gt;api de 11870.com&lt;/a&gt; tenía ganas de liberar un plugin para Rails que me ha ayudado a experimentar con &lt;a href='http://www.ietf.org/rfc/rfc5023.txt'&gt;AtomPub&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;Como no soy muy original con los nombres lo he llamado &lt;a href='http://svn.thinkincode.net/rails/plugins/atom_pub_server'&gt;atom_pub_server&lt;/a&gt; y básicamente sirve para empezar a implementar AtomPub dentro de una aplicación desarrollada con Rails. Ya que el punto de entrada del protocolo  es su documento de servicio este plugin sirve para generar un documento de servicio a partir de los controllers de una aplicación. A partir de ahí, y gracias al genial soporte de REST por parte de rails y a alguna de &lt;a href='http://weblog.rubyonrails.org/2007/9/30/rails-2-0-0-preview-release'&gt;las novedades de la versión 2.0&lt;/a&gt; implementar un servidor de Atom Publishing Protocol con una aplicación rails es francamente sencillo.&lt;/p&gt;

&lt;p&gt;Pero para ver como funciona el plugin lo mejor es ver un ejemplo. Empezaremos instalándolo en la aplicación desde el repositorio:&lt;/p&gt;

&lt;pre&gt;
    $script/plugin install http://svn.thinkincode.net/rails/plugins/atom_pub_server
&lt;/pre&gt;

&lt;p&gt;Supongamos que nuestra aplicación tiene dos controllers, uno llamado PostsController y otro llamado ServicesController. El primero será en encargado de gestionar una colección de recursos, así que le añadiremos el siguiente método:&lt;/p&gt;

&lt;pre class='ruby'&gt;
    class PostsController &amp;lt; ApplicationController
      acts_as_collection :title =&gt; 'posts', :workspace =&gt; 'blog',
        :href=&gt; 'http://myblog', :accept =&gt; Mime::ATOM_ENTRY
    ...
&lt;/pre&gt;

&lt;p&gt;Al marcar este primer controlador para que actúe como una colección automáticamente se le añade un filtro anterior a los métodos de crear y actualizar un elemento. El método que invoca el filtro se debe llamar &lt;em&gt;filter_content_type&lt;/em&gt; y los nombres de los métodos sobre los que se ejecuta se pueden configurar como variables de entorno, siendo por defecto &lt;em&gt;create&lt;/em&gt; y &lt;em&gt;update&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;El segundo controlador será el encargado de generar el documento de servicio, así que lo marcaremos como tal:&lt;/p&gt;

&lt;pre class='ruby'&gt;
    class ServicesController &amp;lt; ApplicationController
        acts_as_service_document
    ...
&lt;/pre&gt;

&lt;p&gt;Finalmente, para que el controlador genere el documento de servicio solo tendremos que llamar al método &quot;service_document&quot; que le aporta el plugin dentro de otro de los métodos del controlador:&lt;/p&gt;

&lt;pre class='ruby'&gt;
    def index
      render :xml =&gt; service_document
    end
&lt;/pre&gt;

&lt;p&gt;y nos generará un xml parecido a este:&lt;/p&gt;

&lt;pre class='xml'&gt;
  &amp;lt;service xmlns:atom='http://www.w3.org/2005/Atom' xmlns='http://www.w3.org/2007/app'&amp;gt;
    &amp;lt;workspace&amp;gt;
      &amp;lt;atom:title&amp;gt;blog&amp;lt;/atom:title&amp;gt;
      &amp;lt;collection href='http://myblog'&amp;gt;
          &amp;lt;atom:title&amp;gt;posts&amp;lt;/atom:title&amp;gt;
          &amp;lt;accept&amp;gt;application/atom+xml;type=entry&amp;lt;/accept&amp;gt;
     &amp;lt;/collection&amp;gt;
    &amp;lt;/workspace&amp;gt;
  &amp;lt;/service&gt;
&lt;/pre&gt;

&lt;p&gt;Además, este plugin añade varios tipos Mime necesarios para la cumplir especificación de AtomPub:&lt;/p&gt;

&lt;pre class='ruby'&gt;
    Mime::ATOM_ENTRY == 'application/atom+xml;type=entry'
    Mime::ATOM_SVC == 'application/atomsvc+xml'
    Mime::ATOM_CAT == 'application/atomcat+xml'
&lt;/pre&gt;

&lt;p&gt;Para finalizar, he decidido sobreescribir uno de los nuevos helpers de rails, concretamente el que nos ayuda a escribir documentos Atom. El método original no permite añadir nuevos espacios de nombres siendo su llamada tal que así:&lt;/p&gt;

&lt;pre class='ruby'&gt;
    atom_feed do |feed|
    ...
&lt;/pre&gt;

&lt;p&gt;mientras que con este plugin podríamos escribir:&lt;/p&gt;

&lt;pre class='ruby'&gt;
    atom_feed( 'xmlns:app' =&gt; 'http://www.w3.org/2007/app') do |feed|
    ...
&lt;/pre&gt;

&lt;p&gt;Cabe decir que el método para sobreescribir 'atom_feed' sólo funciona con la versión actual de Rails (2.0RC) y posteriores. En el fichero &lt;a href='http://svn.thinkincode.net/rails/plugins/atom_pub_server/README'&gt;README&lt;/a&gt; del plugin se puede encontrar una documentación mucho más detallada. Cualquier duda, sugerencia o mejora es bienvenida.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2007-04-03:13</id>
    <published>2007-04-03T15:04:00Z</published>
    <updated>2008-03-17T16:35:54Z</updated>
    <category term="Desarrollo"/>
    <category term="Java"/>
    <link href="http://thinkincode.net/2007/4/3/consumir-microformatos-con-xquery" rel="alternate" type="text/html"/>
    <title>Consumir microformatos con XQuery</title>
<content type="html">
            &lt;p&gt;&lt;a href='http://www.w3.org/TR/xquery/'&gt;XQuery&lt;/a&gt; es un lenguaje para hacer consultas bien formadas sobre documentos xml. Combinado con &lt;a href='http://home.ccil.org/~cowan/XML/tagsoup/'&gt;TagSoup&lt;/a&gt;, que permite parsear cualquier documento html como si fuera xml, y un procesador de documentos como &lt;a href='http://dsd.lbl.gov/nux/'&gt;Nux&lt;/a&gt; es muy facil consumir &lt;a href='http://microformats.org'&gt;microformatos&lt;/a&gt; de cualquier web.&lt;/p&gt;

&lt;p&gt;Como supuesto veamos como consumir el &lt;a href='http://microformats.org/wiki/hcard'&gt;hcard&lt;/a&gt; de uno de mis sitios favoritos en 11870, el &lt;a href='http://11870.com/pro/20770'&gt;café Costello&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;XQuery está basado en &lt;a href='http://www.w3.org/TR/xpath'&gt;XPath&lt;/a&gt; pero además nos permite hacer consultas más cercanas al &lt;a href='http://en.wikipedia.org/wiki/Sql'&gt;sql&lt;/a&gt;. La consulta para extraer del dom de un documento xml un elemento cuyo atributo contenga la palabra &lt;em&gt;vcard&lt;/em&gt; podría ser así:&lt;/p&gt;

&lt;pre class='java'&gt;
    String query = &quot;declare namespace xhtml=\&quot;http://www.w3.org/1999/xhtml\&quot;; \n&quot; +
        &quot; for $data in //xhtml:* \n&quot;+
        &quot; where contains($data/@class, \&quot;vcard\&quot;) \n&quot; +
                &quot; return &amp;lt;vcard&gt; { data($data) } &amp;lt;/vcard&gt;&quot;;
&lt;/pre&gt;

&lt;p&gt;Refinandola un poco más podríamos decir que solo queremos mostrar unos cuantos nodos, como los que contengan el nombre, dirección, localidad, provincia y país del sitio:&lt;/p&gt;

&lt;pre class='java'&gt;
    String query = &quot;declare namespace xhtml=\&quot;http://www.w3.org/1999/xhtml\&quot;; \n&quot; +
        &quot;for $data in //xhtml:* \n&quot;+
    &quot; where contains($data/@class, \&quot;vcard\&quot;) \n&quot;+
    &quot; return &amp;lt;vcard&amp;gt; \n&quot; + 
        &quot; &amp;lt;fn&amp;gt; { data($data//xhtml:*[contains(@class, \&quot;fn\&quot;)]) } &amp;lt;/fn&amp;gt;&quot; +
        &quot; &amp;lt;street-address&amp;gt; { data($data//xhtml:*[contains(@class, \&quot;street-address\&quot;)]) } &amp;lt;/street-address&amp;gt;&quot; +
        &quot; &amp;lt;locality&amp;gt; { data($data//xhtml:*[contains(@class, \&quot;locality\&quot;)]) } &amp;lt;/locality&amp;gt;&quot; +
        &quot; &amp;lt;region&amp;gt; { data($data//xhtml:*[contains(@class, \&quot;region\&quot;)]) } &amp;lt;/region&amp;gt;&quot; +
        &quot; &amp;lt;country-name&amp;gt; { data($data//xhtml:*[contains(@class, \&quot;country-name\&quot;)]) } &amp;lt;/country-name&amp;gt;&quot; +
    &quot; &amp;lt;/vcard&amp;gt; &quot;;
&lt;/pre&gt;

&lt;p&gt;Una vez tenemos la consulta, podemos obtener el html haciendo una llamada por &lt;em&gt;get&lt;/em&gt; a la dirección de nuestra página:&lt;/p&gt;

&lt;pre class='java'&gt;
    GetMethod get = new GetMethod(&quot;http://11870.com/pro/20770&quot;); 
    get.setFollowRedirects(true); 

    HttpClient httpClient = new HttpClient();
    httpClient.executeMethod(get); 
    InputStream in = get.getResponseBodyAsStream(); 
&lt;/pre&gt;

&lt;p&gt;Y transformar el html en xml para ejecutar nuestra consulta xquery:&lt;/p&gt;

&lt;pre class='java'&gt;
    XMLReader parser = new org.ccil.cowan.tagsoup.Parser();
    Document doc = new Builder(parser).build(in);
    Nodes results = XQueryUtil.xquery(doc, query);
&lt;/pre&gt;

&lt;p&gt;La variable &lt;em&gt;results&lt;/em&gt; almacenaría el resultado de ejecutar la consulta, donde quedaría un xml parecido a este:&lt;/p&gt;

&lt;pre class='xml'&gt;
    &amp;lt;vcard&amp;gt;
        &amp;lt;fn&amp;gt;Costello Cafe&amp;lt;/fn&amp;gt;
        &amp;lt;street-address&amp;gt;Calle del Caballero de Gracia 10&amp;lt;/street-address&amp;gt;
        &amp;lt;locality&amp;gt;Madrid&amp;lt;/locality&amp;gt;
        &amp;lt;region&amp;gt;Madrid&amp;lt;/region&amp;gt;
        &amp;lt;country-name&amp;gt;España&amp;lt;/country-name&amp;gt;
    &amp;lt;/vcard&amp;gt;
&lt;/pre&gt;

&lt;p&gt;TagSoup facilita bastante la tediosa tarea de parsear un html ya que transforma hasta los documentos peor formados, y con unos conocimientos de xquery las posiblidades son casi infinitas. Todo el código del ejemplo se puede descargar de &lt;a href='http://thinkincode.net/samples/VcardScrape.java'&gt;aqui&lt;/a&gt;.&lt;/p&gt;
          </content>  </entry>
  <entry xml:base="http://thinkincode.net/">
    <author>
      <name>david</name>
    </author>
    <id>tag:thinkincode.net,2007-03-12:11</id>
    <published>2007-03-12T14:08:00Z</published>
    <updated>2007-03-17T14:32:28Z</updated>
    <category term="Desarrollo"/>
    <category term="Ruby on rails"/>
    <link href="http://thinkincode.net/2007/3/12/validando-feeds-contra-el-w3c" rel="alternate" type="text/html"/>
    <title>Validando feeds contra el w3c</title>
<content type="html">
            &lt;p&gt;Ultimamente he pasado demasiado tiempo jugando con los feeds de &lt;a href='http://11870.com'&gt;11870&lt;/a&gt;, pero aunque tengo el proceso de creación bastante trillado y lo he dejado muy DRY nunca está de más validarlos.&lt;/p&gt;

&lt;p&gt;El &lt;a href='http://www.w3c.es/'&gt;w3c&lt;/a&gt; tiene una &lt;a href='http://validator.w3.org/feed/'&gt;web&lt;/a&gt; que te permite validar un feed alojado en una determinada url o pastearle el código que este genera dentro den un textarea. La principal pega es que si tu url es la de tu ordenador de desarrollo no la acepta y tienes que optar por la segunda opción. &lt;/p&gt;

&lt;p&gt;Por suerte se les ocurrió liberar un api para no tener que estar copiando y pegando cada vez que queramos validar un feed que estemos desarrollando. Con esta api me he creado &lt;a href='http://thinkincode.net/samples/feeds_validator.rb'&gt;un script&lt;/a&gt; que indicándole el host y la ruta del feed, lo descarga y lo intenta validar contra el w3c, no es nada del otro mundo y seguro que es muy mejorable pero a mi me ha sido bastante útil.&lt;/p&gt;

&lt;p&gt;Básicamente se trata de recoger el xml que genera el feed con la siguiente instrucción:&lt;/p&gt;

&lt;pre class='ruby'&gt;
&lt;span&gt;@response = Net::HTTP.get_response ARGV[0], ARGV[1], 80&lt;/span&gt;
&lt;/pre&gt;

&lt;p&gt;Y enviarlo al validador:&lt;/p&gt;

&lt;pre class='ruby'&gt;
&lt;span&gt;v = W3C::FeedValidator.new&lt;/span&gt;
&lt;span&gt;v.validate_data @response.body.to_s&lt;/span&gt; 
&lt;/pre&gt;

&lt;p&gt;Una vez hecho esto podremos comprobar si el feed es válido con el método &lt;em&gt;valid?&lt;/em&gt; y acceder a los mensajes a través de las variables &lt;em&gt;errors&lt;/em&gt;, &lt;em&gt;warnings&lt;/em&gt; e &lt;em&gt;informations&lt;/em&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;NOTA&lt;/strong&gt;: El validador del w3c no funciona muy bien y de vez en cuando da algún error al validar, solo hay que insistir un poco hasta que pilla vuestro feed ;)&lt;/p&gt;
          </content>  </entry>
</feed>
