No coffee outside. How do they expect me to survive? However, the signs are out for the box lunches and they look to not suck.

Jim starts with a slide of a Flame Maple guitar back. Very beautiful.

Jim’s journey: FORTRAN (Physics),  Lisp (in a fortran class taught by Daniel Friedman), C, Modula 2, C++, Eiffel, Java, FORTH, TCL, and Perl.

On learning Lisp: “Yes, these are your father’s parentheses”

Out to show interesting techniques that aren’t Java-esque.

Box 1: Master of Disguise, Rake::FileList

It’s essentially a specialized array which can be init’d with a GLOB, has some extra methods including a custom to_s, and is a lazy evaluator. First cut inherited from Array (very non-Java, this inheriting from a concrete class)

Be sure to call super in subclass initializers.

Overrides Array’s various accessor methods to cause them to all auto-resolve on access. This makes fl + […] work, but doesn’t help with […] + fl … so implement to_ary which is automatically called. Which would be peachy except that inheriting from Array causes this not to be called. So don’t inherit from Array; instead contain one (and cause all your previously overridden accessors to access the contained array)

def [](index)
  resolve unless @resolved
  @items[index]
end

(and he showed an excellent metaprogramming method to handle defining all the accessors)

Box 2: The Art of Doing Nothing, Builder::XmlMarkup

uses method_missing to construct tag accessors, but what about name collisions (e.g. class)?

Inherits from BlankSlate (not Object):

class BlankSlate
  instance_methods.each do |name|
    undef_method name unless name =~ /^__/
  end
end

Kernel is a module included on all Objects, so this is icky:

require ‘blank_slate’

class Kernel
  def foo
    ‘foo’
  end
end

And now BlankSlate is not blank. So use method_added hook (in Kernel) to catch when anyone reopens the class, then use that to have BlankSlate hide/remove the method if someone adds something to Kernel. Excellent, until:

module Foo
  dev foo
    ‘foo’
  end
end

class Object
  include Foo
end

@#%&! Time for the append_features hook and a nearly identical implementation.

Box 3: Parsing without Parsing,

Wouldn’t it be nice to do this:

User.select { |user|
  user.name == ‘jim’
}

The Naive Implementation

class User
  def self.select(&block)
    find(:all).select(&block)
  end
end

… perhaps a bit inefficient as you do a full table scan. ;] Might be good to offload the work to the database (but how to avoid SQL?)

class User
  def self.select(&block)
    cond = block_to_condition(block)
    find(:all, :conditions => cond)
  end
end

Use ParseTree: a la Ambition

user = TableNode.new(“users”)
result = user.name
puts result.to_s
users.name # <– that’s the SQL fragment to reference the db column

class TableNode < Node
  def initialize(table_name)
    @table_name = table_name
  end

  def method_missing(sym, *args, …

[I can’t keep up. We’ll find his slides. I’m going to nap at lunch.]



blog comments powered by Disqus

Published

02 November 2007

Categories

ruby/rails rubyconf 2007