Matthew Palmer: [Ruby] Blocks as Resource Management
One of the really neat things about Ruby is the extensive use of blocks
(closures, I think the rest of the world calls them) in the standard
library to control the allocation and deallocation of resources. Take the
following snippet:
File.open('something.txt') do fd
# Manipulate the file through 'fd'
end
# File handle is now closed
There's no way that you can escape from that block without the file being
closed (well, in theory, you could lose the file handle if there was an
exception thrown in the block, but the File::open method can take
care of that internally by catching, closing, then rethrowing).
I've loved this feature since I first saw it -- "holy crap!" I thought to
myself, "I never have to call close again!". And I was pretty well right
-- I think I can count (in unary, not binary!) on one hand (well, I'd use
grep wc) the number of times I've used IO#close in my
Ruby code.
The funny thing is, though, that I don't think I've used this pattern in my
own code enough. But I just had an epiphany whilst waiting for a
train home -- and I think I'm cured. Take this hideous piece of test code
I had laying around in an app I'm working on at the moment:
def test_something_funny
faux_path_on
d = Domain.new('127.0.0.1', 'somethingfunny.com')
faux_path_off
# assert writ large
end
Domain::new calls out to a shell command (dig(1) to be
precise -- take a guess at what I'm writing <grin>, and yes, it will
be released shortly) but for test purposes I can't run dig (because I'm not
guaranteed to have all the infrastructure available for a real dig
to succeed). So I have a flimsy mock of dig in a directory in my
test suite, which is where faux_path_on sets ENV['PATH']
to look at.
This is, of course, pretty untidy, because when (not if!) I forget to call
faux_path_off, everything goes to complete poop, and my children
will have two heads or something.
The much cleaner version is like this:
def test_something_funny d = faux_path Domain.new # Assert ahoy! endAnd my faux_path method (I've even saved a method!) is as simple as simple can be:
def faux_path realpath = ENV['PATH'] ENV['PATH'] = my_fake_path rv = yield ENV['PATH'] = realpath return rv endI also have a trickier faux_* method, which sets a couple of environment variables which tell my mock nsupdate(8) where to write the data it gets sent from my application -- again, it's a block-taking method that sets the environment, yields, reads in the data from the temporary file, cleans it up, and returns the contents of the aforementioned file. The power of the Ruby is growing within me, I can feel it. And I like it.
That’s the building, though when I took the picture, I did not know on which side the apartment would be, and it turned out this is not the side. Would have been nice, though: a view to a small patch of forest, beyond which I could have seen (barely) the old building.
Instead, my view from the windows is toward the yard-cum-parking-lot, though it is possible to vary this a lot by choosing the angle (one angle gives a view toward another forest patch).
The first picture is from the kitchenette, the others are from the single room, which I call the living room. I also have a kitchenette —
— and an alcove (which I call the bedroom).
The bathroom hopefully doesn’t have a mold problem, but probably does. It’s of the older design that frequently didn’t take moisture and water protection seriously enough. Well, at least there are no outward signs of such a problem, and the air circulation system definitely works. I apologise for the poor quality of this picture:
I got the keys on the first of this month, and promptly moved in a spring mattress. The next day I walked nearly the recommended 10,000 steps in handling all kinds of issues, including buying a very nice lamp and a barstool to the kitchenette.
I got cable service on Monday and am now writing this on my laptop in the kitchenette sitting on the barstool, over a wireless network that is connected to the cable modem.