Reflection, observ(er|able) instance vars?

H

Hugh Sasse

I have an object for which equality tests take a long time, and I
have lots of others to compare it with. It is
an instance variable of my class, and it is also accessble by
attr_accessor. I'd like to hold a hash (number not Hash.new()) for
this object so I can compare it quickly with another. How do I detect that
it has changed so that the hash gets updated correctly? Does attr_accessor
construct code that leaves the right hooks in to detect this, or
must I write my own? Should attr_accessor do that if it doesn't?
Can I trap this by interposing in freeze tests, somehow?

If this is a code smell, how should I handle frequently queried,
slow-to-test, but changing instance variables? Make them all observables
and use update()? (That sounds expensive.)

Thank you
Hugh
 
E

Edward Faulkner

--BOKacYhQ+x31HxR3
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

I'd like to hold a hash (number not Hash.new()) for this object so I
can compare it quickly with another. How do I detect that it has
changed so that the hash gets updated correctly?

I think the simplest solution it to define your own attribute writer
and always use it:

class Test
attr_reader :my_attribute
def my_attribute=(val)
@my_attribute = val
@my_attribute_hash = make_hash(val)
end

def some_other_method
# Do this
my_attribute = something_new
# Not this!
@my_attribute = something_else
end
end

regards,
Ed

--BOKacYhQ+x31HxR3
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: Digital signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)

iD8DBQFDV7OunhUz11p9MSARAp3FAJ0W2bu0HfRIOHl+b1zkV9Za3wqx1gCeL3CX
0Qzu9Cb8TOi8U9e1Yo9KkSY=
=Aseo
-----END PGP SIGNATURE-----

--BOKacYhQ+x31HxR3--
 
H

Hugh Sasse

I think the simplest solution it to define your own attribute writer
and always use it:

[...]

If only I could add it to object. I've tried, but _Why's metastuff
confuses me just sufficiently to stop me making the transition.

Given metaid.rb thusly:
<quote>
#!/usr/local/bin/ruby -w
#
# Due to Whytheluckystiff.
# http://www.whytheluckystiff.net/articles/seeingMetaclassesClearly.html
# Reformatted to work around bugs in vim indent.
#
#
class Object
# The hidden singleton lurks behind everyone
def metaclass
class << self
self
end
end
def meta_eval &blk
metaclass.instance_eval &blk
end

# Adds methods to a metaclass
def meta_def name, &blk
meta_eval { define_method name, &blk }
end

# Defines an instance method within a class
def class_def name, &blk
class_eval { define_method name, &blk }
end
end

</quote>

and hashing.rb thusly:

<quote>
#!/usr/local/bin/ruby -w
#
# Make a class keep its hash up to date by using
# accessor methods that call hash on update.
#
# Hugh Sasse
# created: 20-OCT-2005
#
#

require 'metaid' # See http://www.whytheluckystiff.net/articles/seeingMetaclassesClearly.html

class Object
def self.attr_hashing( *arr )
attr_reader *arr
arr.each do |var|
meta_def var do |val|
@var
end
vareq = (var.to_s + "=")
meta_def vareq do |val|
instance_variable_set( "@#{var}", val )
self.hash
end
end
=begin
class_def :initialize do
self.class.traits.each do |k,v|
instance_variable_set( "@#{k}", v )
end
end
=end
end
end

</quote>

which I've produced from some badly aimed kicks at Dwemthy's Array,
I can't actually get the results I'd like.


<quote>
#!/usr/local/bin/ruby -w
#
# Test out the hashing prog.
#

require 'hashing'

class Wombat
attr_hashing :wom, :bat
attr_reader :thehash

def initialize
@wom = "wom"
@bat = "bat"
@thehash = hash
end

def hash
puts "hash called"
@thehash = (@wom.to_s + @bat.to_s).hash
end

def to_s
@wom.inspect + @bat.inspect
end
end

x = Wombat.new # produce the hash message
puts x
puts x.wom
puts x.bat
puts x.methods.sort.join(', ')
x.wom = "WOM" # produce the hash message
puts x.wom
x.bat = "BAT" # produce the hash message
puts x.bat
</quote>

Does anyone feel inclined to help me out? :)
regards,
Ed
Thank you,
Hugh
 
T

Trans

Use Module, or better yet your own mixin. And just do the class eval
yourself w/o metaid, it's pretty easy

module HashAttr

def attr_hashing( *arr )
attr_reader *arr
arr.each do |var|
class_eval %{
def #{var}(val) ; @var ; end
}
class_eval %{
def #{var}=(val)
@var=val
@thehash = nil #reset
end
}
end
end

end

Then do

class Wombat
extend HashAttr

attr_hashing :wom, :bat
attr_reader :thehash

def initialize
@wom = "wom"
@bat = "bat"
@thehash = nil
end

def hash
puts "hash called"
@thehash ||= (@wom.to_s + @bat.to_s).hash
end

def to_s
@wom.inspect + @bat.inspect
end

# compare
def ==( other )
hash == other.hash
end
end

HTH,
T.
 
H

Hugh Sasse

Use Module, or better yet your own mixin. And just do the class eval
yourself w/o metaid, it's pretty easy

module HashAttr

def attr_hashing( *arr )
attr_reader *arr
arr.each do |var|
class_eval %{
def #{var}(val) ; @var ; end
}
class_eval %{
def #{var}=(val)
@var=val
@thehash = nil #reset
end
}
end
end

end

That's very nice! :)
Then do

class Wombat
extend HashAttr

attr_hashing :wom, :bat
attr_reader :thehash

def initialize
@wom = "wom"
@bat = "bat"
@thehash = nil
end

def hash
puts "hash called"
@thehash ||= (@wom.to_s + @bat.to_s).hash
end

def to_s
@wom.inspect + @bat.inspect
end

# compare
def ==( other )
hash == other.hash
end
end

HTH,

Yes, that's much simpler than the knots I'd got myself into. Thank
you. That will help considerably.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,181
Messages
2,570,970
Members
47,537
Latest member
BellCorone

Latest Threads

Top