L
Luke Blanshard
--------------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;
name="knowledge.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="knowledge.rb"
style = :code # or :string
case style
when :string
class Module
def attribute desc, &block
if desc.is_a? Hash
name = desc.keys[0]
default = desc[name]
raise "Hash or block, not both" if block
else
name, default = desc, nil
end
module_eval <<-"end;", __FILE__, __LINE__
def #{name}?; #{name} != nil end # Permanent definition of query method
def __#{name}__ivarget; @#{name} end # ivar getter and setter
def __#{name}__ivarset v; @#{name}=v end
# Initial def of attr reader
define_method(name) { self.#{name} = (block ? instance_eval(&block) : default) }
def #{name}= value # 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} = value
end
end;
end
end
when :code
class Module
def attribute desc, &block
if desc.is_a? Hash
name = desc.keys[0]
default = desc[name]
raise "Hash or block, not both" if block
else
name, default = desc, nil
end
ivar_name = "@#{name}"
module_eval do
define_method("#{name}?") {send(name) != nil}
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--
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;
name="knowledge.rb"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
filename="knowledge.rb"
style = :code # or :string
case style
when :string
class Module
def attribute desc, &block
if desc.is_a? Hash
name = desc.keys[0]
default = desc[name]
raise "Hash or block, not both" if block
else
name, default = desc, nil
end
module_eval <<-"end;", __FILE__, __LINE__
def #{name}?; #{name} != nil end # Permanent definition of query method
def __#{name}__ivarget; @#{name} end # ivar getter and setter
def __#{name}__ivarset v; @#{name}=v end
# Initial def of attr reader
define_method(name) { self.#{name} = (block ? instance_eval(&block) : default) }
def #{name}= value # 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} = value
end
end;
end
end
when :code
class Module
def attribute desc, &block
if desc.is_a? Hash
name = desc.keys[0]
default = desc[name]
raise "Hash or block, not both" if block
else
name, default = desc, nil
end
ivar_name = "@#{name}"
module_eval do
define_method("#{name}?") {send(name) != nil}
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--