[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Re: [SOLUTION] metakoans.rb (#67

Greg Millam

2/19/2006 7:56:00 PM

Here's my solution: Took me about 15 minutes to solve the koans. I agree
with everyone else: Great quiz =). Continuous fiddling with it made me
late for a date, and when I tried explaining why, she just stared at me.
"Meta cones? What's that?" Ah well!

My koan solution, 9 lines:

def one_attribute(arg,&b)
name = (arg.is_a?(Hash) ? arg.keys[0] : arg).to_s
p = Hash.new( arg.is_a?(Hash) ? arg[name] : nil )
fun = lambda { |*args|
p[self] = *args unless args.empty?
(p.include?(self) or !b) ? p[self] : instance_eval(&b)
}
['','?','='].each { |ch| define_method(name+ch,&fun) }
end

And to make it accept multiple arguments to work with the benchmark
suites (10 lines):

def attribute(arg,&b)
attribute(*rest,&b) if rest.any?
name = (arg.is_a?(Hash) ? arg.keys[0] : arg).to_s
p = Hash.new( arg.is_a?(Hash) ? arg[name] : nil )
fun = lambda { |*args|
p[self] = *args unless args.empty?
(p.include?(self) or !b) ? p[self] : instance_eval(&b)
}
['','?','='].each { |ch| define_method(name+ch,&fun) }
end

With comments:

def attribute(arg,&b)
# Allow multiple attributes to be set and defined.
attribute(*rest,&b) if rest.any?

# The name of the attribute.
name = (arg.is_a?(Hash) ? arg.keys[0] : arg).to_s

# p holds all the attributes for each object.
# This is wasteful since in real use, this would cause
# Each object that's set an attribute to be kept in
# memory.
p = Hash.new( arg.is_a?(Hash) ? arg[name] : nil )

# The only method I define: It takes 1 or more arguments.
# If it's given an argument, it assigns. In all cases,
# It returns.
fun = lambda { |*args|
# Assign if necessary.
p[self] = *args unless args.empty?
# If it's been assigned, or there's no block, return
# Its saved value (Or Hash's default)
(p.include?(self) or !b) ? p[self] : instance_eval(&b)
}

# Assign that method to all 3 methods we need.
['','?','='].each { |ch| define_method(name+ch,&fun) }
end


More quizzes like this would be much appreciated. It rocked.

Ara++

- Greg


1 Answer

Greg Millam

2/20/2006 3:41:00 PM

0

As with everyone, it seems, some more twiddling and playing with this
yielded me a better, faster, and smaller solution.

This also beats my prior solution in that a? returns only true or false,
and variables are kept with the object rather than in a hash with the
object as a key. The reader methods also won't take an argument now.
(They did before.)

9 lines with a little golfing: (8 if you ditch the line for multiple
definitions, which isn't needed for passing the koans).

It's pretty much the same as most of the other solutions out there, now.

def attribute(arg,*rest,&b)
attribute(*rest,&b) if rest.any? # Allow multiple definitions.
n = (arg.is_a?(Hash) ? arg.keys[0] : arg).to_s
b ||= lambda { arg.is_a?(Hash) ? arg[n] : nil }
attr_writer n
define_method(n) { instance_variables.include?('@'+n) ? instance_variable_get('@'+n) : instance_eval(&b) }
define_method(n+'?') { ! [nil,false].include?(send(n)) }
end

Blast it, Ara, how do I stop myself from doing more and more tweaking? ;)

- Greg