<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type="text/xsl" media="screen" href="/~d/styles/atom10full.xsl"?><?xml-stylesheet type="text/css" media="screen" href="http://feeds.feedburner.com/~d/styles/itemcontent.css"?><feed xmlns="http://www.w3.org/2005/Atom" xmlns:openSearch="http://a9.com/-/spec/opensearch/1.1/" xmlns:georss="http://www.georss.org/georss" xmlns:gd="http://schemas.google.com/g/2005" xmlns:feedburner="http://rssnamespace.org/feedburner/ext/1.0" gd:etag="W/&quot;DEQCQ3c6cSp7ImA9WxNbEk0.&quot;"><id>tag:blogger.com,1999:blog-22641314</id><updated>2009-11-14T05:46:02.919-08:00</updated><title>Clever Title Pending</title><subtitle type="html" /><link rel="http://schemas.google.com/g/2005#feed" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/posts/default" /><link rel="alternate" type="text/html" href="http://seangeo.blogspot.com/" /><link rel="hub" href="http://pubsubhubbub.appspot.com/" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email></author><generator version="7.00" uri="http://www.blogger.com">Blogger</generator><openSearch:totalResults>13</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>25</openSearch:itemsPerPage><link rel="self" href="http://feeds.feedburner.com/CleverTitlePending" type="application/atom+xml" /><atom10:link xmlns:atom10="http://www.w3.org/2005/Atom" rel="hub" href="http://pubsubhubbub.appspot.com" /><entry gd:etag="W/&quot;A0YCQX0_cSp7ImA9WxZaF0Q.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-6633881117310110223</id><published>2008-05-03T00:17:00.000-07:00</published><updated>2008-05-03T00:19:20.349-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-05-03T00:19:20.349-07:00</app:edited><title>rAtom 0.3.5 released</title><content type="html">This is just a maintenance release, nothing too exciting:&lt;div&gt;&lt;br /&gt;&lt;br /&gt;== 0.3.5 2008-05-03&lt;br /&gt;&lt;br /&gt;* Make sure atom:entries appears last.&lt;br /&gt;* Better examples in the documentation.&lt;/div&gt;&lt;div&gt;* Docs for Feed and Entry list attributes.&lt;br /&gt;* Gave Feeds authors and contributors.&lt;br /&gt;* Fixed a couple warnings.&lt;/div&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-6633881117310110223?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/qU3JiR3r4Hc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/6633881117310110223/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=6633881117310110223" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/6633881117310110223?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/6633881117310110223?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/qU3JiR3r4Hc/ratom-035-released.html" title="rAtom 0.3.5 released" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2008/05/ratom-035-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;D0cCRH0ycCp7ImA9WxZbEk8.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-7684957224594894720</id><published>2008-04-14T18:13:00.000-07:00</published><updated>2008-04-14T19:04:25.398-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-14T19:04:25.398-07:00</app:edited><title>Using rAtom in Rails</title><content type="html">Some &lt;a href="http://seangeo.blogspot.com/2008/04/ratom-030-released.html?showComment=1208001480000#c4174573861575860339"&gt;mysterious anonymous person&lt;/a&gt; asked me for a tutorial on using rAtom within Rails.  So I'll show you all how I do it.&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Firstly, the big difference is that I treat it more like ActiveRecord#to_xml instead of like a *.builder view. So I'll start with an example.&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;Assuming you have a blog application with a Post model class, you can add a #to_atom method to your class like this:&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;div&gt;&lt;br /&gt;&lt;/div&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_model"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;Post&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;  &lt;br /&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;  &lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;to_atom&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Atom&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Entry&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|entry|&lt;br /&gt;      entry.title     = &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.title&lt;br /&gt;      entry.updated   = &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.updated_at&lt;br /&gt;      entry.published = &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.created_at&lt;br /&gt;      entry.author    = &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Atom&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Person&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;(&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;name&lt;/span&gt; =&amp;gt; &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.author)&lt;br /&gt;      entry.links    &amp;lt;&amp;lt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Atom&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Link&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;(&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;rel&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;alternate&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;                                    &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;href&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/posts/&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;&lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.id&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;      entry.content   = &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Atom&lt;/span&gt;::&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Content&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Html&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;(&lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.content)&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;  &lt;br /&gt;&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;The advantage of returning a rAtom object here is that the atom representation is then composable, for example if you have a Blog class that has many posts you can do this:&lt;/p&gt;&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_model"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;Blog&lt;span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"&gt; &lt;span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"&gt;&amp;lt;&lt;/span&gt; ActiveRecord::Base&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="support support_function support_function_activerecord support_function_activerecord_rails"&gt;has_many&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;posts&lt;/span&gt;&lt;br /&gt;  &lt;br /&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;  &lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;to_atom&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Atom&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Feed&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt; &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|feed|&lt;br /&gt;      feed.title = &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.title&lt;br /&gt;      feed.links &amp;lt;&amp;lt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Atom&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Link&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;(&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;rel&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;alternate&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;                                &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;href&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/blogs/&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;&lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.id&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;      &lt;br /&gt;      &lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.posts.each &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|post|&lt;br /&gt;        feed.entries &amp;lt;&amp;lt; post.to_atom&lt;br /&gt;      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;To get this atom representation out via HTTP, you would do this in the controller:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_controller"&gt;&lt;span class="meta meta_class meta_class_ruby"&gt;&lt;span class="keyword keyword_control keyword_control_class keyword_control_class_ruby"&gt;class&lt;/span&gt; &lt;span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"&gt;BlogsController&lt;/span&gt;&lt;/span&gt; &amp;lt;&amp;lt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ApplicationController&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;  &lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;show&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;blog&lt;/span&gt; = &lt;span class="support support_class support_class_ruby"&gt;Blog&lt;/span&gt;.find(params[&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;id&lt;/span&gt;])&lt;br /&gt;    respond_to &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|format|&lt;br /&gt;      format.atom {&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="support support_function support_function_actionpack support_function_actionpack_rails"&gt;render&lt;/span&gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;xml&lt;/span&gt; =&amp;gt; &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;blog&lt;/span&gt;.to_atom.to_xml }&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This has been really useful in an application that I am working on because we are using Atom as the main communication format between a bunch of different components, so this composability comes in really handy. For a simple blog it might be overkill, but at least you get the much better performance of libxml-ruby.&lt;br /&gt;&lt;br /&gt;You'll probably notice a bit of ugliness in the to_atom methods, specifically this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_model"&gt;      entry.links    &amp;lt;&amp;lt; &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Atom&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Link&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;(&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;rel&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;alternate&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;br /&gt;                                    &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;href&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/posts/&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;&lt;span class="variable variable_language variable_language_ruby"&gt;self&lt;/span&gt;.id&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;The URL is hard-coded here because url_for is not available in a model.  This is a bit of trade-off between the composability and strict MVC here, if you really wanted to you could pass the URL in as a parameter, or add a block that generates URLs or whatever, it's up to you.  &lt;br /&gt;&lt;br /&gt;For some applications, like a simple blog, the composability might not be too important, and you might prefer the syntax of atom_feed in Rails, or at least want to be able to render the atom in a view.  In this case it would probably be nice to have a rAtom based template format, so you could add a view like "blogs/show.atom.ratom" which allowed you to move the to_atom method into a view and call url_for directly from the view.  I'd like to add this at some stage, but it hasn't happened yet, due to time and priorities, but if anyone would like to submit a patch for it I'd gladly accept it.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-7684957224594894720?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/T9g5Ac0BXH0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/7684957224594894720/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=7684957224594894720" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/7684957224594894720?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/7684957224594894720?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/T9g5Ac0BXH0/using-ratom-in-rails.html" title="Using rAtom in Rails" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2008/04/using-ratom-in-rails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0UCRn8_eSp7ImA9WxZUEU0.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-7477289664041114701</id><published>2008-04-01T18:35:00.000-07:00</published><updated>2008-04-01T18:54:27.141-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-04-01T18:54:27.141-07:00</app:edited><title>rAtom 0.3.0 Released</title><content type="html">&lt;p&gt;I've just release rAtom 0.3.0.  This version adds support for &lt;a href="http://www.atomenabled.org/developers/syndication/atom-format-spec.php#simple.extension.elements"&gt;simple extension elements&lt;/a&gt; and also checks that content is in UTF-8 before serializing to XML.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;As defined in the Atom Syndication Format, simple extension elements consist of XML elements from a non-Atom namespace that have no attributes or child elements, i.e. they are empty or only contain text content.  These elements are treated as a name value pair where the element namespace and local name make up the key and the content of the element is the value, empty elements will be treated as an empty string.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To access extension elements use the [] method on the Feed or Entry. For example, if we are parsing the follow Atom document with extensions:&lt;/p&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class="text text_xml"&gt;&lt;span class="meta meta_tag meta_tag_preprocessor meta_tag_preprocessor_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;lt;?&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_xml"&gt;xml&lt;/span&gt;&lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_xml"&gt; version&lt;/span&gt;=&lt;span class="string string_quoted string_quoted_double string_quoted_double_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_xml"&gt;"&lt;/span&gt;1.0&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_xml"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;?&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_tag meta_tag_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml"&gt;feed&lt;/span&gt; &lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_localname entity_other_attribute-name_localname_xml"&gt;xmlns&lt;/span&gt;=&lt;span class="string string_quoted string_quoted_double string_quoted_double_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_xml"&gt;"&lt;/span&gt;http://www.w3.org/2005/Atom&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_xml"&gt;"&lt;/span&gt;&lt;/span&gt; &lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_namespace entity_other_attribute-name_namespace_xml"&gt;xmlns&lt;/span&gt;&lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_xml"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_namespace punctuation_separator_namespace_xml"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="entity entity_other entity_other_attribute-name entity_other_attribute-name_localname entity_other_attribute-name_localname_xml"&gt;ex&lt;/span&gt;=&lt;span class="string string_quoted string_quoted_double string_quoted_double_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_xml"&gt;"&lt;/span&gt;http://example.org&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_xml"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="meta meta_tag meta_tag_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml"&gt;title&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Feed with extensions&lt;span class="meta meta_tag meta_tag_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml"&gt;title&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;  &lt;span class="meta meta_tag meta_tag_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;lt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_namespace entity_name_tag_namespace_xml"&gt;ex&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_xml"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_namespace punctuation_separator_namespace_xml"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml"&gt;myelement&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;Something important&lt;span class="meta meta_tag meta_tag_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_namespace entity_name_tag_namespace_xml"&gt;ex&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_xml"&gt;&lt;span class="punctuation punctuation_separator punctuation_separator_namespace punctuation_separator_namespace_xml"&gt;:&lt;/span&gt;&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml"&gt;myelement&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="meta meta_tag meta_tag_xml"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="entity entity_name entity_name_tag entity_name_tag_localname entity_name_tag_localname_xml"&gt;feed&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_tag punctuation_definition_tag_xml"&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;We could then access the extension element on the feed using:&lt;/p&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&amp;gt; feed[&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;http://example.org&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;myelement&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;  =&amp;gt; [&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Something important&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Note that the return value is an array. This is because XML allows multiple instances of the element.&lt;/p&gt;&lt;br /&gt;&lt;p&gt;To set an extension element you append to the array:&lt;/p&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&amp;gt; feed[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;http://example.org&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;, &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;myelement&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;] &amp;lt;&amp;lt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Something less important&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;=&amp;gt; [&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Something important&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;Something less important&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;]&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;You can then call to_xml and rAtom will serialize the extension elements into xml.&lt;/p&gt;&lt;br /&gt;&lt;pre class="textmate-source"&gt;&lt;span class="source source_ruby"&gt;&amp;gt; puts feed.to_xml&lt;br /&gt;&amp;lt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;?x&lt;/span&gt;ml version=&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;1.0&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;?&amp;gt;&lt;/span&gt;&lt;br /&gt;&amp;lt;feed xmlns=&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;http://www.w3.org/2005/Atom&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;br /&gt;  &amp;lt;myelement xmlns=&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;http://example.org&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Something&lt;/span&gt; important&amp;lt;/myelement&amp;gt;&lt;br /&gt;  &amp;lt;myelement xmlns=&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;http://example.org&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&amp;gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;Something&lt;/span&gt; less important&amp;lt;/myelement&amp;gt;&lt;br /&gt;&amp;lt;/feed&amp;gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;p&gt;Notice that the output repeats the xmlns attribute for each of the extensions, this is semantically the same the input XML, just a bit ugly.  It seems to be a limitation of the libxml-Ruby API. But if anyone knows a work around I'd gladly accept a patch (or even advice).&lt;/p&gt;&lt;br /&gt;&lt;p&gt;You can get rAtom via gem:&lt;/p&gt;&lt;br /&gt;&lt;p&gt;&lt;code&gt;&amp;gt; gem install ratom&lt;/code&gt;&lt;/p&gt;&lt;br /&gt;&lt;p&gt;or from &lt;a href="http://github.com/seangeo/ratom/tree/master"&gt;Github&lt;/a&gt;.&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-7477289664041114701?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/w9-JE0yAkEE" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/7477289664041114701/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=7477289664041114701" title="2 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/7477289664041114701?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/7477289664041114701?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/w9-JE0yAkEE/ratom-030-released.html" title="rAtom 0.3.0 Released" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">2</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2008/04/ratom-030-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CU4FRH89fSp7ImA9WxZWEE4.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-8595761109705937373</id><published>2008-03-08T19:03:00.000-08:00</published><updated>2008-03-08T19:38:35.165-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2008-03-08T19:38:35.165-08:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="atom" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="gem" /><title>rAtom 0.2.1 Gem released</title><content type="html">rAtom is a Ruby Gem for working with the Atom Syndication Format and the Atom Publishing Protocol (APP).&lt;br /&gt;&lt;br /&gt;rAtom was originally built to support the communication between a number of applications built by Peerworks[http://peerworks.org], via the Atom Publishing protocol.  However, it supports, or aims to support, all the Atom Syndication Format and Publication Protocol and can be used to access Atom feeds or to script publishing entries to a blog supporting APP.&lt;br /&gt;&lt;br /&gt;Features:&lt;br /&gt;&lt;ul&gt;&lt;li&gt;Uses libxml-ruby so it is _much_ faster than a REXML based library.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Uses the libxml pull parser so it has much lighter memory usage.&lt;br /&gt;&lt;/li&gt;&lt;li&gt;Supports RFC 5005 (http://www.ietf.org/rfc/rfc5005.txt) for feed pagination.&lt;br /&gt;&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;You can install via gem using:&lt;br /&gt;&lt;code&gt;# sudo gem install ratom&lt;/code&gt;&lt;br /&gt;&lt;h2&gt;Usage&lt;/h2&gt;To fetch and parse an Atom Feed you can simply:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;feed = Atom::Feed.load_feed(URI.parse("http://example.com/feed.atom"))&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And then iterate over the entries in the feed using:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;feed.each_entry do |entry|&lt;br /&gt; # do cool stuff&lt;br /&gt;end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;To construct a Feed&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;feed = Atom::Feed.new do |feed|&lt;br /&gt; feed.title = "My Cool Feed"&lt;br /&gt; feed.id = "http://example.com/my_feed.atom"&lt;br /&gt; feed.updated = Time.now&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;To output a Feed as XML use to_xml&lt;br /&gt;&lt;pre&gt;&lt;code&gt;&lt;br /&gt;&gt; puts feed.to_xml&lt;br /&gt;&amp;lt;feed xmlns="http://www.w3.org/2005/Atom"&amp;gt;&lt;br /&gt; &amp;lt;title&amp;gt;My Cool Feed&amp;lt;/title&amp;gt;&lt;br /&gt; &amp;lt;id&amp;gt;http://example.com/my_feed.atom&amp;lt;/id&amp;gt;&lt;br /&gt; &amp;lt;updated&amp;gt;2008-03-03T23:19:44+10:30&amp;lt;/updated&amp;gt;&lt;br /&gt;&amp;lt;/feed&amp;gt;&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;Publishing&lt;/h2&gt;To publish to a remote feed using the Atom Publishing Protocol, first you need to create a collection to publish to:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;collection = Atom::Pub::Collection.new(:href =&gt; 'http://example.org/myblog')&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;Then create a new entry:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;entry = Atom::Entry.new do |entry|&lt;br /&gt; entry.title = "I have discovered rAtom"&lt;br /&gt; entry.authors &lt;&lt; name =""&gt; 'A happy developer')&lt;br /&gt; entry.updated = Time.now&lt;br /&gt; entry.id = "http://example.org/myblog/newpost"&lt;br /&gt; entry.content = Atom::Content::Html.new("&amp;lt;p&amp;gt;rAtom lets me post to my blog using Ruby, how cool!&amp;lt;/p&amp;gt;")&lt;br /&gt;end&lt;br /&gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;And publish it to the Collection:&lt;br /&gt;&lt;pre&gt;&lt;code&gt;published_entry = collection.publish(entry)&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;&lt;h2&gt;More Information&lt;/h2&gt;See &lt;a href="http://ratom.rubyforge.org/"&gt;http://ratom.rubyforge.org&lt;/a&gt; for more information.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-8595761109705937373?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/eoj3GI7SSlw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/8595761109705937373/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=8595761109705937373" title="10 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/8595761109705937373?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/8595761109705937373?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/eoj3GI7SSlw/ratom-021-gem-released.html" title="rAtom 0.2.1 Gem released" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">10</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2008/03/ratom-021-gem-released.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkMNRH8zfCp7ImA9WB9SFU4.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-8827410976060723073</id><published>2007-09-26T03:09:00.000-07:00</published><updated>2007-10-04T15:54:55.184-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-10-04T15:54:55.184-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="erlang" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="rake" /><title>Building Erlang with Rake</title><content type="html">I've recently started using Erlang on a project.  This is my first foray into Erlang and I'm using Joe Armstong's new book &lt;a href="http://www.pragmaticprogrammer.com/titles/jaerlang/"&gt;Programming Erlang&lt;/a&gt; as introductory material. It is a great introduction to the language, although I wish it covered more of the OTP.  I suppose there is the &lt;a href="http://www.erlang.org/doc/design_principles/part_frame.html"&gt;OTP Design Principles&lt;/a&gt; guide but sometimes a good paper book written in conversational style is better when you are learning.&lt;br /&gt;&lt;br /&gt;In the book Joe describes building an Erlang project using make and most of the downloadable bits of Erlang code use make too; this makes sense, make is virtually ubiquitous.  However the other components of this project are Ruby on Rails applications and make heavy use of &lt;a href="http://rake.rubyforge.org"&gt;Rake&lt;/a&gt;, so I figure why subject myself to Make when I can use the beautiful Rake.&lt;br /&gt;&lt;br /&gt;Here is my Rakefile for building an Erlang project.&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby"&gt;&lt;span class="meta meta_require meta_require_ruby"&gt;&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;require&lt;/span&gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;rake/clean&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;INCLUDE&lt;/span&gt; = &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;include&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ERLC_FLAGS&lt;/span&gt; = &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;-I&lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;INCLUDE&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt; +warn_unused_vars +warn_unused_import&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;SRC&lt;/span&gt; = &lt;span class="support support_class support_class_ruby"&gt;FileList&lt;/span&gt;[&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;src/*.erl&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;]&lt;br /&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;OBJ&lt;/span&gt; = &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;SRC&lt;/span&gt;.pathmap(&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;%{src,ebin}X.beam&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;CLEAN&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;include&lt;/span&gt;(&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;ebin/*.beam&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;&lt;br /&gt;directory &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;ebin&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;rule &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;.beam&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt; =&amp;gt;  [&lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;%{ebin,src}X.erl&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;] &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|t|&lt;br /&gt;  sh &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;erlc -pa ebin -W &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ERLC_FLAGS&lt;/span&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt; -o ebin &lt;span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"&gt;&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;#{&lt;/span&gt;t.source&lt;span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby"&gt;}&lt;/span&gt;&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;br /&gt;task &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;compile&lt;/span&gt; =&amp;gt; [&lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;ebin&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;] + &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;OBJ&lt;/span&gt;&lt;br /&gt;task &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;default&lt;/span&gt; =&amp;gt; &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;compile&lt;/span&gt;&lt;br /&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This gives you &lt;code&gt;rake compile&lt;/code&gt; which builds all the &lt;code&gt;.erl&lt;/code&gt; files in the &lt;code&gt;src&lt;/code&gt; subdirectory into the &lt;code&gt;.beam&lt;/code&gt; files in the &lt;code&gt;ebin&lt;/code&gt; directory. Files will only be built if they have changes since the last build.  You also get &lt;code&gt;rake clean&lt;/code&gt; which deletes all the &lt;code&gt;.beam&lt;/code&gt; files from the &lt;code&gt;ebin&lt;/code&gt; directory.&lt;br /&gt;&lt;br /&gt;I much prefer this over the equivalent Makefile and it is much easier to extend since you have the full power of Ruby at your disposal.&lt;br /&gt;&lt;br /&gt;Enjoy.&lt;br /&gt;&lt;br /&gt;Update: Fixed bug when compile many files from after clean.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-8827410976060723073?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/HsntSneaMAM" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/8827410976060723073/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=8827410976060723073" title="52 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/8827410976060723073?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/8827410976060723073?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/HsntSneaMAM/building-erlang-with-rake.html" title="Building Erlang with Rake" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">52</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2007/09/building-erlang-with-rake.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A0QDRnw7fCp7ImA9WB5bGEs.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-6281894991469010181</id><published>2007-09-03T17:11:00.000-07:00</published><updated>2007-09-03T18:29:37.204-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-09-03T18:29:37.204-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="activeresource" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><category scheme="http://www.blogger.com/atom/ns#" term="testing" /><title>Testing ActiveResource</title><content type="html">I recently started using &lt;a href="http://bloggingrailsconf.com/articles/2006/06/25/david-heinemeier-hansson-keynote"&gt;ActiveResource&lt;/a&gt; on a project.  ActiveResource is the client side of the REST picture, that is it can consume the REST style web services you get with Rails, think of it as ActiveRecord for HTTP.&lt;br /&gt;&lt;br /&gt;One of the difficult parts of using ActiveResource is testing. You don't want to run it over a real HTTP connection, for one it would significantly slow down your tests and secondly you don't know what horrible side effects it might have.  So you need some way to fake a HTTP connection and HTTP requests and responses.  Enter the HttpMock class.&lt;br /&gt;&lt;br /&gt;HttpMock is a fairly nice class put together by the Rails folk that allows you to register a bunch of request and response pairs for a fake HTTP connection.  When you call a method on an ActiveResource in a test, it calls the HttpMock class instead of trying to create a real connection.  It is fairly easy to use, although there is no documentation the blogging community has come to the &lt;a href="http://www.movesonrails.com/articles/2007/07/04/testing-a-rest-full-activeresource"&gt;rescue&lt;/a&gt;.&lt;br /&gt;&lt;br /&gt;Here is a quick example:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_unit_test"&gt;  &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;matz&lt;/span&gt;  = {&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;id&lt;/span&gt; =&amp;gt; &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;, &lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;name&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;Matz&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt; }.to_xml(&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;root&lt;/span&gt; =&amp;gt; &lt;span class="string string_quoted string_quoted_single string_quoted_single_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;'&lt;/span&gt;person&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;'&lt;/span&gt;&lt;/span&gt;)&lt;br /&gt;  &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ActiveResource&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;HttpMock&lt;/span&gt;.respond_to &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|mock|&lt;br /&gt;    mock.get &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/people/1.xml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"&gt;@&lt;/span&gt;matz&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This creates a request response pair so that when ActiveResource tries to GET /people/1.xml it gets back the xml for the @matz hash.  Pretty simple.&lt;br /&gt;&lt;br /&gt;However there is a problem.  HttpMock is misnamed - HttpMock is a &lt;a href="http://martinfowler.com/articles/mocksArentStubs.html"&gt;stub not a mock&lt;/a&gt;.  But the difference is more than semantic, a mock object, like those provided by the excellent &lt;a href="http://mocha.rubyforge.org"&gt;Mocha&lt;/a&gt; library, will allow you to set expectations on a object. An expectation is like saying "for this test to pass, this method with these arguments must be called on this object".  HttpMock doesn't do that, instead it is just a stub that returns a value when a method is called with a certain argument, there is no verification that the method is actually called.&lt;br /&gt;&lt;br /&gt;To show why this is bad, lets look at the test for resource deletion from the ActiveResource unit tests themselves.&lt;br /&gt;&lt;br /&gt;Firstly, in the setup method we use HttpMock to create response for the delete method used on the "/people/1.xml" path:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_unit_test"&gt;  &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ActiveResource&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;HttpMock&lt;/span&gt;.respond_to &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|mock|&lt;br /&gt;    mock.delete &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/people/1.xml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;200&lt;/span&gt;&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;And here is the test_delete method:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class='linenum'&gt;    1&lt;/span&gt; &lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_unit_test"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;  &lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;test_delete&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;    2&lt;/span&gt;     assert &lt;span class="support support_class support_class_ruby"&gt;Person&lt;/span&gt;.delete(&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;)&lt;br /&gt;&lt;span class='linenum'&gt;    3&lt;/span&gt;     &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ActiveResource&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;HttpMock&lt;/span&gt;.respond_to &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|mock|&lt;br /&gt;&lt;span class='linenum'&gt;    4&lt;/span&gt;       mock.get &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/people/1.xml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;404&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;    5&lt;/span&gt;     &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;br /&gt;&lt;span class='linenum'&gt;    6&lt;/span&gt;     assert_raises(&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ActiveResource&lt;/span&gt;::&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ResourceNotFound&lt;/span&gt;) {&lt;span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"&gt; &lt;/span&gt;&lt;span class="support support_class support_class_ruby"&gt;Person&lt;/span&gt;.find(&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;) }&lt;br /&gt;&lt;span class='linenum'&gt;    7&lt;/span&gt;   &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;So what is happening here?  Firstly on line 2 of the test_delete method we call the Person classes delete method. The delete method is a nice one-liner:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_controller"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;      &lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;delete&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;id, options = {}&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        connection.delete(element_path(id, options))&lt;br /&gt;      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;We can assume here that the the content of the delete method is sending a delete request to "/people/#{id}.xml", that makes sense. The rest of the test_delete method creates a request response pair that returns a 404 error when "/people/1.xml" is requested, all that does is test that ActiveResource::Base.find correctly handles 404.&lt;br /&gt;&lt;br /&gt;So what ensures that the delete method does the right thing, all the test does is ensure that it returns something other than nil or false.  Lets change the method and see if we can break the test.  We'll just return true in the delete method:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_controller"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"&gt;      &lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;delete&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;(&lt;/span&gt;&lt;span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"&gt;id, options = {}&lt;/span&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby"&gt;)&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;        &lt;span class="constant constant_language constant_language_ruby"&gt;true&lt;/span&gt;&lt;br /&gt;      &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;After this change I re-ran the tests and they all passed.  This can't be good. If you can effectively remove the body of a method you are testing and the tests still pass you don't have a very good test.  So how can we fix it? &lt;br /&gt;&lt;br /&gt;Well if HttpMock was truely a mock we could ensure that the HTTP delete method is called on the "/people/1.xml" path.  Fortunately HttpMock stores every request it recieves in a class variable.  So we can check that the request was received with an assertion.  &lt;br /&gt;&lt;br /&gt;Here is a new test_delete:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_unit_test"&gt;&lt;span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"&gt;  &lt;span class="keyword keyword_control keyword_control_def keyword_control_def_ruby"&gt;def&lt;/span&gt; &lt;span class="entity entity_name entity_name_function entity_name_function_ruby"&gt;test_delete&lt;/span&gt;&lt;/span&gt;&lt;br /&gt;    assert &lt;span class="support support_class support_class_ruby"&gt;Person&lt;/span&gt;.delete(&lt;span class="constant constant_numeric constant_numeric_ruby"&gt;1&lt;/span&gt;)&lt;br /&gt;    assert &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ActiveResource&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;HttpMock&lt;/span&gt;.requests.include?(&lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ActiveResource&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;Request&lt;/span&gt;.&lt;span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby"&gt;new&lt;/span&gt;(&lt;span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby"&gt;:&lt;/span&gt;delete&lt;/span&gt;, &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/people/1.xml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;, &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;, {}))&lt;br /&gt;  &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;This one now fails when the body of the delete method is removed and passes when it is put back in, so this way we know that the tests is actually testing the functionality of the method.  However it is a bit ugly isn't it?  It would be nice if HttpMock allowed you to do this:&lt;br /&gt;&lt;br /&gt;&lt;pre class="textmate-source vibrant_ink"&gt;&lt;span class="source source_ruby source_ruby_rails"&gt;&lt;span class="meta meta_rails meta_rails_unit_test"&gt;    &lt;span class="variable variable_other variable_other_constant variable_other_constant_ruby"&gt;ActiveResource&lt;/span&gt;::&lt;span class="support support_class support_class_ruby"&gt;HttpMock&lt;/span&gt;.expects &lt;span class="keyword keyword_control keyword_control_ruby keyword_control_ruby_start-block"&gt;do &lt;/span&gt;|http|&lt;br /&gt;      http.delete &lt;span class="string string_quoted string_quoted_double string_quoted_double_ruby"&gt;&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby"&gt;"&lt;/span&gt;/people/1.xml&lt;span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby"&gt;"&lt;/span&gt;&lt;/span&gt;, {}, &lt;span class="constant constant_language constant_language_ruby"&gt;nil&lt;/span&gt;, &lt;span class="constant constant_numeric constant_numeric_ruby"&gt;200&lt;/span&gt;&lt;br /&gt;    &lt;span class="keyword keyword_control keyword_control_ruby"&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/span&gt;&lt;/pre&gt;&lt;br /&gt;&lt;br /&gt;But I'll leave that for another blog post.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-6281894991469010181?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/-X_G08QGxxc" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/6281894991469010181/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=6281894991469010181" title="3 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/6281894991469010181?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/6281894991469010181?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/-X_G08QGxxc/testing-activeresource.html" title="Testing ActiveResource" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">3</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2007/09/testing-activeresource.html</feedburner:origLink></entry><entry gd:etag="W/&quot;A04BRX86eip7ImA9WB5TFEs.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-757702374302679940</id><published>2007-05-28T18:41:00.000-07:00</published><updated>2007-05-29T13:19:14.112-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2007-05-29T13:19:14.112-07:00</app:edited><category scheme="http://www.blogger.com/atom/ns#" term="ruby" /><category scheme="http://www.blogger.com/atom/ns#" term="rails" /><category scheme="http://www.blogger.com/atom/ns#" term="code" /><title>Index Ruby Objects by an Attribute</title><content type="html">&lt;code&gt;&lt;pre&gt;&lt;br /&gt;class Array&lt;br /&gt;  def hash_by(attribute)&lt;br /&gt;    self.inject({}) do |hash, e|&lt;br /&gt;      hash[e.send(attribute)] = e&lt;br /&gt;      hash&lt;br /&gt;    end&lt;br /&gt;  end&lt;br /&gt;end&lt;br /&gt;&lt;/pre&gt;&lt;/code&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-757702374302679940?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/xkT0HrQtgOA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/757702374302679940/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=757702374302679940" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/757702374302679940?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/757702374302679940?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/xkT0HrQtgOA/index-ruby-objects-by-attribute.html" title="Index Ruby Objects by an Attribute" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2007/05/index-ruby-objects-by-attribute.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C04FRX0_fip7ImA9WBJVEUg.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-114615158984995050</id><published>2006-04-27T07:56:00.000-07:00</published><updated>2006-04-27T08:31:54.346-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2006-04-27T08:31:54.346-07:00</app:edited><title>Why GET should always be idempotent: A lesson from Del.icio.us and Sage</title><content type="html">This evening I downloaded &lt;a href="http://sage.mozdev.org"&gt;Sage&lt;/a&gt;, a RSS/Atom feed reader extension for &lt;a href="http://www.getfirefox.com"&gt;Firefox&lt;/a&gt;.  It is quite a nice feed reader and a big improvement over Firefox's Live Bookmarks which I find hard to use with lots of feeds and IMO over Google's Personalised Homepage which I find doesn't scale too well with lots of feeds and doesn't provide previews of the content.&lt;br /&gt;&lt;br /&gt;Sage had a particularly cool feature that jumped out at me, the 'Discover Feeds' feature.  This allows you to find all the feeds referenced in a page, rather than just the feed in a link tag in the header.  It seems that what it does is follow links that may be potential feeds and checks if they are.  You then get a list of all the feeds in the page and can add them to your 'watched' feeds in Sage.&lt;br /&gt;&lt;br /&gt;This got me thinking, since I use alot of different computers it is pain trying to manage my list of feeds on each computer, exporting them and copying them around is just asking to get them out of sync and frankly too much effort. ;) So since I already have a &lt;a href="http://del.icio.us"&gt;Del.icio.us&lt;/a&gt; account where I keep my bookmarks I could bookmark all the feeds I care about and tag them with 'feed' in Del.icio.us.  Then I just need to navigate to the page for the 'feed' tag click on the Discover Feeds button in Sage and all my bookmarked feeds are there to be added to Sage! Yay online storage of feed links that can easily be added to my feed reader of choice from any computer!!!&lt;br /&gt;&lt;br /&gt;Or so I thought.  It just so happens that the Delicious 'Delete Bookmark' link is one of the links that Sage follows when it searches for feeds.  This has the unfortunate side effect of deleting all my bookmarks in the feed tag.  The ideal fix is that Delicious delete action needs to be changed to only respond to a HTTP POST method. This would be comformant with &lt;a href="http://www.w3.org/2001/tag/doc/whenToUseGet.html"&gt;W3C Recommandations&lt;/a&gt; too.&lt;br /&gt;&lt;br /&gt;I've submitted this bug to Delicious but for now the dream of online bookmarking of feeds to be accessed by Sage remains elusive.&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Tags: &lt;a href="http://technorati.com/tag/Delicious" rel="tag"&gt;Delicious&lt;/a&gt; &lt;a href="http://technorati.com/tag/HTTP" rel="tag"&gt;HTTP&lt;/a&gt; &lt;a href="http://technorati.com/tag/Firefox" rel="tag"&gt;Firefox&lt;/a&gt; &lt;a href="http://technorati.com/tag/Blogs" rel="tag"&gt;Blogs&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-114615158984995050?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/-cmzbdPSdvs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/114615158984995050/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=114615158984995050" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114615158984995050?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114615158984995050?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/-cmzbdPSdvs/why-get-should-always-be-idempotent.html" title="Why GET should always be idempotent: A lesson from Del.icio.us and Sage" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2006/04/why-get-should-always-be-idempotent.html</feedburner:origLink></entry><entry gd:etag="W/&quot;C0YCQ388eCp7ImA9WBJWGEs.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-114586015704996827</id><published>2006-04-23T23:13:00.000-07:00</published><updated>2006-04-23T23:46:02.170-07:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2006-04-23T23:46:02.170-07:00</app:edited><title>Calling Web Services From Rails</title><content type="html">I've notice a &lt;a href="http://www.leonsays.com/2006/04/23/can-ruby-on-rails-consume-web-services/"&gt;few&lt;/a&gt; &lt;a href="http://www.leonsays.com/2006/04/23/can-ruby-on-rails-consume-web-services/"&gt;places&lt;/a&gt; where people have asked whether &lt;a href="http://www.rubyonrails.com"&gt;Ruby On Rails&lt;/a&gt; supports the consumption of web services.  Rails itself doesn't. I have found the easiest thing to use is &lt;a href="http://dev.ctor.org/soap4r"&gt;SOAP4R&lt;/a&gt;, which according to its web page comes bundled with Ruby 1.8.3 and above.&lt;br /&gt;&lt;br /&gt;SOAP4R is really easy to use, it simply generates Ruby stubs from a WSDL which will call the web service for you.  You just call the stubs as though they were a Ruby API.&lt;br /&gt;&lt;br /&gt;If you have ever used any Java or .NET web service clients, it is pretty much the exact same concept.&lt;br /&gt;&lt;br /&gt;Tags: &lt;a href="http://technorati.com/tags/SOAP" rel="tag"&gt;SOAP&lt;/a&gt; &lt;a href="http://technorati.com/tags/Web+Services" rel="tag"&gt;Web Services&lt;/a&gt; &lt;a href="http://technorati.com/tags/Rails" rel="tag"&gt;Rails&lt;/a&gt; &lt;a href="http://technorati.com/tags/Ruby" rel="tag"&gt;Ruby&lt;/a&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-114586015704996827?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/Hz9t_dLCcFw" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/114586015704996827/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=114586015704996827" title="1 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114586015704996827?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114586015704996827?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/Hz9t_dLCcFw/calling-web-services-from-rails.html" title="Calling Web Services From Rails" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">1</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2006/04/calling-web-services-from-rails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;Ak4CSH49fip7ImA9WBJSGUk.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-114194896905442664</id><published>2006-03-09T15:56:00.000-08:00</published><updated>2006-03-09T16:02:49.066-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2006-03-09T16:02:49.066-08:00</app:edited><title>Javascript Graph Visualisation</title><content type="html">I just found this new &lt;a href="http://aslakhellesoy.com/articles/tag/canvas"&gt;graphing library&lt;/a&gt; for Javascript.  I've been looking for something that does this for a while so I can visualise relationships represented in RDF.  The last thing I was looking at was &lt;a href="http://www.foafnaut.org"&gt;Foafnaut&lt;/a&gt; which doesn't seem to be very active and only supports foaf information.&lt;br /&gt;&lt;br /&gt;This Javascript library looks really promising though since you should be able update the graph using Ajax which would be really cool.  It's just in the beginning stages now but I'll definately be keeping an eye on it.&lt;br /&gt;&lt;p&gt;Technorati: &lt;a href="http://www.technorati.com/tag/semantic+web" rel="tag"&gt;semantic web&lt;/a&gt; &lt;a href="http://www.technorati.com/tag/Javascript" rel="tag"&gt;Javascript&lt;/a&gt; &lt;a href="http://www.technorati.com/tag/RDF" rel="tag"&gt;RDF&lt;/a&gt; &lt;a href="http://www.technorati.com/tag/Canvas" rel="tag"&gt;Canvas&lt;/a&gt; &lt;a href="http://www.technorati.com/tag/SVG" rel="tag"&gt;SVG&lt;/a&gt; &lt;a href="http://www.technorati.com/tag/Firefox" rel="tag"&gt;Firefox&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-114194896905442664?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/xABhAgcgAQs" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/114194896905442664/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=114194896905442664" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114194896905442664?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114194896905442664?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/xABhAgcgAQs/javascript-graph-visualisation.html" title="Javascript Graph Visualisation" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2006/03/javascript-graph-visualisation.html</feedburner:origLink></entry><entry gd:etag="W/&quot;DkQFQXg8eyp7ImA9WBJTE0g.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-114035209879596102</id><published>2006-02-19T04:01:00.000-08:00</published><updated>2006-02-19T05:05:10.673-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2006-02-19T05:05:10.673-08:00</app:edited><title>Active Ontology for Ruby on Rails</title><content type="html">Obie Fernandaz has some &lt;a href="http://jroller.com/page/obie?entry=more_about_ontologies"&gt;ideas&lt;/a&gt; for a Ontology based &lt;a href="http://wiki.rubyonrails.org/rails/pages/ActiveRecord"&gt;ActiveRecord&lt;/a&gt; alternative.&lt;br /&gt;&lt;br /&gt;This is a really interesting idea, something I've also been thinking about for a while. One of the tricky things in doing this would be determining what properties a class has.  In a RDBMS table you declare that a table (class) has a number of columns (attributes) the mapping to an object model is fairly obvious.&lt;br /&gt;&lt;br /&gt;However with &lt;a href="http://www.w3.org/TR/owl-features/"&gt;OWL&lt;/a&gt; and &lt;a href="http://www.w3.org/RDF/"&gt;RDF&lt;/a&gt; you declare a class and you declare properties, however properties are independant of classes.  You can, in RDFS, say that a property has the domain of a specific class, which means that if a Resource has that property it is a member of that class.  This is different to RDBMS/OO land where you declare that a class has a property.  The difference is subtle but important as it allows you to say things like:&lt;br /&gt;&lt;ol&gt;&lt;li&gt;There is a Employee class.&lt;/li&gt;&lt;li&gt;There is a Manager class which is a subclass of Employee.&lt;/li&gt;&lt;li&gt;There is a manages property that has domain Manager.&lt;/li&gt;&lt;li&gt;We can then infer that the manages property also has Employee as its domain since all Managers and Employees. (Note that this the opposite of OO where properties and inherited down the class heirarchy).&lt;br /&gt;&lt;/li&gt;&lt;li&gt;We can then create an instance of Employee.  It is valid to give that Employee a manages property pointing at another Employee instance. We can then infer that the Employee is also a manager.&lt;/li&gt;&lt;/ol&gt;When you want to map this to OO though, which class gets the manages property?  It is correct to give it Employee since we infered that Employee is a valid domain for manages.  &lt;span style="font-weight: bold;"&gt;Except any Employee who manages someone is a Manager too.  &lt;/span&gt;&lt;br /&gt;&lt;br /&gt;This is one of the tricky things that will arise out of the differences between Ontologies and OO.  A couple of the others are multiple inheritence and multiple class membership.&lt;br /&gt;&lt;br /&gt;Most of these issues could be worked out after the initial functionality is there, but it should interesting to see how they are tackled.&lt;br /&gt;&lt;br /&gt;&lt;span style="font-weight: bold;"&gt;Update: &lt;/span&gt;Man I really need to look at dates before I respond to blogs.&lt;br /&gt;&lt;p&gt;Technorati: &lt;a href="http://www.technorati.com/tag/semantic+web" rel="tag"&gt;semantic web&lt;/a&gt;, &lt;a href="http://www.technorati.com/tag/Rails" rel="tag"&gt;Rails&lt;/a&gt; &lt;a href="http://www.technorati.com/tag/Ruby" rel="tag"&gt;Ruby&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-114035209879596102?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/Fuv8exXWJxA" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/114035209879596102/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=114035209879596102" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114035209879596102?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114035209879596102?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/Fuv8exXWJxA/active-ontology-for-ruby-on-rails.html" title="Active Ontology for Ruby on Rails" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2006/02/active-ontology-for-ruby-on-rails.html</feedburner:origLink></entry><entry gd:etag="W/&quot;AkcCRng8eyp7ImA9WBJTE08.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-114032772616665027</id><published>2006-02-18T21:31:00.000-08:00</published><updated>2006-02-18T21:47:47.673-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2006-02-18T21:47:47.673-08:00</app:edited><title>RDF Schema Generator</title><content type="html">I've release my first &lt;a href="http://www.rubyonrails.com"&gt;Rails&lt;/a&gt; generator on &lt;a href="http://rubyforge.org"&gt;Ruby Forge&lt;/a&gt;.  &lt;a href="http://rubyforge.org/projects/rdfsgen/"&gt;RDF Schema Generator&lt;/a&gt; builds a Ruby Module from an RDFS file.  The module contains constants for each of the properties and classes in the Schema. If you are using Rails to build RDF based applications you might find it useful.&lt;br /&gt;&lt;br /&gt;Install it using &lt;code&gt;gem install rdf_schema_generator&lt;/code&gt;.&lt;br /&gt;&lt;br /&gt;Once it is installed you can run &lt;blockquote&gt;&lt;code&gt;ruby script/generate rdf_schema &amp;lt;prefix&amp;gt; &amp;lt;rdfs_url&amp;gt;&lt;/code&gt;&lt;/blockquote&gt; and a class called &lt;prefix&gt; will be generated in the lib directory containing a module with all the classes and properties for the RDFS file retreived from &amp;lt;rdfs_url&amp;gt;.&lt;br /&gt;&lt;br /&gt;Enjoy!&lt;br /&gt;&lt;br /&gt;&lt;br /&gt;&lt;p&gt;Tags: &lt;a href="http://technorati.com/blogs/Ruby" rel="tag directory"&gt;Ruby&lt;/a&gt; &lt;a href="http://technorati.com/blogs/Rails" rel="tag directory"&gt;Rails&lt;/a&gt; &lt;a href="http://technorati.com/blogs/RDF" rel="tag directory"&gt;RDF&lt;/a&gt;&lt;/p&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-114032772616665027?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/8etgKrSG4D0" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/114032772616665027/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=114032772616665027" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114032772616665027?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114032772616665027?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/8etgKrSG4D0/rdf-schema-generator.html" title="RDF Schema Generator" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2006/02/rdf-schema-generator.html</feedburner:origLink></entry><entry gd:etag="W/&quot;CUYHSHgzeyp7ImA9WBJTEko.&quot;"><id>tag:blogger.com,1999:blog-22641314.post-114027313967598705</id><published>2006-02-18T06:26:00.000-08:00</published><updated>2006-02-18T06:32:19.683-08:00</updated><app:edited xmlns:app="http://www.w3.org/2007/app">2006-02-18T06:32:19.683-08:00</app:edited><title>First Post</title><content type="html">Well, this is my first ever blog post.&lt;br /&gt;&lt;br /&gt;By way of introduction - my name is Sean Geoghegan,  I'm a geek, I work as a computer programmer.  I'm currently into &lt;a href="http://www.rubyonrails.com"&gt;Ruby on Rails&lt;/a&gt; and really want to write a Rails based web application in the guise of &lt;a href="http://www.flickr.com"&gt;flickr&lt;/a&gt; or &lt;a href="http://www.43things.com"&gt;43things&lt;/a&gt; that becomes hugely popular, I just need an idea, if you have one post it in a comment.&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/22641314-114027313967598705?l=seangeo.blogspot.com'/&gt;&lt;/div&gt;&lt;img src="http://feeds.feedburner.com/~r/CleverTitlePending/~4/kSWQwLBASVY" height="1" width="1"/&gt;</content><link rel="replies" type="application/atom+xml" href="http://seangeo.blogspot.com/feeds/114027313967598705/comments/default" title="Post Comments" /><link rel="replies" type="text/html" href="https://www.blogger.com/comment.g?blogID=22641314&amp;postID=114027313967598705" title="0 Comments" /><link rel="edit" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114027313967598705?v=2" /><link rel="self" type="application/atom+xml" href="http://www.blogger.com/feeds/22641314/posts/default/114027313967598705?v=2" /><link rel="alternate" type="text/html" href="http://feedproxy.google.com/~r/CleverTitlePending/~3/kSWQwLBASVY/first-post.html" title="First Post" /><author><name>Sean Geoghegan</name><uri>http://www.blogger.com/profile/00647947610695016991</uri><email>noreply@blogger.com</email><gd:extendedProperty name="OpenSocialUserId" value="00683068210945311782" /></author><thr:total xmlns:thr="http://purl.org/syndication/thread/1.0">0</thr:total><feedburner:origLink>http://seangeo.blogspot.com/2006/02/first-post.html</feedburner:origLink></entry></feed>
