Learnings for Week 23 2010

  • Recently needed to ignore some files that were already being tracked by git. This Link helped me out.
    • git update-index —assume-unchanged config/database.yml
  • HTML5 ‘type=search’ renders a nice search box and degrades to a simple input in older browsers.
  • HTML5 ‘placeholder=text’ renders placeholder text into an input that goes away when you click into it.
  • case; when ‘one’, ‘two’; to match ‘one’ or ‘two’ in a Ruby case statement.
  • Rails hide_action :action_name in a controller will prevent the action from being routed to.
  • jQuery “input” event gets fired when typing, pasting, cutting etc. from an input field.
  • jQuery live != livequery plugin. Main difference is live can only bind an event handler to the matching elements, livequery can run a function every time another element matches.
  • http://www.quickdiff.com super easy online tool to diff text.
June 23, 2010 | View Comments

Learnings for Week 22 2010

  • grep -rl ‘structure_dump’ . to recursivly search through a folder for the given string. mvim `grep..` to open them up.
  • alias ls=‘ls -GF’ so that ls is colored in all consoles.
  • nvarchar in SQLServer takes a limit from 0 to 4000 OR the keyword MAX. MAX != 4000, it is actually much larger.
  • When using Rails and the JDBC adapter queries SQLServer for nvarchar columns it gets the value back for limit, which when created with MAX is much larger than a limit you can use. This comes up when trying to create the database from schema.rb (testing).
  • Phocus gem to temporarily focus some tests, ignoring all others, even across test classes.
  • Harmony provides a simple DSL to execute javascript + DOM code within ruby.
  • Holy Grail execute browser-less, console-based, javascript + DOM code right from within your Rails test suite.
June 15, 2010 | View Comments

Learnings for Week 21 2010

  • A couple of interesting resources for getting rid of alias_method_chain in your code here and here
    • The basic idea in both of these is to create a module that defines the method you want to chain and call super in your redefinition. When you include the module into your class the modules method is insterted right above the instance’s class in the inheritance tree.
  • jQuery nextAll and prevAll functions to get all following/previous siblings of each element in the set of matched elements
  • cmd-shift-t reopens last closed tab in the web browser (chrome, firefox, safari).
  • A selected like ‘input + label’ matches all the labels that are directly beside an input. There is no way, with the same markup, to target the inputs directly beside a label (‘input - label’ someday, maybe?)
June 05, 2010 | View Comments

DSLs FTW!

I love programming in Ruby. It’s amazing how powerful and expressive the language can be. One of the best parts about Ruby is how easy it is to whip up a DSL (Domain Specific Language) to help clean up you code and hopefully make it more enjoyable (readable, understandable) to work with. I recently had the chance to cleanup some messy, hard to understand code with a really simple and easy to understand DSL and I thought it might be useful to share the basics doing something like this.

What We’re Working With

For this example lets say you’re writing some code that builds an html page. Lets say you have a class for each html element and a page is made up of a heiarchy of these html elements. The code to build a simple page might look something like this:

page = HTMLPage.new

form = FormElement.new(:id=>"new-user", :action=>"/user/new", 
  :parent=>page)
wrapper = DivElement.new(:class=>"wrapper", :parent=>form)

LabelElement.new(:text=>"Name", :parent=>wrapper)
InputElement.new(:name=>"name", :type=>"text", :parent=>wrapper)

InputElement.new(:text=>"Save", :type=>"submit", :parent=>form)

Okay, so you might not actually do something like this in reality but if you did and you were defining a bunch of pages and wanted to adjust each of them it would probably get confusing really fast. Even this simple example is a little hard to read as is…the Input is in the Form? Oh ya, it’s in the wrapper Div which is inside the Form. Confusing!

What will the DSL Look Like?

When I’m looking at some ugly code that I want to clean up I like to step back a little and write some code the way I want it to look and then work on making my DSL or whatever work towards that goal.

I would much rather be writing the stuff about in a way that looks something like this:

page do
  form "/user/new", :id=>"new-user" do
    div :class=>"wrapper" do
      label "Name"
      input "text", :name=>"name"
    end

    input "submit", :text=>"Save"
  end
end

To me something like that is a lot easier to follow, especially with something hierarchical like html or xml.

So that’s all well and good, but this looks pretty different than the code we had earlier, it might be a lot of work to build something to do this. Is it really work all that effort just so our code looks a little better? In all honesty it depends on the situation. If you have code like this on one little spot it might not be worth the effort. But writting a lot of unclear code all over the place then replacing it with a readable DSL will gain you many High Fives from future developers. Besides, it really isn’t that much work and DSLs are too cool to pass up, so lets get to it.

Building the DSL

Lets start out with something simple that will just define and return a couple of our elements.

class HTMLPageDSL
  def page(&block)
    page = HTMLPage.new
    yield
  end

  def form(options, &block)
    form = FormElement.new(options)
    yield
  end

  def div(options, &block)
    div = DivElement.new(options)
    yield
  end

  def input(options)
    InputElement.new(options)
  end

  def label(options)
    LabelElement.new(options)
  end
end

This little bit of code gives us the main structure of our DSL. It doesn’t quit work yet since there’s no way to set the parent attribute on each of the elements. Lets take care of that.

class HTMLPageDSL
  def page(&block)
    last = @current
    page = HTMLPage.new
    @current = page
    yield
    @current = last
  end

  def form(options, &block)
    last = @current
    form = FormElement.new(options.merge(:parent=>@current))
    @current = form
    yield
    @current = last
  end

  def div(options, &block)
    last = @current
    div = DivElement.new(options.merge(:parent=>@current))
    @current = div
    yield
    @current = last
  end

  def input(options)
    InputElement.new(options.merge(:parent=>@current))
  end

  def label(options)
    LabelElement.new(options.merge(:parent=>@current))
  end
end

Okay, wo what I’m doing here is just keeping track of whatever the current container element is and setting it to @current so that the elements being defined within the block can set it’s parent attribute. Lets take a look at what using our DSL might look like so far:

page do
  form :action=>"/user/new", :id=>"new-user" do
    div :class=>"wrapper" do
      label :text=>"Name"
      input :type=>"text", :name=>"name"
    end

    input :type=>"submit", :text=>"Save"
  end
end

That looks pretty close now! I have to be honest though, I cheated and made a little change so that this would be possible:

def page(&block)
  HTMLPageDSL.new(HTMLPage.new).instance_eval(&block)
end

class HTMLPageDSL
  def initialize(current)
    @current = current
  end
end

So I moved the page method outside of our DSL class and made it create an instance of HTMLPageDSL. We then call instance_eval giving the HTMLPageDSL object the block to evaluate.

The last thing I want to do is add a bit of syntax magic so we don’t have to type quite as much. At the moment we’re passing all the attributes as a hash, but in my initial example I could pass some options directly, without a hash.

First we add the following methods to HTMLPageDSL

class HTMLPageDSL
  private
    def setup_options(args, keys, current=nil)
      options = extract_options!(args)
      keys.each_with_index do |k, index|
        options.merge!(k.to_sym=>args[index]) if args[index]
      end
      current ? {:parent=>current}.merge(options) : options
    end

    # From Rails ActiveSupport
    def extract_options!(args)
      args.last.is_a?(::Hash) ? args.pop : {}
    end
end

After that we can use it in our DSL methods to let us pass array arguments or a hash to the method call.

class HTMLPageDSL
  def input(*args)
    options = setup_options(args, %w(type), @current)
    InputElement.new(options.merge(:parent=>@current))
  end
end

And that’s it. Now we can pass the type as the first argument to the call to input and any other options as a hash, or everything as a hash if we want.

Conclusion

So there we have it, a nice simple example of creating a DSL. This example isn’t perfect, that’s for sure, but it does show how to get started and how simple it can be.

Full Example Code:

def page(&block)
  HTMLPageDSL.new(HTMLPage.new).instance_eval(&block)
end

class HTMLPageDSL
  def initialize(current)
    @current = current
  end

  def form(*args, &block)
    options = setup_options(args, %w(action), @current)
    last = @current
    form = FormElement.new(options.merge(:parent=>@current))
    @current = form
    yield
    @current = last
  end

  def div(options, &block)
    last = @current
    div = DivElement.new(options.merge(:parent=>@current))
    @current = div
    yield
    @current = last
  end

  def input(*args)
    options = setup_options(args, %w(type), @current)
    InputElement.new(options.merge(:parent=>@current))
  end

  def label(*args)
    options = setup_options(args, %w(text), @current)
    LabelElement.new(options.merge(:parent=>@current))
  end

  private
    def setup_options(args, keys, current=nil)
      options = extract_options!(args)
      keys.each_with_index do |k, index|
        options.merge!(k.to_sym=>args[index]) if args[index]
      end
      current ? {:parent=>current}.merge(options) : options
    end

    # From Rails ActiveSupport
    def extract_options!(args)
      args.last.is_a?(::Hash) ? args.pop : {}
    end
end

# These classes added for completness so the example will run
class HTMLPage
  attr_accessor :children
  def initialize
    @children = []
  end
end

class HTMLElement
  def initialize(options={})
    @options = options
    options[:parent].children << self if options[:parent]
  end
end

class FormElement < HTMLElement
  attr_accessor :children
  def initialize(options={})
    @children = []
    super
  end
end
class DivElement < HTMLElement
  attr_accessor :children
  def initialize(options={})
    @children = []
    super
  end
end
class InputElement < HTMLElement; end
class LabelElement < HTMLElement; end

# Example Usage
p = page do
  form "/user/new", :id=>"new-user" do
    div :class=>"wrapper" do
      label "Name"
      input "text", :name=>"name"
    end

    input "submit", :text=>"Save"
  end
end
May 30, 2010 | View Comments

Learnings for Week 20 2010

  • If, for whatever reason, your Win XP install doesn’t show Remote Desktop in the start menu running ‘mstsc’ will start it up.
  • Until recently you couldn’t access the raw response from HTTParty. This can be confusing but most of the data can be found using proxied methods on the HTTParty::Response (code, headers, body, message).
  • Two very cool gems for simplifying html forms in rails: simple_form and formtastic. I’m using simple_form in a project right now and loving it.
  • rr seems to have a problem with mocked class methods sticking around between test calls. Issue opened.
  • Rails 3 respond_with helps clean up controllers by packaging up the standard respond_to cases for html, json, xml etc into one method. It’s also very extendable (responders gem has some nice ones).
  • Getting devise to authenticate by email or login is less trickier than it seems. Matt Tanase has a nice little post on how to do it. The key is remembering to change your initializer to have ‘config.authorization_keys :login’ in it.
May 26, 2010 | View Comments

Learnings for Week 19 2010

  • csshx - a tool to allow simultaneous control of multiple SSH sessions
  • sql server management studio (not express) can be used to generate scripts for a sql server database to recreate tables and data
  • The pattern of using modules to provide interface implementations used by the paperclip gem is extreamly powerful
May 20, 2010 | View Comments

Making the Switch to VIM

Well, after a couple years of using Textmate (and liking it for the most part) I’ve decided to change editors and have happily been using VIM for the last couple weeks. Why VIM? Nothing in particular stands out really. One of my co-workers is a big fan of it, I have to use it once and awhile when on the servers and emacs seemed to be a big pain in the ass :).

Here’s a few of the plugins I’ve installed that helped make me feel more at home in VIM:

NERDTree
This plugin gives you a project tree that you can use to navigate your project tree. I also mapped the ` key to toggle the tree making it super easy to open and close.

fuzzy finder and fuzzy finder textmate
These two plugins give the same functionality as cmd-t in Textmate, letting you quickly open files in the project. I mapped this to ,+t and ,+r to refresh the list.

rails vim
This gives a while pile of shortcuts and helpers for working with rails.

snipMate
Just like it sounds, this plugin gives you snippets much like Textmate has. Put that together with the snippets from scrooloose (Martin Grenfell) and we have access to lots of cool shortcuts.

These are the main plugins I added. I also included a shortcut to use ACK for search and a number of other little scripts and shortcuts to make myself more productive. I’ve got the whole set of config files up on github so you can use it, fork it, change it all you want.

May 13, 2010 | View Comments

Learnings for Week 18 2010

Learnings for the past week.

  • more vim fun
    • zf5j to fold the next 5 lines
    • zo to open a fold
    • zc to close a fold
    • c in visual block to substitute
    • ctrl+_ to complete html tag (with closetag plugin)
    • ctrl+w+_ to maximize splits vertically
    • ctrl+w+| to maximize splits horizontally
    • ctrl+w+= to equalize splits
  • after_initialize in a ruby model if you want something to happen when both new or create are called
  • instance_eval can be given a block. This is really powerful if you want to whip up a quick DSL to clean up some code (highly recommended).
  • Devise authentication plugin dropped support for MongoMapper until it conforms to ActiveModel (MongoMapper is in turn waiting until Rails 3 is final before making this change)
May 12, 2010 | View Comments

Learnings for Week 17 2010

Learnings for the past week.

  • vim (I made the switch this week!)
    • ctrl+v to enter visual mode (useful for block comments)
    • :sp to split a window
    • :vsp for vertical split
    • :A for alternate file (rails plugin)
    • snipmate for awesome snippets (plugin, snippets)
    • * searches for current word
    • :%s/search/replace/modifiers
      • if you leave search blank it uses your previous search
      • g modifier for global search, c to confirm each replacement (very useful!)
  • autotest doesn’t run in ruby 1.9.1
    • It fails for me saying “set a breakpoint in malloc_error_break to debug” and that’s about all
  • ruby -e “code to run”
  • assert_select(‘input’, 0) doesn’t work, need to use (assert_select ‘input’, :count=>0)
    • This is confusing since assert_select(‘input’, 5) works just fine

That’s it for this week. If I find some time I’ll post my vim config and talk about that a bit and maybe discuss what I did about autotest not working.

May 05, 2010 | View Comments

Learnings for Week 16 2010

Learnings for the past week. It was a busy one.

  • rvm uninstall leaves build files
    • rvm remove gets rid of everything
  • Firefox on Ubuntu gets thin black borders around images that are resized in html/css
    • Adding some transparency to the edges of the images fixes
  • rails i18n translation keys can’t have ‘.’ in them, even if escaped
  • -webkit-user-select/-moz-user-select:none; to disable selection on a webpage
  • Webkit doesn’t allow keyboard entry to 0 height inputs
  • Firefox and Webkit don’t allow keyboard entry to invisible inputs (display:none)
  • jQuery fadeOut doesn’t work on some (circle, line) svg elements in Webkit
  • jQuery.keypad on multiple inputs should check if the keyboard target is changing before updating the keypad (huge performance gains)
  • git cherry lists commits that don’t exist in another branch. Compares the changeset, not commit ids
  • gem install -f will install gem even if dependencies can’t be met
  • apt-get build-dep ruby1.8 will get you all the ruby build dependencies
  • git checkout -t -b BRANCH origin/BRANCH will checkout and track a remote branch
April 27, 2010 | View Comments