--------------090205020702090600080900
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

My solution is attached.  Actually, two different styles of the same 
solution.  Neither one is anywhere near 13 lines -- I'll be very 
interested to see the work of people who actually know this language.

A couple of subtleties.  (1) The first time the attribute is set, I 
redefine the setter and getter to just be ivar accessors.  (2) I only 
ever evaluate the block once: the initial version of the getter calls 
the setter with the result of evaluating the block.

And I'll echo everyone else: excellent quiz.

Luke Blanshard


--------------090205020702090600080900
Content-Type: text/plain;
 namenowledge.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filenamenowledge.rb"

style  code # or :string

case style
when :string
  class Module
    def attribute desc, &block
      if desc.is_a? Hash
        name  esc.keys[0]
        default  esc[name]
        raise "Hash or block, not both" if block
      else
        name, default  esc, nil
      end
      module_eval <<-"end;", __FILE__, __LINE__
        def #{name}?; #{name} ! il end            # Permanent definition of query method
        def __#{name}__ivarget;   @#{name}   end    # ivar getter and setter
        def __#{name}__ivarset v; @#{name}end
                                                            # Initial def of attr reader
        define_method(name) { self.#{name}  block ? instance_eval(&block) : default) }
        def #{name} alue                                  # Initial def of attr writer
          (class << self; self; end).class_eval do
            alias_method :#{name},  :__#{name}__ivarget     # Subsequent calls use ivar getter and setter
            alias_method :#{name}:__#{name}__ivarset
          end
          @#{name}  alue
        end
      end;
    end
  end

when :code
  class Module
    def attribute desc, &block
      if desc.is_a? Hash
        name  esc.keys[0]
        default  esc[name]
        raise "Hash or block, not both" if block
      else
        name, default  esc, nil
      end
      ivar_name  @#{name}"
      module_eval do
        define_method("#{name}?") {send(name) ! il}
        define_method("__#{name}__ivarget") {    instance_variable_get(ivar_name) }
        define_method("__#{name}__ivarset") {|v| instance_variable_set(ivar_name, v) }
        define_method(name) { send("#{name} block ? instance_eval(&block) : default) }
        define_method("#{name} do |value|
          (class << self; self; end).class_eval do
            alias_method "#{name}",  "__#{name}__ivarget"
            alias_method "#{name} "__#{name}__ivarset"
          end
          instance_variable_set(ivar_name, value)
        end
      end
    end
  end
end

--------------090205020702090600080900--