<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <title>Edd Dumbill's Weblog: 'ruby' articles</title>
  <link href="http://times.usefulinc.com/tagrubyatom" rel="self"/>
  <link href="http://times.usefulinc.com/tagruby" rel="alternate"/>
  <id>http://times.usefulinc.com/</id>
  <updated>2008-01-12T13:49:42Z</updated>
  <author>
    <name>Edd Dumbill</name>
    <email>edd-web@usefulinc.com</email>
  </author>
  <entry>
    <title>Telling stories with RSpec</title>
    <link href="http://times.usefulinc.com/2008/01/12-rspec-stories" rel="alternate"/>
    <id>http://times.usefulinc.com/public/read/906</id>
    <updated>2008-01-12T13:49:42Z</updated>
    <published>2008-01-12T13:14:43Z</published>
    <summary>Using RSpec's Story runner to describe integration testing for Rails applications.</summary>
    <category term="software"/>
    <category term="rails"/>
    <category term="ruby"/>
    <category term="agile"/>
    <content type="html">
         &lt;p&gt;For a while now I've been writing &lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; specifications to test &lt;a href="http://expectnation.com/"&gt;Expectnation&lt;/a&gt;, rather than &amp;quot;traditional&amp;quot; Rails unit tests. Although I don't completely get the Behaviour Driven Development hype around RSpec, I do find that it helps in writing more literate and maintainable test suites.&lt;/p&gt;                 &lt;p&gt;Until very recently, however, &lt;a href="http://rspec.info/documentation/rails/index.html"&gt;RSpec for Rails&lt;/a&gt; had no decent answer to Rails' &lt;a href="http://www.oreillynet.com/pub/a/ruby/2008/01/02/cookin-with-ruby-on-rails---integration-tests.html"&gt;integration tests&lt;/a&gt;. Integration tests enable the testing of compete scenarios, as opposed to the specific testing of methods or single HTTP operations that unit and functional testing provide.&lt;/p&gt;  &lt;p&gt;For instance, our integration test suite for Expectnation tests things such as &amp;quot;a user tries to submit a proposal, is redirected to the account sign up page, signs up, and then is redirected to the proposal submission page&amp;quot;. This involves multiple steps, and the whole suite of tests necessitates a lot of reuse.&lt;/p&gt;                 &lt;p&gt;The need for reuse resulted in trying to construct a &lt;a href="http://en.wikipedia.org/wiki/Domain-specific_programming_language"&gt;DSL&lt;/a&gt;-like set of methods for each step, such as &amp;quot;user logs in with email X and password Y&amp;quot;. It has gotten a bit tangled, especially when looking at test failures to see what's really gone wrong.&lt;/p&gt;      &lt;div style="text-align: center"&gt;&lt;img width="160" height="240" src="/asset/name/41/2098453701_9a8d1e9f19_m.jpg" alt="Tangled wires" /&gt;&lt;br /&gt;    &lt;br /&gt;   &lt;em&gt;After a while, unravelling the test suite starts to feel like unpacking Christmas lights.  (Photo: &lt;a href="http://flickr.com/photos/leecullivan/2098453701/"&gt;shoothead&lt;/a&gt;)&lt;/em&gt; &lt;/div&gt;                        &lt;h3&gt;RSpec Story Framework&lt;/h3&gt;           &lt;p&gt;My problems with integration tests made the Story Framework, newly available in RSpec 1.1, look very interesting. Based around plain text descriptions of application behaviour, it lets you write integration tests with good reuse and good diagnostic reporting.&lt;/p&gt;                 &lt;p&gt;For example, here's a story I wrote to check the login process.&lt;/p&gt;             &lt;p&gt;Story: login as an existing user&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; As an unauthenticated user&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; I want to log in to Expectnation&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; So I can see my account details&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; &lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Scenario: login details are correct&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Given an event provider&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; And my test@example.org account&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; When I log in with email test@example.org and password foofoo&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; Then I will be logged in&lt;br /&gt;       &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; And I will be shown the account page&lt;/p&gt;            &lt;p&gt;The words such as &amp;quot;Given&amp;quot;, &amp;quot;When&amp;quot; and &amp;quot;Then&amp;quot; are cues to the story runner to execute some code. Behind the story sits a collection of steps. Here's a couple of steps from this test:&lt;/p&gt;           &lt;p&gt;&amp;nbsp; Given &amp;quot;my $email account&amp;quot; do |email|&lt;br /&gt;      &amp;nbsp;&amp;nbsp;&amp;nbsp; @user = find_or_create_user_by_email({:email =&amp;gt; email,&lt;br /&gt;      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; :password =&amp;gt; 'foofoo',&lt;br /&gt;      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; :password_confirmation =&amp;gt; 'foofoo'})&lt;br /&gt;      &amp;nbsp; end&lt;/p&gt;          &lt;p&gt;&amp;nbsp; When &amp;quot;I log in with email $email and&lt;br /&gt;      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; password $password&amp;quot; do |email, password|&lt;br /&gt;      &amp;nbsp;&amp;nbsp;&amp;nbsp; post '/user/account/authenticate',&lt;br /&gt;      &amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp;&amp;nbsp; :user =&amp;gt; {:email =&amp;gt; email, :password =&amp;gt; password}&lt;br /&gt;      &amp;nbsp; end&lt;/p&gt;          &lt;p&gt;Notice how a clever bit of string matching allows you to pass parameters from the story prose. &lt;br /&gt;      &lt;/p&gt;           &lt;p&gt;With a small bit of bolting together, the prose stories are then run as code and the tests executed. One nice touch is that if you write a story which doesn't yet have code behind it, it is marked not as a pass or fail, but as pending, which means you can sit down and write all your stories and then get to coding the steps later. This beats writing empty tests which transparently pass.&lt;/p&gt;           &lt;p&gt;To conclude, the RSpec Story Framework offers these advantages over Rails' integration tests:&lt;/p&gt;           &lt;ul&gt;      &lt;li&gt;Text-only stories makes it very easy to write and understand tests&lt;/li&gt;           &lt;li&gt;The construction of steps for each line makes it easy and maintainable to construct reusable components for the tests&lt;/li&gt;      &lt;/ul&gt;      &lt;h3&gt;Further reading&lt;/h3&gt;      &lt;ul&gt;      &lt;li&gt;&lt;a href="http://rspec.info/"&gt;RSpec&lt;/a&gt; web site&lt;/li&gt;           &lt;li&gt;&lt;a href="http://jbehave.org/"&gt;JBehave&lt;/a&gt; for Java, of which RSpec's Story Framework is a port&lt;/li&gt;           &lt;li&gt;&lt;a href="http://behaviour-driven.org/"&gt;Behaviour-Driven Development&lt;/a&gt;&lt;/li&gt;      &lt;/ul&gt;      &lt;p&gt;&lt;a href="http://times.usefulinc.com/2008/01/12-rspec-stories#disqus_thread"&gt;Join the conversation about this post&lt;/a&gt;&lt;/p&gt;    </content>
  </entry>
  <entry>
    <title>GObject subclassing in Ruby</title>
    <link href="http://times.usefulinc.com/2006/01/31-subclass" rel="alternate"/>
    <id>http://times.usefulinc.com/public/read/840</id>
    <updated>2006-01-31T20:23:24Z</updated>
    <published>2006-01-31T20:05:57Z</published>
    <summary>An update to yesterday's Ruby GNOME adventures.</summary>
    <category term="ruby"/>
    <category term="gnome"/>
    <category term="mono"/>
    <content type="html">
 &lt;p&gt;Thanks to everybody who wrote in with suggestions following on from my initial &lt;a href="http://times.usefulinc.com/2006/01/30-ruby-gnome"&gt;Ruby GNOME investigations&lt;/a&gt; yesterday.&lt;/p&gt; &lt;p&gt;After talking at cross purposes for some time in a bug report with a Ruby GNOME developer, I was pointed to a good example of how to do what I wanted: subclassing a GObject in Ruby.&lt;/p&gt; &lt;p&gt;This is something that the Mono Gtk# bindings do so well, I'd forgotten the required mechanics. Here's a simple subclass of button. I've highlighted the required magic in bold.&lt;br /&gt; &lt;/p&gt; &lt;pre&gt;class MyButton &amp;lt; Gtk::Button&lt;br /&gt;   attr_accessor :hitcount&lt;br /&gt; &lt;strong&gt;  # tell the GLib object system this is a new type&lt;br /&gt;   type_register&lt;br /&gt; &lt;/strong&gt;&lt;br /&gt;   def initialize(text)&lt;br /&gt;     super(&amp;quot;label&amp;quot; =&amp;gt; text)&lt;br /&gt;     self.hitcount = 0&lt;br /&gt;   end&lt;br /&gt; &lt;br /&gt; &lt;strong&gt;  # rather than overriding 'clicked', we must&lt;br /&gt;   # override the signal_do_clicked method&lt;br /&gt;   def signal_do_clicked(*args)&lt;br /&gt; &lt;/strong&gt;    self.hitcount+=1&lt;br /&gt;     super&lt;br /&gt;   end&lt;br /&gt; end&lt;/pre&gt; &lt;p&gt;The &lt;em&gt;type_register&lt;/em&gt; call registers the new class with the GLib type system (something the Mono bindings do for you automatically).&amp;nbsp; The second key was knowing the name of the default signal handler, which turns out to be of the form &lt;em&gt;signal_do_signalname&lt;/em&gt;.&lt;/p&gt; &lt;p&gt;So, to follow up yesterday, I hadn't found a bug, merely a gap in the documentation. Thanks to  					Masao Mutoh for taking the time to answer my questions.&lt;/p&gt; &lt;p&gt;For comparison, here's the same implementation in Gtk#. There are pros and cons of both languages. Ruby's succinct &lt;em&gt;attr_accessor&lt;/em&gt; is balanced by the neat GObject-aware subclassing and the constructor inheritance of C#.&lt;br /&gt; &lt;/p&gt;  &lt;pre&gt;class MyButton : Button {&lt;br /&gt;        private int hitcount;&lt;br /&gt;&lt;br /&gt;        public MyButton (string text) : base (text)&lt;br /&gt;        {&lt;br /&gt;                hitcount = 0;&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        protected override void OnClicked ()&lt;br /&gt;        {&lt;br /&gt;                hitcount++;&lt;br /&gt;                base.OnClicked ();&lt;br /&gt;        }&lt;br /&gt;&lt;br /&gt;        public int HitCount {&lt;br /&gt;                get&lt;br /&gt;                {&lt;br /&gt;                        return hitcount;&lt;br /&gt;                }&lt;br /&gt;                set&lt;br /&gt;                {&lt;br /&gt;                        hitcount = value;&lt;br /&gt;                }&lt;br /&gt;        }&lt;br /&gt;} &lt;/pre&gt; &lt;p&gt;&lt;a href="http://times.usefulinc.com/2006/01/31-subclass#disqus_thread"&gt;Join the conversation about this post&lt;/a&gt;&lt;/p&gt;    </content>
  </entry>
  <entry>
    <title>Beginnings with Ruby GNOME</title>
    <link href="http://times.usefulinc.com/2006/01/30-ruby-gnome" rel="alternate"/>
    <id>http://times.usefulinc.com/public/read/839</id>
    <updated>2006-01-31T02:37:24Z</updated>
    <published>2006-01-30T23:56:00Z</published>
    <summary>My first experiments with writing small GNOME applications in Ruby.</summary>
    <category term="ruby"/>
    <category term="gnome"/>
    <content type="html">
  &lt;p&gt;A while back I started porting the GTK &lt;a href="http://examples.oreilly.com/monoadn/"&gt;examples&lt;/a&gt; from &lt;a href="http://www.oreilly.com/catalog/monoadn/"&gt;Mono: A Developer's Notebook&lt;/a&gt; to IronPython and Boo, the r&lt;a href="http://svn.usefulinc.com/svn/repos/trunk/ironpython/monodn/"&gt;esults of which are available in my Subversion repository&lt;/a&gt;.&lt;/p&gt;   &lt;p&gt;Although I've not finished that task yet, I thought I'd investigate the state of the &lt;a href="http://ruby-gnome2.sourceforge.jp/"&gt;Ruby GNOME bindings&lt;/a&gt; by porting those same examples. They have the advantage of increasing gently in complexity.&lt;/p&gt;   &lt;p&gt;Before I go on, you can find the work in progress posted in the &lt;a href="http://svn.usefulinc.com/svn/repos/trunk/ruby-gnome/monodn/"&gt;ruby-gnome/monodn branch of my Subversion repository&lt;/a&gt;.&lt;/p&gt;   &lt;p&gt;Now for a few observations. At the basic level, Ruby GNOME has a lot in common with all the other GNOME bindings out there. One distinguishing feature however is signal handlers, which take a Ruby closure as an argument. Look at this handler for closing the window, for example:&lt;/p&gt;   &lt;pre&gt;w = Gtk::Window.new(&amp;quot;My Window&amp;quot;)&lt;br /&gt;w.signal_connect(&amp;quot;delete_event&amp;quot;) { Gtk.main_quit } &lt;/pre&gt;  &lt;p&gt;This is fine for simple handlers. Developers wanting to reuse handlers might wish to specify a method here to use. The best way of doing this I've found is:&lt;/p&gt;   &lt;pre&gt;def my_handler(but)&lt;br /&gt;  &amp;nbsp;&amp;nbsp; ...&lt;br /&gt;end&lt;br /&gt; &lt;br /&gt;button.signal_connect(&amp;quot;changed&amp;quot;, &amp;amp;method(:my_handler))&lt;/pre&gt;  &lt;p&gt;This involves a little bit more magic, as you can see.&lt;/p&gt;   &lt;p&gt;I've also run into an unexpected barrier with subclassing and the class default signal handler. The subclassing example from the Mono Notebook shows an example of overriding the &lt;em&gt;clicked&lt;/em&gt; method of a &lt;em&gt;Button.&lt;/em&gt; In C# this looks like this:&lt;/p&gt;   &lt;pre&gt;class MyButton : Button {&lt;br /&gt; ...&lt;br /&gt; protected override void OnClicked ()&lt;br /&gt; {&lt;br /&gt;  &amp;nbsp; hitcount++;&lt;br /&gt;  &amp;nbsp; base.OnClicked ();&lt;br /&gt; }&lt;/pre&gt; &lt;p&gt;In Ruby I would write this:&lt;/p&gt;  &lt;pre&gt;class MyButton &amp;lt; Gtk::Button&lt;br /&gt; ...&lt;br /&gt; def clicked&lt;br /&gt; &amp;nbsp; self.hitcount += 1&lt;br /&gt; &amp;nbsp; super&lt;br /&gt; end&lt;/pre&gt; &lt;p&gt;However, when you click the button it's clear the overridden method isn't being called. I've &lt;a href="http://sourceforge.net/tracker/index.php?func=detail&amp;amp;aid=1419230&amp;amp;group_id=53614&amp;amp;atid=470969"&gt;filed a bug&lt;/a&gt; with what I think is the underlying problem. In this instance, I worked round it by adding a signal handler in the constructor:&lt;/p&gt; &lt;pre&gt;self.signal_connect(&amp;quot;clicked&amp;quot;) { |b| b.hitcount += 1 }&lt;/pre&gt;&lt;p&gt;At the moment it feels like I'm writing rather C-like Ruby, rather than it being idiomatic. But then again, I am porting examples from C# in as literal manner as possible, in order to facilitate comparison.&lt;br /&gt;&lt;/p&gt;  &lt;p&gt;&lt;a href="http://times.usefulinc.com/2006/01/30-ruby-gnome#disqus_thread"&gt;Join the conversation about this post&lt;/a&gt;&lt;/p&gt;    </content>
  </entry>
  <entry>
    <title>Why Rails?</title>
    <link href="http://times.usefulinc.com/2006/01/21-rails-zope" rel="alternate"/>
    <id>http://times.usefulinc.com/public/read/833</id>
    <updated>2006-01-21T22:50:53Z</updated>
    <published>2006-01-21T11:43:56Z</published>
    <summary>When I moved my blog to Rails from Zope, I was asked why. This is a brief explanation.</summary>
    <category term="programming"/>
    <category term="rails"/>
    <category term="ruby"/>
    <content type="html">
&lt;p&gt;When &lt;a href="http://times.usefulinc.com/2006/01/15-redesign"&gt;I moved this blog&lt;/a&gt; from being Zope-backed to using Rails several people got in touch to ask why. This is a brief explanation of why I've moved.&lt;/p&gt;&lt;p&gt;Firstly I should point out I've had a long and mostly happy experience with Zope. I got into Zope originally because I'd spent some time in constructing web frameworks from scratch (we're talking 1995-1999 here) and found that not only does a framework need good templating, it needs reusable components within that.&lt;/p&gt;&lt;p&gt;Zope seemed like a good fit, so I spent some time getting up to speed and was happy there. However, there were some things that didn't make me feel completely comfortable. Zope offered a very stark choice between developing through the web based interface (DTML methods, etc.) and writing raw Python. To do really useful stuff, you had to get into the Python side of things, but also learn a lot about Zope guts that wasn't really well documented.&lt;/p&gt;&lt;p&gt;I spent more time than I probably should have had to reading Zope's own source code in order to figure out how things worked. Fine, for my own silly little projects, but not practical in general. It was hard to get the overall view of a project, and hard to test. The learning curve was a little too steep, I suppose.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;So, once I'd got to a certain point I stopped, and looked around for a platform that gave me more code visibility and testability. Loyal readers will know I've looked at &lt;a href="http://times.usefulinc.com/2005/03/06-queetah"&gt;ASP.NET and Python, Quixote and Cheetah&lt;/a&gt;. ASP.NET I rejected because I didn't view Mono's web application server as mature enough at the time, and I also had reservations about ASP.NET's non-free baggage. Python, Quixote and Cheetah looked a lot more friendly.&lt;/p&gt;&lt;p&gt;What I wrote about Quixote and Cheetah at the time was &amp;quot;this combination isn't adequately presented and described anywhere.&amp;quot; These were good technologies, but not integrated as a framework. I started work on integrating them, and made some interesting progress. I was correct that Python lacked a solid modern framework, and the time was certainly right for it, as we can now see by the emergence of &lt;a href="http://www.djangoproject.com/"&gt;Django&lt;/a&gt; and &lt;a href="http://www.turbogears.org/"&gt;TurboGears&lt;/a&gt;.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;However, at the same time I started looking at Rails and found out that it did pretty much what I wanted. To be honest, I'd avoided it for a while as a friend once did me the disservice of calling Ruby a cross between Python and Perl. &amp;quot;Why ruin Python?&amp;quot;, I thought. And it takes me a while to get over the hype barrier before I conclude that there's a &amp;quot;there&amp;quot; there.&lt;br /&gt; &lt;/p&gt;&lt;p&gt;Now I've been using Rails for a while, I find its attractions have changed for me. The thrill of not having to write basic functionality over and over again has given way to more select pleasures. Writing in Ruby itself is a rewarding experience, as its idioms become plainer over time.&lt;/p&gt;&lt;p&gt;Sure, you can write Java or Perl in any language, and that's where I started off. But the subtle elegance of the Ruby idiom is a slowly appreciated and highly satisfying flavour. For developers who consider themselves as poets and artists too, I can't think of a better language.&lt;br /&gt;&lt;/p&gt;&lt;p&gt;&lt;a href="http://times.usefulinc.com/2006/01/21-rails-zope#disqus_thread"&gt;Join the conversation about this post&lt;/a&gt;&lt;/p&gt;    </content>
  </entry>
</feed>
