Korny’s blog

The personal blog of Korny Sietsma

Ruby DSLs - so easy

By Korny at 9:15 pm on Monday, October 13, 2008

The joy of Ruby - writing simple DSLs is so very easy.  (That’s “Domain Specific Language” for the uninitiated - go look it up, it’s good for you)
I have some code that builds a tree of info from the file system - basically traversing directories and files and loading up definitions in memory.

I wrote some tests initially based on using real file fixtures, and while they worked, they seemed very ugly and confusing - they were basically integration tests not unit tests, and to know why a test failed, you had to go digging around in the filesystem.  Yuck.

Instead I wrote a DSL that lets me specify directories and files like:

@builder = StubDirBuilder.construct(”root”) do
dir ‘one’ do
file ‘loremipsum.txt’, “123″
end
dir ‘two’ do
file ‘loremipsum.txt’, “123″
file ‘egosum.txt’, “456″
end
dir ’single_child’ do
dir ’single_grandchild’ do
file ‘loremipsum.txt’, “123″
end
end
dir ’something_unreadable’ do
unreadable
end
end

This basically sets up the structures in memory to fake the corresponding directories and files when my tests run.

The code is a bit messy to post here (especially as this stupid blog sucks at formatting code) but the basic structure is:

class StubDirBuilder
def self.construct(root_name,&block)
builder = new(root_name)
builder.instance_eval(&block)
builder
end
def initialize(root_name)
… do stuff to set up the data structures
@cwd = root_name
end
def dir(name)
parent = @cwd
begin
@cwd = File.join(@cwd,name)
… process the directory info into memory
yield self if block_given?
ensure
@cwd = parent
end
end
def file(name, contents = “”)
fullname = File.join(@cwd,name)
… process file
end
end

Basically the call to “instance_eval” is ruby magic that evaluates the whole “dir/file” structure in the context of the newly built StubDirBuilder object.  So each time “dir(name) do…” is found, it calls the “dir” method on the StubDirBuilder; ditto for “file” and “unreadable”.  I just keep track of the current directory in “cwd” and store the data as needed.

(Credit for this is due to several different articles - mostly http://blog.8thlight.com/articles/2007/05/20/ruby-dls-blocks and http://www.artima.com/rubycs/articles/ruby_as_dsl.html )

Filed under: geek1 Comment »

Curved corner images in rmagick

By Korny at 12:05 pm on Sunday, July 20, 2008

RMagick is a great ruby library for image manipulation - it’s basically a wrapper around the venerable ImageMagick libraries.  There are some complexities around installing it on some platforms, and you have to be careful with garbage collection, but it’s still very easy to use and very powerful.

The curved corner images I used in previous blog posts could be built in photoshop or gimp or other gui applications, but I wanted something scriptable, so I’m trying to build all images in RMagick - and it’s really not that difficult.

RMagick has a whole set of vector graphics functions, but I’m mainly using one, the roundrectangle function - it’s pretty simple:

image = Magick::Image.new(width+bordsize, height+bordsize) { self.background_color = 'transparent'}
gc = Magick::Draw.new
gc.stroke(bordercolour)
gc.stroke_linecap('round')
gc.stroke_width(bordsize)
gc.fill(innercolour)
gc.roundrectangle(bordsize/2,bordsize/2, width,height, radius, radius)
gc.draw(image)

This basically draws a round rectangle, with a solid border, at offset (bordsize/2,bordsize/2) - you need the offset as otherwise the border edge will overlap the edge of the image.
Adding a shadow is pretty simple, rmagick has the shadow method:

shadow = image.shadow()
image = shadow.composite(image,Magick::NorthWestGravity, Magick::OverCompositeOp)

- this basically works, but sadly you get issues when you save the image. The shadow() method creates a shadow of a given image, with a specified shadow radius, which results in a larger image than the original - so the code above gives you an image which has shadow pixels at negative x and y coordinates!  Some file formats cope with this just fine - png files seem to do ok - but I wanted gif images for ie6 fallback, and gif doesn’t cope at all.

Anyway, to cut a long post short, the final code (see below) has a fair bit of logic for allocating extra space in the image for the shadow.  An example of the basic image-with-border-and-shadow image:

simple shadow sample

One last tweak I did - I wanted to have a shadow on the borders - the dark border is nice for some effects, but I wanted a slightly more 3d look:
sample with dark border
And a more subtle effect with the raised border the same colour as the diagram:
sample with light border

I also added some logic to set transparency of the image, for pretty backgrounds like the example from my last blog post (sample page here) - and to automatically save a gif version for ie6 display.

The full code can be seen at http://www.sietsma.com/korny/corner_test/corners_code.html

Obviously there’s lots of other things you can do - but this is a useful start!

Filed under: geek Leave A Comment »

Curved Corners with transparent png background on IE6

By Korny at 9:10 pm on Wednesday, June 11, 2008

I’ve been playing in the wonderful world of css - partly for work, and partly for fun.

I wanted to have fluid sized, png-based, rounded-corner dialogs for a web site. This is something that has been solved many times, but not (as far as I can see) for internet explorer 6 - which still has a big share of the browser market.

The best solution I’ve found for other browsers is the one by Scott Schiller at Schillmania - http://www.schillmania.com/content/projects/even-more-rounded-corners/ - which uses a single image, with cunning sprite tricks to get it into position. But on ie6, it has to revert to gif images.

The problem is, you can use pngs on ie6 - most simply, by using the iepngfix.htc behaviour trick (see http://www.twinhelix.com/css/iepngfix/) - but it has one big problem - you can’t align the png images to the right or bottom, so most of the usual tricks used to display corners don’t work.

So, I’ve been hacking around with ways to do corners where all the images are top-left aligned. I have a solution, I’m not sure it’s perfect, but it works - see the demo page at http://www.sietsma.com/korny/corner_test/test.html. This works in ie6, ie7, Firefox 2 and 3, and Safari.

Some caveats:

- it uses the iepngfix.htc behaviour - I experimented with using the Microsoft AlphaImageLoader stuff directly, but iepngfix does some tricks that I can’t reproduce easily, so for now I’m using the code directly.

- it’s a long way from semantic markup; there are a number of divs in there just to make it look right. I can’t see a way around this - I could make some javascript to turn a semantically-nice html page into the mess shown, which might be a good idea - but the end result would be the same (and doing it in javascript can make for ugly corner loading, and hassles re-running the javascript if you populate stuff via ajax). Anyone with hints on how to make this more web-standards-friendly, please tell! I’m still pretty new to the world of front-end stuff.

- there’s a bit of fiddling to make links work properly - the ie png stuff causes screwups if you use relative or absolute positioning on a div with a background image, and then add links to it.  So I had to mess around a bit to work around this - and I probably need to mess around more to make it cleaner.

- there are some ie-specific bits in there, added via conditional comments; at least one of them was pure trial-and-error to get things lining up right!

- there is probably more work needed to make padding and things consistent across browsers.

I’ll try to blog more later about the details, and about how I generated the images…

Filed under: work, geek Leave A Comment »

Faking DNS with Ruby and Sinatra

By Korny at 3:37 pm on Friday, March 7, 2008

I had an annoying problem, so I needed a hacky solution…

At work, we have a large number of boxes with dynamic IP addresses. Getting a static IP address is a complete pain, and keeping boxes running is bad for the planet.

IP addresses don’t *usually* change, but the do change often enough to be annoying - especially when you want to run a VMWare server to do something background-ish, and find that it’s IP address has changed and you have to open the console just to find the new address. Bleah.

I’m sure a DNS/DHCP trick could be done somewhere, somehow - probably setting up a special DNS server somewhere locally could be done. But I needed something quickly, so some ruby hackery was the solution…

Basically I set up a tiny web server running Sinatra, a really really simple web framework. It just listens to http posts containing mac addresses, host names, and IP addresses, and stores them (in a YAML text file on disk - this isn’t meant to be scalable!). It also serves up a general status page, plus a simple /etc/hosts file snippet containing all known hosts.

I then have a really tiny ruby script that I run on each other box, which posts that box’s IP address to the server whenever it changes. (Currently this means on Ubuntu boxes, it runs from /etc/network/if-up.d/, on RedHat it runs from a script called /sbin/ifup-local)

At any stage, a user can load the file served by the sinatra server at http://the_server:4567/hosts - this gives a snippet of text that can be pasted into an /etc/hosts file (or the Windows equivalent). I might automate this step eventually, but for now it’s a manual process; it’s usually pretty clear when your hosts file is wrong, and not that hard to update it.

The code is real simple. First, the script to post data from each machine - this basically runs ‘ipconfig’ and extracts useful fields, it would need fiddling to work on Windows or anywhere that had a different ipconfig command (or didn’t use ‘eth0′):
(note - file saved as text attachment to get around this blog’s limitations):
postip.rb

Next, the server. Sinatra does most of the work for me - but it’s documentation is kind of thin, so some bits took some fiddling. Still, it really doesn’t get much easier than this:
fakedns.rb

And that’s it!

Filed under: geek1 Comment »

Twitter, Twibble, GPS and Maps!

By Korny at 5:29 pm on Friday, February 15, 2008

I’ve been getting hooked on twitter - you can find me at http://twitter.com/kornys . Ephemeral micro-blogging! Beware, most of what I write is entirely trivial - but that’s half the fun.

Worse than that, I’ve found ‘twibble’ (http://www.das-zentralorgan.de/twibble/) , a java phone app that lets me sent tweets on the fly, and tags them with my GPS location!
So you can go to http://twittermap.com/maps, enter “kornys” and see where I’ve been. Unless I have a sudden rash of privacy concerns - but at the moment, this stuff is kind-of fun.

Filed under: geek — Comments Off

Windows on Ubuntu USB stick

By Korny at 9:56 am on Friday, August 3, 2007


I achieved a sad geek triumph the other day - a wonderful heath robinson
arrangement that lets me run Ubuntu linux on my work machine with
minimal risk.
In brief - ubuntu boots from a 4g usb stick. /home and other bits are
stored in a folder on my (ntfs) hard disk. And I can run Windows, from
my original drive, under Vmware!
Or I can pull out my usb stick, and my system will run Windows
normally, with almost no visible changes from it’s original setup.
Needless to say, this was rather complex to get working!

(update - I tried sending this on Wednesday, but due to flickr issues it only got here today… and in the meantime, I’ve had an episode where Windows on booting decided to chkdsk my drive, and found some minor errors. I’m now a bit anxious about the above… but I’ll keep struggling on with it!)

Filed under: geek — Comments Off