I generally use define_method only because it works better with the
syntax highlighting of SciTE, and also make the code look a little
unnatural... you also can't pass in real objects to be used by the
method, only things that are stringable.
class_eval %{
def #{method_name}(*args)
stuff
end
}
gets all screwed up (the #{} string is treated as a comment), but
define_method :method_name { |*args|
stuff
}
works fine. If I was trying to make it run fast, I'd probably be using
class_eval, not define_method.
Evals can be slow, but you're only doing the eval once when it's a
class_eval, and then it's just like any other method, whereas with
define_method you're calling off to the proc object every time, which is
slower than a method call for each and every call.
···
-----Original Message-----
From: Trans [mailto:transfire@gmail.com]
Sent: Saturday, 22 October 2005 10:37 PM
To: ruby-talk ML
Subject: Re: Reflection, observ(er|able) instance vars?
Hugh Sasse wrote:
> This "delivers us from eval"
but does define_method
offer anything
> else over the class_eval %{...} approach? Maybe [only :-)] speed?
Daniel makes some fair points, but there's nothing wrong with
using class_eval here. In fact with eval it's more concise
the resulting code will be faster.
T.
#####################################################################################
This email has been scanned by MailMarshal, an email content filter.
#####################################################################################
I generally use define_method only because it works better with the
syntax highlighting of SciTE, and also make the code look a little
unnatural... you also can't pass in real objects to be used by the
[...]
works fine. If I was trying to make it run fast, I'd probably be using
class_eval, not define_method.
I couldn't get the class_eval form to work.
Evals can be slow, but you're only doing the eval once when it's a
class_eval, and then it's just like any other method, whereas with
define_method you're calling off to the proc object every time, which is
slower than a method call for each and every call.
I don't know by how much. Anyway, this will be much faster than
doing a full compare each time, and faster than doing a hash each
time, so I don't really need to milk the last drop.
Here is what I ended up with in the end. It does what I want.
If anyone feels like improving on it, you are welcome to do so.
Thank you
Hugh
#!/usr/local/bin/ruby -w
···
On Tue, 25 Oct 2005, Daniel Sheppard wrote:
#
# Ruby-Talk:161789 from: "Daniel Sheppard" <daniels@pronto.com.au>
# Provides hashing for an object based on instance vars, and handles
# changes to those vars gracefully.
# The thread begins with Ruby-Talk:161631.
#
# Modified by Hugh Sasse to move it into class Class so attr_hashing
# works like the other attr methods. Also added code so that
# freezing works correctly: Hash works faster with frozen objects.
#
# require 'fasthashequals'
# class Example
# attr_hashing :this, :that, :other
#
# end
#
# For getting an array back as Ruby code.
class Array
def display
return "[ "+ map{|x|
x.inspect
}.join(', ') + " ]"
end
end
class Class
# attr_hashing needs to be a method of class to be useable as
# the other attr methods are. This method sets up the
# informtion and methods needed to create the hash from those
# instance variables.
def attr_hashing(*arr)
stararr = arr.flatten
# puts "stararr is #{stararr.inspect}"
(stararr).each do |sym|
attr_reader sym
end
hashers = class_eval "@@__hashers ||= "
hashers.concat(stararr)
hashers.uniq!
# puts "@@__hashers = " + hashers.display
class_eval "@@__hashers = " + hashers.display
stararr.each do |var|
define_method(var) {
instance_variable_get("@#{var}")
}
define_method("#{var}=") {|obj|
instance_variable_set("@#{var}", obj)
instance_variable_set(:@__equals_hash, nil)
}
define_method('eql?') { |other|
hash === other.hash && hashers.all? { |x|
send(x) == other.send(x)
}
}
define_method('hash') {
# puts "in hash, self is #{self.inspect}"
@__equals_hash ||= hashers.inject(0) do |s,x|
s + instance_variable_get("@#{x}").hash
end
}
# Once we freeze an object we can't update its hash again
define_method('freeze') {
hash
super
}
end
end
end