Caius Theory

Now with even more cowbell…

Potty Training YAML

Ran into a problem today where I have a class with a few attributes on it, but I only want a certain three of those attributes to appear in the YAML dump of a class instance.

Diving straight into a code example–lets say we have a Contact class, and we only want to dump the name, email and website attributes.

require "yaml"

class Contact
  attr_accessor :name, :email, :website, :telephone

  # helper method to make setting up easy
  def initialize(params={})
    params.each do |key, value|
      meffod = "#{key.to_s}="
      send(meffod, value) if respond_to?(meffod)
    end
  end
end

# And create an instance for us to play with
caius = Contact.new(
  :name => "Caius",
  :email => "dev@caius.name",
  :website => "http://caius.name/",
  :telephone => "12345"
)

As we'd expect when dumping this, all instance variables get dumped out:

print caius.to_yaml
# >> --- !ruby/object:Contact 
# >> email: dev@caius.name
# >> name: Caius
# >> telephone: "12345"
# >> website: http://caius.name/

Initially I tried to override to_yaml and unset the instance variables I didn't want showing up, but that just made them show up empty. After digging around a bit more, I happened across the Type Families page in the yaml4r docs, which right at the bottom mentions to_yaml_properties.

Turns out to_yaml_properties returns an array of instance variable names (as strings) that should be dumped out as part of the object. A quick method definition later, and we're only dumping the variables we want. (See my Ruby Shortcuts post if you don't know what %w() does)

class Contact
  def to_yaml_properties
    %w(@name @email @website)
  end
end

And now we dump the class, expecting only the three attributes to be outputted:

print caius.to_yaml
# >> --- !ruby/object:Contact 
# >> name: Caius
# >> email: dev@caius.name
# >> website: http://caius.name/

Success!

Adding XHTML output validation to Cucumber stories

At the 2009 Barcamp Leeds I attended a talk by Neil Crosby where he talked about automated testing, and about how he felt there was a gap in everything that people were testing. Everyone has unit tests, and people are doing full stack testing too, but no-one (so he feels) does XHTML/CSS/JS validation as part of their automated test suite. And certainly from what I've seen on the mainstream Ruby site's about testing, I agreed with him.

So after his talk I had a quick look at his frontend test suite, and started wondering where exactly I would fit frontend validation testing into my workflow. Would it be part of my unit tests (RSpec), or part of the full stack tests (Cucumber)? As you've probably guessed by the title of this post, its ended up going into my cucumber tests. Since the initial play its been something I've mused about occasionally, but not something I've actively looked into how to implement as part of my test workflow.

Fast-forward a few weeks from Barcamp Leeds and I see a news article in my feed reader entitled "Easy Markup Validation" which gets me hopeful someone's solved this frontend validation thing easily for Rubyists. A quick read through and I'm sold on it and installing the gem. Opened an existing project I'm working on which has a fairly extensive test suite (both unit tests & full stack tests) and tried to slot the validation into my controller unit tests.

Problem with doing this is by default RSpec-rails doesn't generate the views in your controller specs. At that point I realised I was already generating the full page when I was doing a full stack test using culerity and cucumber. So why not just add a cucumber step in my stories to validate the HTML on each page I visit? Mainly because its not enough of a failure for this app to have invalid XHTML markup. Having valid markup would be nice, but I'd rather have it as a separate test to my stories in some way.

Currently I just do that by only validating if ENV["VALIDATION"] is set to anything, so a normal run of my cucumber stories will just test the app does what its supposed to do. If I run them with VALIDATION=true then it will check my markup is valid as well.

features/support/env.rb

require "markup_validity" if ENV["VALIDATION"]

features/step_definitions/general_steps.rb

Then %r/the page is valid XHTML/ do
  $browser.html.should be_xhtml_strict if ENV["VALIDATION"]
end

features/logging_in.feature

Feature: Logging in
  In order to do stuff
  As a registered user
  I want to login

  Scenario: Successful Login
    Given there is a user called "Caius"

    When I goto the homepage
    Then the page is valid XHTML

    When I click on the "Login" link
    Then I am redirected to the login page
    And the page is valid XHTML

    When I enter my login details
    And I click "Login"
    Then I am redirected to my dashboard
    And the page is valid XHTML

Now when I run cucumber features/logging_in.feature, it doesn't validate the HTML, it just makes sure that I can login as my user and that I am redirected to the right places. But if I run VALIDATION=true cucumber features/logging_in.feature, then it does validate my XHTML on the homepage, the login page and on the user's dashboard. If it fails validation then it gives you a fairly helpful error message as to what it was expecting and what it found instead.

From a quick run against a couple of stories in my app I discovered that I've not been wrapping form elements in an enclosing element, so they've been quickly fixed and now they validate. Now I realise this gem is only testing XHTML output, and doesn't include CSS or JS validation, but from a quick peek at the gem's source it should be fairly easy to add both of those in I think, although again they aren't major errors for me yet in this app.

Find shell commands with which

So I have this command in my $PATH, apachectl. Because I'm on a mac and I've installed apache2 through MacPorts, the command that gets found first is my macports install in /opt. Up until now I've always known that which apachectl will find that location, but to find any other locations of apachectl I'd usually use locate and egrep together.

Here's my original workflow, lets find the location of the apachectl being called when I don't specify a path.

Julius:~ caius$ which apachectl
/opt/local/apache2/bin/apachectl

Simple enough. Now lets figure out what other locations there's an apachectl installed at.

Julius:~ caius$ locate apachectl | egrep "\/apachectl$"
/opt/local/apache2/bin/apachectl
/opt/local/var/macports/software/apache2/2.2.11_0+darwin_9/opt/local/apache2/bin/apachectl
/usr/sbin/apachectl

Right, so now I know where else a command exists in the filesystem called apachectl, but I don't know if any of those is in my $PATH, or what order they come in when searching through my $PATH. In this (old) workflow I'd have compared them to my $PATH manually as there's so few of them.

So I noticed Ali googling for the which man page on IRC, and (quite stupidly) poked fun at him for doing so. I then swallowed my ego and actually followed the link to the man page, and boy was I glad I did. Just shows with even a fairly simple command like which, you sure don't know everything!

What I discovered was that which has a single flag you can pass it, -a. From the man page:

-a     print all matching pathnames of each argument

Right. So that locate | grep command plus manually figuring out what is in my $PATH is really hard work then. which -a should give us the same results, but a lot faster and with a lot less manual thought.

Julius:~ caius$ which -a apachectl
/opt/local/apache2/bin/apachectl
/usr/sbin/apachectl

And hey presto, yet another useful bit of bash knowledge for me, thanks to Ali not being afraid to RTFM!

Inaugural Habaricon

So I managed to secure a place to HabariCon '08. Not quite sure what to expect, but being able to meet other people in real life and talk about habari & related things all day will be quite cool.

Expect a round-up post of the 'con tonight!