Mr eel

CSS - Image Replacement Hot Melon Jam Fu

There are loads of image replacement techniques and I think I’ve experimented with most of them. More recently I’ve hit on a set of rules that are pretty bulletproof and thankfully don’t require any kind of hacks.

It hinges on using the letter-spacing rule — big ups to Beej for putting me onto that one. The basic idea is that you set the letter spacing to a negative value. The text essentially collapses and disappears. The best part is that the element doesn’t otherwise change. It still keeps it’s width, height and positioning. You can now freely change the height or width without having to make hacks to accommodate Internet Explorer’s horrible rendering engine.


.imageReplacement {
  background:left top no-repeat url(/images/heading.gif);
  letter-spacing:-1000em;
  text-indent:-1000em;
  width:250px;
  height:70px;
}

There are two quirks to look out for here. Firstly the letter spacing has to be -1000em. After experimentation, other more patient people have discovered that it is the value that works reliably across most browsers. Secondly, the text-indent is there to hide the text in Safari and early version of IE, where the letter-spacing rule does not correctly apply. It forces the text to sit outside the container, so it disappears. Using both text-indent and letter-spacing together means you’ll hide the text reliably in most browsers.

I’m not sure it’s the Holy Grail of image replacement, but it’s pretty good!

P.S. .imageReplacement is a horrible class name. I only use it as an example. I prefer to use class names that refer to what the element is and what it does, rather than how it looks. Much easier to modify later on.

Posted on November 30th, 2007 | There are 2 comments

You Pimped the Dock? Jesus Christ, Why!

Every release of the Mac OS brings changes that people don’t like. My tack it to try and live with things before I complain about them. Usually it’s just an adjustment. Sometimes however, there are choices in the OS that are sub-par.

Leopard doesn’t bring many dramatic changes — from the user’s point of view. It’s mainly tweaks and improvements. Pretty much every part of the OS has had a good spit and polish. I’m happy to see slightly ropey interfaces like the networking preferences get a good going over. The Finder is actually… still a bit crap, since it can’t decide if it wants to be a spatial browser or not, but at least it’s not a slow motherbitch anymore. Best of all, the Finder doesn’t hang when network drives disappear. Honestly, that last one was the only thing I looked forward to in Leopard.

By and large, it’s nice. It’s faster, neater and visually more coherent.

Except… except the dock is tacky junk. It’s totally at odds with Apple’s hardware design aesthetic. Rather than simple, attractive and usable, we get the UI equivalent of hub-cap spinners. Tacky and pointless.

Don’t get me started on stacks. They suck completely. Give me back my hierarchical menus.

I even liked the transparent menu bar at first. I’m a sucker for gimmicks like anyone else. However after using it for awhile, I’ve found it to be pointless and at times unusable. Pick the wrong desktop and it gets a bit difficult to read. Oops! Besides that, it often just looks ugly, with weird gradients derived from the desktop image and whatever filtering Apple has applied to the menu.

I find these poor choices particularly striking and disappointing because they are so far away from how Apple approaches it’s hardware design. I’ll live, but man it’s irksome.

Posted on November 27th, 2007 | There are 0 comments

Rails - acts_as_tree Select Helper

Do you have a model with acts_as_tree? At some point you probably might want to generate a select with a representation of your tree — say categories and sub-categories for blog posts or something. I’ve seen some slightly nasty ways of doing this, so I thought I might try my hand at something cleaner.

Firstly, the most efficient way of building the options for the select is via recursion. Secondly, you shouldn’t try to do it with one method, otherwise you’ll end up checking conditions repeatedly — Is this the top level? Do I have to write out the select open or select close? — when you really don’t need to.

So I’ve split my helper into two methods. One to generate the select tag and another for the options. The method for the options recurses, going through each level in the hierarchy.


def select_for_tree(model, name, entries, options = {})
  # Grab the current value of the specified attribute
  current = instance_variable_get("@#{model}").send(name)
  # Build the option tags
  option_tags = options_for_tree(entries, current, 0)
  # Check to see if we need to include a blank entry at the top
  option_tags.insert(0, content_tag(:option)) if options[:include_blank]
  # Build the select tag
  select_tag("#{model}[#{name}]", option_tags, :id => "#{model}_#{name}")
end

def options_for_tree(entries, current, level)
  options = ''
  entries.each do |entry|
    attrs = {:value => entry.id}
    attrs[:selected] = 'selected' if entry.id == current
    options < < content_tag(:option, ("- " * level) + entry.name, attrs)
    # This is the bit that does the recursion.
    options << options_for_tree(entry.children, current, level + 1) unless entry.children.empty?
  end
  options
end

Not particularly clever, but it was interesting trying to get something reasonably simple and clean.

Posted on November 27th, 2007 | There are 3 comments

Funnily Enough… You Don’t End Up Where You Begin

Once my dearest wish was to become a graphic designer. It’s never really worked out for me. I don’t have any education in graphic design. I don’t know too many people in the field and I’ve never been able to find and undertake work I actually find interesting.

I’m capable enough, but most of the work I found myself doing was very boring, very conservative. That is inevitable. My flaw I think, was in romanticising graphic design, thinking that companies actually want something ‘interesting’ and ‘cutting-edge’. I’ve heard many people say this. They never actually mean it.

Perhaps in another time and place, I might have found receptive clients. Perhaps if I was a bit less naive I might have pursued interesting opportunities with more energy. But like I say, it just never really worked out.

So, gradually over time, I’ve devoted more energy to web development and from there to programming. There are strong elements of graphic design in web development certainly, but I find myself more interested in interfaces and how they work rather than just making things look nice. Or it might be more accurate to say I like to make things look and work well.

I don’t write any of this with a sense of regret. I’m perfectly happy with the path I’ve set myself on. It’s just interesting to consider how far away I am now from where I imagined I’d be all those years ago.

Posted on November 26th, 2007 | There are 1 comment

Just What The Bloody Hell is a Merb?

I’ve posted about Merb a few times, but I noticed I haven’t actually given anything like an introduction to the framework, which might be useful considering it’s not too well-known. Well, I’m not gonna do that since other nicer, better-spoken people have done it already. So here is a few links to get you started.

Merb

The official site, which has got a good overview of the framework and installations. I recommend starting with the Why Merb? page, which will hopefully convince you to give it a serious look. After that, look at the Features page.

Merb & Datamapper: Getting Rolling

A quick introduction to installing Merb and DataMapper. It should be enough to get you started coding. A slight aside; DataMapper is a really awesome ORM, my preferred choice when using Merb.

Wycats’ Introduction to Plugins

Plugins in Merb are implemented as Gems, not a custom format. The benefits for doing this are manifold. Here Wycats gives a good overview of both creating and using Merb plugins.

Wycats on the Mailer

Merb’s mailer is a very nice, well thought out bit of work.

Hassox - The Great Merb Speedup

Merb is pretty fast. The code in trunk is even faster. There has been loads of good work in the last month or so, which has seen Merb speed up many times over. Hassox has got some rather tasty benchmarks :)

Hassox - The Provides API

Previously Merb had a respond_to API similar to that in Rails. This has since been replaced with a cleaner alternative; the provides declaration.

Posted on November 22nd, 2007 | There are 0 comments

From the Roiling Sea…

Snippits of text, links, videos and all sorts of random nonsense. Yes, that’s right. I’ve finally got a Tumblelog. Late to the table, to only find scraps. But that’s OK because the more tumbling the better.

Posted on November 21st, 2007 | There are 0 comments

internets.search(”[text()*=Hpricot Kicks Arse]“)

There are far too many Ruby libraries I hear about and never use… until the one day I actually start playing with them and think “ZOMG this is awesome, why haven’t I used it before?”. I seem to do this a lot. Today, let’s talk about Hpricot.

It is essentially a library for navigating through HTML documents and extracting the contents. It’s the Rolls-Royce of screen-scrapers. It makes it extremely easy to select elements using CSS syntax, grabbing either an array of elements or the first match. Not only that, it’ll let you modify the contents of elements and output your updated document. As you might guess, there are many wicked things we can do with this!

But lets start out by scraping some results from Google. First step is to require Hpricot and Open-URI. We need open URI to actually retrieve the HTML from the server.


require 'rubygems'
require 'hpricot'
require 'open-uri'

Now lets actually open a url and generate a Hpricot document. Let’s search for some information on Behold… The Arctopus.


url = "http://www.google.com.au/search?hl=en&q=behold+the+arctopus&btnG=Search&meta="
doc = open(url) {|f| Hpricot(f)}

We call the open method in open-uri and pass in our URL. You can see I’ve stuck ‘behold+the+arctopus’ inside the query string. We also pass a block to open which gives us access to the HTML document returned. We pass this off to Hpricot, which then returns a Hpricot document. Now the fun begins!

Our Hpricot document has lots of nice methods in it for grabbing elements, their contents and manipulating them. So, let’s say I was looking for You Tube videos of our beloved Prog-Metal-Avant-Totally-Mental instrumentalists. We can do this by looking for an anchor which contains the words ‘YouTube’.


vids = doc.search("a[text()*=YouTube]")

We call the search method on the document and pass in our CSS selector. This returns a collection of matching elements. If we only wanted the first match, we can replace search with at. The selector is a little bit clever. It’s saying give us the anchors with text-nodes that contain ‘YouTube’ in them somewhere. Unlike most browsers, Hpricot supports a huge range of selectors. A bitter, bitter reminder of what we’re missing my friends.

Now, lets actually list out the links. We can loop through the collection and write out attributes for each. We can access the tag attributes for each element using the [] method, which we pass a symbol for the relevant attribute.


vids.each do |vid|
  puts vid[:href]
end

The code above would output:


http://www.youtube.com/watch?v=wniXxeTJlyM
http://www.youtube.com/watch?v=t80_eFghMdk

We also have access to the innerHTML of the elements:


vids.each do |vid|
  puts vid.inner_html
end

# Outputs
YouTube - <b>Behold... The Arctopus</b> in Guitar one magazine
YouTube - <b>Behold... The Arctopus</b> - Transient Exuberance

Now you can see that our link elements actually have bold tags nested inside of them. Since all the methods we have access to in the doc are available in the elements, we can select children elements with search. For no other reason that serving as a contrived example let’s go, YAAAAAAY!


vids.each do |vid|
  puts vid.at("b").inner_html
end

# Outputs
Behold... The Arctopus
Behold... The Arctopus

OK, so not that interesting, but I’m sure you can see how potentially useful Hpricot is. Want to programatically access a site without an API? OH HO HO HO! Hpricot for the motherbitchin’ win.

Posted on November 21st, 2007 | There are 0 comments

Ye Newbyes Gyde to Routing in Merb

The part of the Merb I’ve found most interesting lately is the routing. A fair number of people will be familiar with the routing in Rails. Have you ever considered how useful it is? For simple cases it does it’s job with no fuss, but if you want to get clever, most of the time you’re just out of luck.

Consider this; how do you route a request based on the subdomain? Can’t. How about based on the protocol? Nope. The port number? Naah. How about using a regular expression to analyze a URL? Shit out of luck my friends.

Merb’s routing holds the answers! It can do all of that with a much nicer syntax in it’s DSL. So, for the sake of illustration I might run through a few examples from an application I’m currently working on — I’m no expert, so these will just be simple ones.

First something real simple. Sending requests on the root url to a particular controller and action. First we match() the url. Then we specify the controller and action we want to send it to. OK… so not that clever.


r.match('/').to(:controller => 'home', :action => 'index')

Another simple one to demonstrate the use of place holders in the match. Any parts of the URL that appear where you specify a place holder will then be available in the routing.


r.match('/:controller/:action').
  to(:controller => ':controller', :action => ':action')

Just to demonstrate, you could have a weird URL scheme like this:


r.match('/:id/:controller').
  to(:controller => ':controller', :action => 'show', :id => ':id')

Now time to show some awesomeness. You can send requests to controllers that live in a particular module based on the subdomain.


r.match('/:controller/:action', :subdomain => ':subdomain').
  to(:controller => ':subdomain/:controller', :action => ':action')

This would be perfect for redirecting the requests via an admin subdomain. So requests to admin.domain.com/users would get sent to the controller/action Admin::Users#index. Nice!

I should also point out that you can also easily turn each one of these route declarations into a named route. Like so:


r.match('/login').to(:controller => 'users', :action => 'login').name(:login)

You just call #name at the end of the route declaration and pass in a symbol which will be the name you can then use in your #url calls inside controllers and views.

Ok, one last cool thing. You can match to a segment of a URL, then define a bunch of sub-matches. This is done by passing a block to the match method.


r.match('/admin') do |admin|
  admin.match("/:controller").
    to(:controller => "admin/:controller", :action => 'index')
  admin.match("/:controller/:id").
    to(:controller => "admin/:controller", :action => ":show", :id => ':id')
  %w(edit delete).each do |action|
    admin.match("/:controller/:id/#{action}").
      to(:controller => "admin/:controller", :id => ":id", :action => action)
  end
end

So what I’ve done here is match against /admin then we go onto our sub-matches. First the controllers index action. Then with an id, we map to the show action. Finally we map to the new and delete actions. This isn’t a real world example, since we’re only crudely emulating RESTful routing, but it shows how flexible you can be with matching parts of a url.

In my next Merb(ivorian) post I’ll go into a little more detail about the resources route declarations and doing some more clever stuff with ports and sub-domains. OH YEA.

Posted on November 20th, 2007 | There are 1 comment

New Site, New Site I Even Love Saying the Word Site

So, I got a bit bored and stuff. For no particular reason, I thought I might have a go at redoing the design for this blog. I like what I’ve ended up with. It’s well serious.

It was an experiment with trying to get the markup as minimal as possible. I’ve only used three divs, the rest is all nice semantic stuff. The next step is to actually get it to validate as XHTML 1.1. This might be a bit tricky since every link needs to have a title attribute — eeek! — and the source needs to start with the XML prolog. The last is a tricky one. Many many browsers and servers just blow up when trying to serve an XML doc using the text/html mime-type — which is derived from the extension.

Validation seems positively quiotic sometimes. I shouldn’t say it less the standards-types beat me up, but I really don’t see the point of many of the requirements in the spec. So rather than fussing about it, I figure I’ll just work to keep things neat, tidy and consistent.

That will have to do.

Posted on November 20th, 2007 | There are 2 comments

Fixtures with Datamapper and Merb

If you’re to be using Datamapper with Merb, you might be wondering how to get your test fixtures into your test database.

Thankfully it’s pretty simple. For those of you using Rspec, just stick this bit of code in you spec/spec_helper.rb


# Make sure the schema is in sync
DataMapper::Base.auto_migrate!

def fixtures(*files)
  files.each do |name|
    klass = Kernel::const_get(Inflector.classify(Inflector.singularize(name)))
    entries = YAML::load_file(File.dirname(__FILE__) + "/fixtures/#{name}.yaml")
    entries.each do |name, entry|
      klass::create(entry)
    end
  end
end

If you haven’t seen the auto_migrate! in DataMapper before, be aware that it destroys and recreates your database schema. I like to add it to my spec_helper so that the test DB is in sync with development, without me having to run a rake task.

This method assumes your fixtures are in the spec/fixtures directory and use the yaml extension. If you’re using .yml instead, you’ll need to change the third line in the fixtures method.

Now just call fixture inside your describe blocks.


describe "make sure the yowie is real" do
  fixtures :yowies
end

Keep in mind this will likely be a bit slow if you have loads and loads of fixtures, but for simple cases it works nice!

Posted on November 12th, 2007 | There are 0 comments

All contents © 2005—2007 Luke Matthew Sutton