Archive for April, 2008

rcov: it is like crack for obsessive completists

Wednesday, April 30th, 2008

rcov is a Ruby code coverage analysis tool that I’ve just been playing with for an hour or so while I look at how well my test cases are covering the code I’ve written.

You can gem install rcov

I’m working on a Rails app and there’s a handy plugin to make running rcov easy peasy:

http://svn.codahale.com/rails_rcov/

with some documentation here:

http://blog.codahale.com/2006/05/26/rails-plugin-rails_rcov/

Now I can just rake test:test:rcov to run all my tests and see what they’re covering.

Update: from playing around a bit I reckon that concentrating your coverage analysis around functional tests is probably the biggest bang for the buck. Functional tests exercise a lot of your code from both the controllers and the models.

rake test:functionals:rcov

rcov generates these amazing HTML reports telling you which code your tests exercised. More importantly it tells you which code your tests didn’t exercise so you can work out what extra tests you need to add.

app_models_poll.rb - C0 code coverage information.jpg

How cool is that!

Now, what prompted all this was a post to the cc.rb mailing list about integrating rcov with a continuous integration build to fail the build if coverage drops below a certain acceptable threshold. Perhaps 80%? Perhaps 100% for those prone to collecting comic book series or trading cards.

There’s a rails plugin named vl_cruise_control that will help with failing a build with cruise. I’ve not tried it yet.

Rails association extensions

Wednesday, April 30th, 2008

I think this might be very useful for creating expressive models.

Search for Association extensions inside the ActiveRecord::Associations::ClassMethods API doc.

Hrm… need a bit of time with this but I suspect I have a lot of uses for it floating around.

Hackney t-shirts

Wednesday, April 30th, 2008
Hipster Tourist London and Hackney t-shirts.jpg

Monica made a few Hackney related tshirts a while back.

She sells one every so often and did so today. I think they’re cool.

Hackney t-shirts

Rails nested resources and form_for

Wednesday, April 30th, 2008

Ah ha! I was working with Rory creating a Rails form backed by a nested resource the other day and we had code like:

<% form_for(:participant, @participant, :url => poll_participant_path(@poll, @participant), :html => {:method => :put}) do |f| %>

#...

<% end %>

That code smelled really bad, having to put in the :url and the :html felt really wrong.

Solution:

<% form_for([@poll, @participant]) do |f| %>

#…

<% end %>

The array of objects makes this much cleaner.

My Wordpress install got hacked

Wednesday, April 30th, 2008

It was an old version. I reckon I should upgrade.

A plugin was installed in /tmp/ro8kbsmawge.txt that was apparently spamming people. *sigh*

Anyway, the only way I discovered it was hacked was because I was getting an error while uploading images from MarsEdit.

I was getting an XMLParse error and no data was coming back in the response.

Here’s a write up:

Link

Baby steps…

Monday, April 28th, 2008

Henry, Rory and I have been hacking away at a little utility website and I think we’ve got an early version that should stand alone and deliver some value.

whenshouldwe is a little web app designed to help people work out a time they can get together.

Baby steps, deliver some value as soon as possible and iterate quickly. We’ve got big plans to increase the feature set while keeping the user experience as simple and clean as possible.

Ruby in the small: the splat operator

Wednesday, April 23rd, 2008

Nice tips on using Splat!, the * operator.

Heads or tails?

Splat! can be used for more than just method definition and invocation. My personal favorite use is destructuring assignment. I read this in Active Record’s source code recently:

def sanitize_sql_array(ary)
statement, *values = ary

end

This is invoked when you do something like User.find(:all, :conditions => ['first_name = ? and last_name = ?', 'nick', 'kallen']). Splat! is used here is to get the head and tail of the conditions array. Of course, you could use always use shift, but the functional style used here is quite beautiful. Consider another example:

first, second, *rest = ary

Link

Generating valid Atom feeds from Rails 2.0.2

Tuesday, April 22nd, 2008

Update to create an auto discover link to your feed use the formatted_resources_url helper:

# app/views/polls/index.html.erb
<% content_for :header do %>
	<%= tag(:link, :rel => "alternate",
	:type => "application/atom+xml",
	:href => formatted_polls_url(:format => :atom))
%>

<% end %>

# app/views/layouts/application.html.erb header block
<%= yield(:header) %>

Update: does anyone know if Google Reader takes a while to process new feeds and render them correctly?

I just put up a feed that was validated it took Google Reader quite a long time to finally figure out how to display its name correctly.

I’ve built a few RSS feeds using builder and just came across this for building Atom feeds.

The Rails team seem to have picked Atom over RSS as their feed format of choice, there’s no mention of RSS in the API documentation.

So… go with the flow right? Why bother with RSS?

Now, sadly Rails 2.0.2 doesn’t generate valid feeds but there’s a patch on edge that will fix that.

From Rails changeset 8529 download a new version of atom_feed_helper.rb (link or look for the zip at the bottom of the changeset page) and drop it into your config/initializers directory to monkey patch Rails. Restart your server.

WARNING: learner driver steering, this is the first time I’ve patched Rails in this way but it seems to not break anything with some very minor testing.

Assuming that we’re dealing with resourceful routing:

# app/views/polls_controllers.rb
  def index
    @polls = Poll.find(:all)

    respond_to do |format|
      format.html # index.html.erb
      format.atom # index.atom.builder
      format.xml  { render :xml => @polls }
    end
  end

# app/views/polls/index.atom.builder
atom_feed(:schema_date => "2008-04-22") do |feed|
  feed.title("Pollthing polls")
  feed.updated((@polls.first.created_at))

  for poll in @polls
    feed.entry(poll) do |entry|
      entry.title(poll.title)
      entry.content(poll.feed_description, :type => 'html')

      entry.author do |author|
        author.name("Pollthing")
      end
    end
  end
end

Job done.

The big difference here between implementing Atom and RSS is that all the links and date stamps are created for you. You can concentrate on things that matter to the application: title, author and description.

Compare with some scavenged builder code that does RSS…

xml.instruct! :xml, :version=>"1.0"
xml.rss(:version=>"2.0"){
  xml.channel{
    xml.title(@blog_posts.blog.title)
    xml.link("http://localhost:3000/blog_posts.rss")
    xml.description(@blog_posts.blog.description)
    xml.language('en-us')

    for post in @blog_posts
      xml.item do
        xml.title(post.title)
        xml.category()
        xml.description(post.body)
        xml.pubDate(post.created_at.strftime("%a, %d %b %Y %H:%M:%S %z"))
        xml.link("http://localhost:3000/blog_posts/" + post.id.to_s)
        xml.guid("http://localhost:3000/blog_posts/" + post.id.to_s)
      end
    end
  }
}

git-svn worked well, here’s my notes and workflow.

Tuesday, April 22nd, 2008

I spent yesterday over at Rory’s writing some code at his new and internet deficient flat.

As mentioned I took a local git clone of my subversion repo with me so we could branch / commit and generally stash our code out of harms way as we progressed.

git-svn works smoothly and isn’t too much of a mental stretch.

WARNING: learner driver steering. Cribbed heavily from Andy Delcambre though all mistakes are mine alone.

At the risk of repeating everybody else in the Rails development space, but for my own edification here is my git-svn workflow:

  1. Make your SVN repo git proof: go and find all your empty directories like log and those things and commit a .gitignore file in them because they’ll get removed by git otherwise. You can put a useful ignore pattern like *.log in some of them if you care to but sometimes like vendor/plugin it is just necessary to create the .gitignore file.
  2. Take a copy of the code before leaving the civilised world for far away and internet impoverished Clapton:


    mkdir pollthing-git && \

    cd pollthing-git && \

    git svn init -s svn+ssh://panic.gatezero.org/Users/tim/svn/pollthing && \

    git svn fetch && \

    git repack -d

    You’ll find yourself in your working directory along with all your code and the master branch is active.

  3. Start working on a new feature by creating a new branch and switching to it:


    git checkout -b add_an_unsubscribe_for_mail

    That will tell you something like this:

    Switched to a new branch "add_an_unsubscribe_for_mail"

    Now hack away to your heart’s content.

  4. You’re going to change and add a bunch of files.

    For new files you have to add them to the repo just like svn:

    git add foo

    For changed files you have to add them too!

    git add bar

    So that’s way different from SVN.

  5. Don’t be afraid of commitment. You’re done with your coding on this feature.

    You can add changed files at commit time and this is probably a good reflexive practice so no file is left behind:

    git svn commit -a -m "I'm not going to forget about that file I modified by using this -a flag"

  6. Hrm… write then rewrite, okay… I just re-read what I’d written about sending changes back up to the SVN repo and it wasn’t clear. So I hope this is clear:

    To send your changes back to the repository from your current branch:

    Pull the latest from your SVN repo into this branch:

    git svn rebase

    Fix any conflicts and then send your changes to SVN:

    git svn dcommit

    Done.

    Okay, so what was it that I was trying to say wasn’t so clear?

    Right, now, getting things back into SVN isn’t hard but there are a couple of schools of thought. All your changes are in the add_an_unsubscribe_for_mail branch.

    Either, pull changes from SVN down into this branch and deal with merge there and then commit. This is probably the best way to go if you have normal access to SVN and you’re just using git-svn to learn git because the git-svn manpage states:

    For the sake of simplicity and interoperating with a less-capable system (SVN), it is recommended that all git-svn users clone, fetch and dcommit directly from the SVN server, and avoid all git-clone/pull/merge/push operations between git repositories and branches. The recommended method of exchanging code between git branches and users is git-format-patch and git-am, or just dcommiting to the SVN repository.

    Running git-merge or git-pull is NOT recommended on a branch you plan to dcommit from. Subversion does not represent merges in any reasonable or useful fashion; so users using Subversion cannot see any merges you’ve made. Furthermore, if you merge or pull from a git branch that is a mirror of an SVN branch, dcommit may commit to the wrong branch.

    Or, merge the local changes from your add_an_unsubscribe_for_mail branch into the master branch and then merge SVN changes at that point and commit to SVN from there. This is what I did yesterday and it worked well. I branched and then merged each feature I worked on from and back into master before working on the next. THIS IS PROBABLY NOT A GOOD IDEA THOUGH because of the caveats above.

    Next time I’m away from my SVN repo with git svn I’ll just branch once and commit to that serially and then send that branch back up to SVN when the time comes that I have connectivity again.

git-svn for macports

Sunday, April 20th, 2008

tim@manhattan:~$ sudo port install git-core +svn

Going to be away from net access tomorrow so thought it would be a great opportunity to take a copy of my svn hosted project down into a local git repository so I can commit merrily on that until I sync up with my svn repo.

More on git:

Git SVN Workflow

git-svn is a gateway drug