Mmm… Rails routes, don’t you love them?
Well, not unreservedly, no.
Here’s my current problem: Typo articles have a permalink that looks like /articles/:year/:month/:mday/:permalink
, so the permalink for this article is /articles/2007/03/15/cover-me-im-going-in
and when someone visits it, the controller gets a params hash which contains keys along the lines of:
I’m getting heartily fed up of people banging on about Domain Specific Languages. It seems that every time someone writes a Ruby library that uses class methods, symbols and hashes reasonably sensibly they get delusions of grandeur and call the result a Domain Specific Language (or maybe an ’embedded’ DSL).
On Monday I went to the London Ruby Users’ Group March meeting. The theme of the meeting was code review, so I put up a chunk of code from my yet to be released Sudoku solver.
There’s a very cunning trick that most Smalltalk implementations use to avoid dereferencing pointers when they’re dealing with ‘small’ integers. And for years, I’ve misunderstood it. For some reason I used to think that Squeak say looked at the value of a pointer to an object and, if it was < some biggish number, it would be treated as an integer.
You know that voice at the back of your head that says things like “That’s not really a data structure, that’s an object that is!”?
Adam Turoff is one of the good guys, a fine host who doesn’t mind when your wife pulls his shower tap off the wall, a wise programmer, mine of information, and an enlightening man to talk to. It was Adam who popped up in an iChat window not long after Rails got released and suggested I take a look.
Almost every time I hear Rails people banging on about Little Languages[1], I find myself wondering what the fuss is all about - these things are not exactly new after all.
At RailsConf Europe this year, DHH went in quite strong on the idea that simply using an opensource framework, like, say, Rails didn’t entitle you to much of anything. The precise phrase used was, if memory serves “We don’t owe you shit.”
Right. I’ve bundled acts_as_resource
up and stuck it on the typosphere SVN server. You can grab it from http://svn.typosphere.org/typo/plugins/acts_as_resource if you’re interested.
It’s currently in what I’d call an all convention, no configuration state - if your resources don’t look pretty similar to the kind of things you get from the resource scaffolding, you’ll probably have some pain, but I expect to rectify that with coming releases. One thing I want/need to do for instance is to allow for ‘relative’ ids in your resource url. For instance, if you’re looking at /albums/10/tracks/982
, it’s not the most readable of permalinks… next trick is to allow you to have urls like /albums/because-its-there/tracks/1
, ie: the first track on the album ‘Because it’s There’. I’m sort of expecting that you’d do that by doing:
I’m very nearly ready to release acts_as_resource
, I just have to pull up and tidy code that’s currently in my working directory’s ApplicationController and we’re laughing. However, I thought you’d like to see what my nested controller looks like.
While I was working on the acts_as_resource
plugin trying to fix things up so that the resource finding side of things works neatly, I realised that I needed some way to get at the ordered list of parameter keys that were matched by the routing system.
So, you’ve upgraded to Rails 1.2.1 and you’re working on a tool to maintain a database of all the tunes you have in your various songbooks and (eventually) your record collection. You start with:
Your mission, should you choose to accept it, is to explain what the following code does:
class Amb
def initialize
@error = Exception.new("Ran out of possibilities")
@failure_continuation = lambda {|v| @error}
end
def assert(assertion)
if !assertion
self.fail
end
end
def deny(assertion)
assert !assertion
end
def fail
@failure_continuation.call(nil)
end
def maybe
one_of [true, false]
end
def one_of(collection = [])
k_prev = @failure_continuation
callcc do |k_entry|
collection.each do |item|
callcc do |k_next|
@failure_continuation = lambda do |v|
@failure_continuation = k_prev
k_next.call(v)
end
k_entry.call(item)
end
end
result = k_prev.call(nil)
if result == @error
raise @error.message
end
end
end
def all_values(&a_block)
k_prev = @failure_continuation
results = []
callcc do |k_retry|
@failure_continuation = lambda {|v| k_retry.call(false)}
results << a_block.call
k_retry.call(true)
end && fail
@failure_continuation = k_prev
results
end
end
Easy? Now explain how it does it.A friend of mine, David Morton, just pointed me at a transcript of a lecture given by one Christopher Small. In it Small nails something I’ve been trying to articulate for ages. I don’t know whether to applaud madly or seethe with silent resentment that someone said it so much better, and in 1995 at that.