Living With Haml & Sass 2

Posted by Carsten Nielsen
on Wednesday, June 25

Haml is a pretty awesome templating language for marking up XML documents and hands-down brilliant for marking up XHTML, I think most people who “get it” use Haml whenever they can. We’ve been using it since day one at LearnHub, it makes my job a lot more enjoyable having yet another elegant tool at my disposal. And yes, it’s fast!

So pretty much everyone agrees Haml is fantastic, but what about Haml’s smokin’ hot sister; Sass? I have been using Sass exclusively on LearnHub since day one too, I find the benefits to be just as high as Haml if not higher, especially when it comes to nested selectors, less typing means less room for error and a document that is compact and easier to read.

There are not as many people out there using Sass though, and I think that is a shame. Sass lets you do some pretty nifty things that in turn give you great power. You can easily scope sets of rules to certain selectors and change them with ease, Sass removes all of the syntactic dirt and mostly all of the repetition from CSS. Consider the following example:


#content {
  margin: 0 8px; }
  #content .block {
    border: 1px solid #ddd; }
    #content .block p {
      font-size: 116%; }

Not bad, now let’s see it in Sass:


#content
  :margin 0 8px
  .block
    :border 1px solid #ddd
    p
      :font-size 116%

Sweet jeebas, why wouldn’t you want that?

Another one of my favorite things about Sass is the ability to declare constants, take the following for example, the ability to spec out all of your typefaces in one spot:


!display = "'lucida grande', 'trebuchet ms'"
!sans = "'helvetica neue', arial, 'dejavu sans'"
!serif = "georgia, times"
!monospace = "monaco, consolas, 'dejavu sans mono'"

And the power to do fun stuff such as:


!gunmetal = #ccc
!steel = !gunmetal + #111
!aluminum = !steel + #111

Now I personally don’t use evaluations in Sass very much, I find it easier to just declare everything explicitly, but I often use string concatenation in Sass everywhere:


.pillar
  .brick
    :border = "1px solid" !steel

In spite of Hampton raising an eyebrow, I break from convention and store my Sass documents in /app/sass which I then have compile out into /public/stylesheets/compiled this works better for me as it removes any confusion as to what stylesheets are Sass output and what are hand-coded CSS.

To do this, simply set the following Sass options during initialization:


Sass::Plugin.options[:template_location] = File.join(RAILS_ROOT, 'app/sass')
Sass::Plugin.options[:css_location] = File.join(RAILS_ROOT, 'public/stylesheets/compiled')

I tip my hat to Nathan and the other contributors of Haml; it keeps getting better and better in terms of speed and features. I remember pre version 1.8 speed was a bit of a concern, but after its release the cynics stopped knocking. With the recent release of version 2 we have seen a slew of improvements and enhancements (better error messages, auto-escaping) as well as yet another speed boost — LOVE IT!

Informative & Painless URIs 0

Posted by Carsten Nielsen
on Saturday, June 21

There is just something nice about those cute URIs that we have all grown to love, I’m sure you’ve seen them around: http://pork.ham/lists/32-grocery-list. Guess what, these are fun and easy to implement, here’s how!

First we need a method that can convert a normal title or name into something safe for use in a URI, here’s my answer:


class ::String

  # Returns a version of self that is safe for inclusion in a URI.
  def urilize
    strip.
    gsub(' ', '-').
    gsub(/[-]+/, '-').
    gsub('&', 'and').
    downcase.
    scan(/[a-z0-9\-]*/).to_s
  end

end

Users enter the darnedest data, so your urilize implementation will probably be tweaked over time. Anyways, the above String extension let’s us do stuff like:


'My Name Is Mud!'.urilize # => "my-name-is-mud"
'Awesome  &  Cool Stuff!!!'.urilize # => "awesome-and-cool-stuff"

Now we need a seamless way to get this functionality into our models so that they start throwing around all of these cool URIs for free. My answer to this is a sweet and simple mixin:


module Findable

  def self.find(*args)
    if args.first.is_a?(String)
      id = /(\d+)-?/.match(args.slice!(0))[1]
      super id.to_i, args
    else
      super args
    end
  end

  def to_param
    to_s.blank? ? id.to_s : "#{id}-#{to_s.urilize}"
  end

end

In order for our mixin to work we need our ActiveRecord models to have an overloaded to_s method that returns the title or name of the object. This is good practice and you should be doing it in any model where it makes sense to do so.

Anyways we can use our mixin as follows:


class Ticket < ActiveRecord::Base

  include Findable

  ...

  def to_s
    title
  end

  ...

end

Now imagine we have the following ticket in our database:


id: 6
created_by: Captain Obvious
assigned_to: Developer Dude
title: Feature Improvements
body: This massive feature that you implemented in far too little time is imperfect!

Assuming resourceful routes for Tickets we can do something like:


ticket = Ticket.find(6)
ticket_path(ticket) # => "/tickets/6-feature-improvements"

Neat.

Method Name Hack 1

Posted by Carsten Nielsen
on Friday, June 13

Ruby lets you do some pretty fun stuff, from highly elegant and useful to interesting and hacky. This is more of a hack than anything but it demonstrates some cool concepts.


module ::Kernel

  private
  # Allows you to get the name of the current method inside that method.
  # Example:
  #
  #   def hello
  #     __method_name__
  #   end
  #
  #   hello # => "hello"
  def __method_name__
    caller[0].scan(/`(.*)'/).to_s
  end

end

Ruby let’s you extend anything and everything, which is pretty powerful. The two preceding colons in ::Kernel tell Ruby to access the Kernel module in the global object space, if we were already there they would not be necessary but to be safe it’s best to add them.

Ruby maintains a call stack which is basically an array of strings that look like:


/Users/carsten/Projects/coolness/cool.rb:12:in `awesome_method'

This lets us know the path and file name as well as the line number and method name; neat. Then we just do a cute little regular expression scan and we can see the name of the method we are inside of.

Go To Helper Method: TextMate Command 0

Posted by Carsten Nielsen
on Wednesday, June 11

If you’re like me you use a lot of view helpers, stored in many different files. On big projects it’s not always easy to remember what helper came from where. You can use naming schemes and other organizational techniques, but you still have to take a few steps to get to the file and then find the method. Life is hard.

Or is it!? Life is easy when you use my Go To Helper Method command for TextMate! It does a simple grep of the current project’s /app/helpers directory (and sub-directories) for the method name in question and then opens the file and places you at the appropriate method. This approach works well because helper methods are usually all in the same namespace.

For the command to work properly you must have a TextMate Project of your application’s root open with at least the /app directory referenced. You can then run the command by placing the cursor on (or selecting) the name of a helper method in any Ruby, Haml or ERb file, then hitting the default key-sequence of Shift→Cmd→H; magic ensues.


#!/usr/bin/env ruby -w
require File.join(ENV['TM_SUPPORT_PATH'], 'lib/textmate')

PROJECT_DIR = ENV['TM_PROJECT_DIRECTORY']
METHOD_NAME = ENV['TM_CURRENT_WORD'] || ENV['TM_CURRENT_SELECTION']

def blank?(string)
  string.nil? || string.strip.eql?('')
end

def helpers_dir
  File.join(PROJECT_DIR, 'app/helpers/*')
end

def grep_and_go_to!
  method_name = Regexp.escape(METHOD_NAME)
  grep = `grep -rnE "def #{method_name}([\( ]{1}|$)" #{helpers_dir}`
  filepath, line = grep.match(/^.+:[\d]+/).to_s.strip.split(':')
  if filepath && line
    TextMate.go_to(:file => filepath, :line => line)
  else
    puts 'Could not find a matching Helper file'
  end
end

if blank?(PROJECT_DIR)
  puts 'Go To Helper Method only works in a project!'
elsif blank?(METHOD_NAME)
  puts 'Place the cursor over the name of a Helper method'
else
  grep_and_go_to!
end

The command works well inside Merb1 and Rails projects. It probably works with other stuff too if there are Ruby files in /app/helpers.

Update

If you think this is neat check out EasyOpen by Eiji Ienaga over on GitHub, it makes my simple command here look like childs play!

Download It Here

1. That’s if you’ve decided to keep your helpers in /app/helpers.