If you're going to add a hook, make it a big one 4
Jay Fields responds to on Ola Bini’s Evil Hook Methods? about the common ruby idiom that lets us write:
class Fruit
include DataMapper::Resource
property :id, Integer, :serial => true
property :name, String
property :notes, Text, :lazy => false
end
What Ola and Jay don’t like about that is the way that a single include DataMapper::Resource actually adds class methods to Fruit because the implementation of DataMapper::Resource.included looks like:
module DataMapper::Resource
sub included(module)
module.send :include, InstanceMethods
module.send :extend, ClassMethods
end
end
Which is a perfectly common idiom nowadays, but which breaks include’s contract in annoying ways. Jay proposes fixing this by adding a become method to Object which would wrap the include and extend in such away that they’d be called by the including class. Huzzah. And it makes sense… sort of. But it really doesn’t go far enough.
Let’s take another look at the original code snippet shall we? The thing that I notice is the wide scope of that ‘property’ method. It really isn’t needed anywhere except for defining how a Fruit is mapped onto the database. What happens if we take a leaf out of Perl’s book:
class Fruit
use DataMapper::Resource {
property :id, Integer, :serial => true
property :name, String
property :notes, Text, :lazy => false
}
property :foo # => raises an exception
end
The block gives our extending module somewhere to play, it can introduce a full on domain specific pidgin for the duration of the block with no fear of polluting the including class with anything but the methods its contracted to provide. So, how do we implement use. Something like the following should serve the purpose:
class Module
def self.use(mod, *args, &block)
mod.used_by(self, *args, &block)
end
def self.used_by(mod, *args, &block)
if instance_behaviours || class_behaviours
mod.become(self)
else
mod.send(:include, self)
end
end
def self.become(mod)
include mod.instance_behaviours) if mod.instance_behaviours
extend mod.class_behaviours if mod.class_behaviours
end
def self.instance_behaviours
nil
end
def self.class_behaviours
nil
end
end
The key idea here is that, in the default case, use will ignore all its arguments beyond the first and just include that module (a more robust implementation would probably ensure that an exception was raised if any extra arguments got passed). If the module author had written her module to comply with Jay’s proposed become, then we simply call become.
The interesting stuff happens when a module wants to do something a little more trick. So a version of DataMapper might do something like:
class DataMapper::Resource
def self.used_by(mod, &block)
mod.become build_behaviours(mod, &block)
end
end
And build_behaviours would instance_eval the block with an object that would capture the properties and use them to build a set of class and instance methods appropriate to the description.
Another module might simply take a hash to describe how things should be parameterized. It all depends on the needs of the module being used. The aim being to avoid polluting the caller’s namespace any more than necessary. If I use a DataMapper type package, then all I want to end up with in my client classes are appropriate instance accessor methods, I don’t need spare class methods like property or storage_names that are only of any use when I’m describing my class.
Updates
I edited one of the code snippets to remove a particularly heinous piece of brace matching. Thanks to Giles Bowkett for the catch.
Oh. Bugger 2
If you asked me to name my favourite radio and TV comedy, the odds are very good that Geoffrey Perkins had a hand in most of them. When I found his obituary in this morning’s Guardian I felt almost physically winded. I never met him, I don’t know anyone who did, but he was someone who helped to make the world a pleasanter place to be in. My thoughts are with his family and friends, who are no doubt even more gutted than I am.
Get sophisticated 6
Ruby’s primitives (Strings, Hashes, Arrays, Numbers – anything that has a literal syntax) are fine things. But that doesn’t mean you should use them everywhere. You’re often much better off wrapping them up in your own Value Objects.
Something I was working on at Railscamp this weekend threw up a great example of why it makes sense to replace primitives with more specific objects as soon as possible. Tom Morris asked me to take a look at Rena, an RDF/Semantic Web thingy.
The RDF spec describes two types of literals: a plain literal, which is a string with an optional language attribute and a typed literal, which is a string and an encoding (so the string might represent an integer, float, or anything else that your schema feels like expressing).
These literals can be output in one of (at least) two formats. We’ll start by looking at Literal#to_trix and see where that takes us:
def to_trix
if @lang != nil && @lang != ""
out = "<plainLiteral xml:lang=\"" + @lang + "\">"
else
out = "<plainLiteral>"
end
out += @contents
out += "</plainLiteral>"
return out
end
If we look over at TypedLiteral#to_trix we see a much more straightforward implementation:
def to_trix
"<typedLiteral datatype=\"#{@encoding}\">#{@contents}</typedLiteral>"
end
How do we eliminate that ugly conditional at the beginning of Literal#to_trix, and analogous conditionals in Literal#to_n3 and TypedLiteral#to_n3?
My first thought was that I wanted to be able to write something like:
def to_trix
"<plainLiteral#{@lang.to_trix}>#{@contents}</plainLiteral>"
end
But I didn’t want every string in the world suddenly acquiring a to_trix method. So, the solution was to intoduce a Literal::Language class and coerce our language into it, so Literal#initialize became:
def initialize(contents, lang = nil)
@contents = contents
@lang = Language.coerce(lang)
end
And Language would look something like:
def self.coerce(lang)
if lang.is_a?(self)
return lang
end
new(lang.to_s.downcase)
end
def initialize(lang)
@value = lang
end
def to_trix
if @value == ''
''
else
" xml:lang=\"#{@value}\""
end
end
That ugly conditional’s still there though, so we introduced the Null Object pattern, and things started to look a good deal cleaner:
class Language
class Null
include Singleton
def to_trix
''
end
end
def self.coerce(lang)
case lang
when self
return lang
when nil, ''
return Null.instance
else
return new(lang.to_s.downcase)
end
end
...
def to_trix
" xml:lang=\"#{@value}\""
end
end
At this point, we’re still just pushing code around. If anything, we’ve got more lines of code now than when we started, but we’re starting to move behaviour nearer to the data it relates to, and our objects are starting to look like objects rather than data structures. So, we press on and make a TypedLiteral::Encoding class and, at this point things start to look interesting. TypedLiteral is starting to look almost exactly the same as Literal, but with an Encoding rather than a language.
That strange leading space in Language#to_trix is starting bug me. Let’s rewrite like so:
class Literal
class Language
def format_as_trix(literal)
"<plainLiteral xml:lang=\"#{@value}\">#{literal}</plainLiteral>"
end
class Null
def format_as_trix(literal)
"<plainLiteral>#{literal}</plainLiteral>"
end
end
end
def to_trix
@lang.format_as_trix(@contents)
end
end
If we make analogous change to TypedLiteral and TypedLiteral::Encoding it’s obvious that TypedLiteral and Literal were essentially the same class. Renaming @lang and @encoding to @language_or_encoding makes this blindingly obvious, so we’ll remove all of TypedLiteral’s methods except initialize. All that remains is to introduce Literal.untyped and Literal.typed factory methods to Literal, and make Literal.new into a private method and we can remove TypedLiteral in its entireity. So we change the specs to reflect the new API (wrong way round I know). Now we have a chunk of shorter, clearer code that will hopefully be easier to extend to cope with outputting literals in other formats.
Retrospective
I realise that patterns aren’t the goal of development, but by the end of the process we have a Strategy (Language/Encoding), a couple of Factory Methods (Literal.typed, Literal.untyped) and a couple of factoryish methods (Language.coerce, Encoding.coerce).
The most important aspect of the change was the introduction of the two new value object classes. Once they were introduced, they became the obvious places in which to put the varying behaviour and eliminate the repeatition of conditional code from the to_* methods. If there were to be a third output style, I would look at introducing classes like N3Stream, TrixStream and WhateverStream and have a scheme like:
def to_n3
print_on( N3Stream.new )
end
def print_on(stream)
language_or_encoding.print_on(stream, value)
end
but that’s almost certainly over complicating things right now.
The other thing I like about this kind of refactoring is that it drives the code towards methods and classes which obey the single responsibility principle and, at the end of the process, not only do we have fewer lines of code in total, but the individual methods involved are all substantially shorter and closer to the left hand margin.
I really should start doing this kind of thing more in my Rails practice – I keep being put off by the fact that the composed_of helper is so annoyingly not quite right and, rather than submitting a patch or making a plugin I go “Ah well… I can live with a string for a bit longer…” and I know. From hard won experience at that, that it’s going to come and bite me. It’s already bitten Rails recently when Ruby got a new String#to_chars which doesn’t work like the ActiveSupport version.
Notes
If you want to see the gory details of how the change got made, Tom has merged this weekends changes into the github repository. It didn’t happen in quite the order I’ve described it in this post, but neither is this post a complete fabrication.
Changes
Corrected a stupid typo in the first block of code. Ugly condition is actually if @lang != nil && @lang != ''
Work with us 2
If the last post about our Javascript issues didn’t put you off, then you might be interested to know that we’re hiring. If you’re an experienced, test infected Ruby on Rails programmer with some Javascript and a real world consumer website or two under your belt, and you’re happy to work in Newcastle upon Tyne, then we definitely want to hear from you. I’d probably be interested in at least hearing from you if you’re an experienced dynamic language programmer who has only recently made (or is considering making) the switch to Ruby and Rails. It’s only syntax after all.
The money’s decent, the work is interesting, the people (well, apart from me, obviously) are great, and Newcastle’s a fantastic city. Drop me a line, ping me on AIM/gTalk/Twitter or just send your CV to the jobs@amazing-media.com.
Usability testing (throws) rocks 4
Usability testing is wonderful. But wow, its humiliating.
I’ve spent the last few weeks working on the Amazingtunes in page player. Amazingtunes is a music site, so we need to play music. However, we don’t like the way that most music sites work; either the music stops as you go from one page to another, or the player is a huge Flash app running in its own window. There has to be a better way. There needs to be a popup window if you want to eliminate stop/start behaviour, but there’s surely no reason not to keep the controls on the main page.
So, we set about writing somthing that did just that. We settled on using Jeroen Wijering’s excellent flvPlayer, which handles the media formats we need and has good Javascript control and communications. This sits in the child window and we use Javascript cross-window communication to have a player controller in the main window that looks something like:
This is all done in HTML and and Javascript, the progress bar does the Safari trick of running behind the tune data links, the buttons do their AJAX magic and the whole thing is rather slick, though I say so myself.
At least, we thought it was slick until we pointed the usertesting.com legions at it. Without exception, they ignore the in page player, foreground the popup and use the teeny weeny controls on the flash player. Originally, the popup window didn’t even display any transport controls, it just had a picture of some speakers and some text asking the user not to close it because it was playing the tunes. We added transport controls as a stopgap while we made the in page player work properly.
I sound like I’m whinging don’t I? It’s certainly a blow to the ego to see something we spent so much time and attention on being ignored by our sample users. On at least one occasion, while watching the screencasts I found myself boggling at the things the users did, and if I didn’t shout “Just play some bloody music!” at the screen, then I came worryingly close.
It would be easy to retreat into a state of denial: “They’re not our target users! They’re stupid! They’re American! If they would only magically intuit the way we think they should use the site!”. And maybe it would be comforting to do so, for a while. The right thing to do is to suck it up – take away from those videos the sure and certain knowledge that bits of the site don’t work and do something about it.
We may dislike the ‘popup window for transport controls’ model of controlling music playback, but users are cool with it. And it’s not as if the work we did on making the in page player work is going to be wasted – widget is straightforwardly event driven so it’ll work just as well in the popup window, and the communication protocol will be much simpler. Having the player in its own window means we’ll be able to extend its interface in ways that would be hard when the player had to share window space with the rest of the page. In the end, it’s all good.
But… damn that in page player was sweet. I learned Javascript as I wrote it (mostly by pretending it was Perl with odd syntas) and I’m bloody proud of it. I’ll happily replace it with the next iteration (which I’m already working on), but it’ll be with a pang of remorse all the same.
Announcing Announcements for Ruby
I’ve just pushed a just about usable (but horribly untested) port of Vassili Bykov’s very lovely Smalltalk Announcements framework onto github. It’s a very raw port at the moment (the interface isn’t what you’d call idiomatic ruby yet), but I shall be working on that soon. Documentation (beyond a synopsis in the readme file) is nonexistent, but I reckon that there’s the core of something useful there (I’ve got plans for using it in Typo as the basis of a Wordpressesque plugin architecture and I need it for my Sooper Sekrit Project too…).
Expect some more details on the whats and whys in this blog soon, but if you want to have a play, you’ll find it at http://github.com/pdcawley/announcements. Enjoy.
git is the monads 2
When, in the course of learning about Haskell, I reached the point where I thought I understood what Monads were for, I wrote about it. In the comments, Seth Gordon observed that:
There are two kinds of people who try to learn Haskell: the people who give up because they can’t figure out monads, and the people who go on to write tutorials on how to understand monads.
I remembered this today as yet another git tutorial rolled by in my newsreader. Maybe git is the monads of version control.
What other ‘monads’ are there out there? RESTful routing in Rails seems an obvious candidate, but I’m sure there’s more.
Rails tip: Dealing with out of sync migrations 4
Sometimes, for one embarrassing reason or another (usually involving chaotic branch merges…) a database migration can get leapfrogged. When this happens, it’s tempting to renumber the leapfrogged migration, but that breaks any servers where the migration didn’t get renumbered. Here’s how I dealt with it recently:
class MaybeOldMigration < ActiveRecord::Migration
def self.up
unless old_migration_applied?
OldMigration.up
end
end
def old_migration_applied?
# Checks that the schema looks as it should
# if the old migration got applied
end
endYeah, it’s a hack, but it’s a fairly robust hack.
A quick Javascript formatting tip 10
IE’s a pain. The particular pain I want to write about is its pickiness about Javascript object literals. Consider the following Javascript object:
{ success: function () {...},
failure: function () {...},
}If you’re used to programming in Perl or Ruby, that trailing comma’s perfectly fine, in fact leaving it there is sometimes considered good practice because it makes it easy to extend the hash, just add a new row and leave another trailing comma.
The trouble is, it’s not strictly legal to do that in Javascript. Pretty much every implementation out there will allow it though.
Except IE.
So, I’ve taken a leaf out of Damian Conways Perl Best Practices and writing my object literals as:
{ success: function () {...}
, failure: function () {...}
}By sticking the comma at the beginning of the line, I’m never going to make an object that breaks IE, and adding a new line to the hash is straightforward too. Just stick the cursor in front of the }, type my leading comma, space, attribute name, and hit return when I’m finished.
I’ve also started using the same practice pretty much everywhere else that I’ve got a comma separated list of things:
var foo
, bar
, baz
;
$.each( anArray
, function () { ... }
);It looks weird at first, but trust me, it grows on you.
Update
In the comments, I make reference to tweaking Steve Yegge’s excellent js2-mode to handle leading comma style a little more gracefully. Since then, I’ve made it work and attached a diff to this issue on the project’s issue tracker.
Ads are gone 2
Back when I was writing the occasional “How do you find me?” article, I would get some weird ads showing up. On one occasion, I commented that the searcher had obviously just typed a homework question into google and expected an answer. All the ads on that page ended up being for sites that would write your essays for you.
“Hmm…” I thought, “That’s not good.”, and set about adding those advertisers to the block list.
Then, in another article, I ranted about those, ah, bastions of democracy (thank you, Tom Lehrer) who indulge in comment spamming and found myself advertising them.
Rolling back the enlightenment which discussed, amongst other things, my Uncles’ marriage after 36 years together (yay!) attracted some pretty dodgy ads too.
To my shame, none of these made me rethink the advertising, I just extended the filter and shook my head at the unpleasantness of it all.
The straw that broke the camel’s back was the advertising around Fat is an economic issue ran utterly counter to the spirit of the of the article, and they were like “whack a mole”. Every time I extended the filter, another ad for another bloody health insurance leech or some other snake oil peddler popped up.
So, screw that, the Google ads are gone – it’s not as if they were making me a huge amount anyway. I’ll continue with the left margin Amazon links though – nobody ever buys anything I recommend, but I like the pictures.

