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.]
Comments