eval
evil, it was not ever really necessary. He suggested that the attr_r
, attr_w
, and attr_rw
could be better implemented by using define_method
, instance_variable_get
, and instance_variable_set
. So, as I like to do after someone smart shows me a better way of doing things, I reimplemented our last piece of code using these methods. It's really pretty straightforward so there's not much to really talk about, so here it is:# Open the class Class and add three new access methods, access_r, access_w, access_rw.
# These are really just reimplementations for attr_reader, attr_writer, attr_accessor.
# This version will use define_method, instance_variable_get,
# and instance_variable_set to do this (based on a recommendation from Gregory Brown.
class Class
# Provide read access only. Take a list of symbols and create a
# method that will all the user to access each symbol.
def access_r(*symbols)
symbols.each do |symbol|
define_method(symbol) do
instance_variable_get("@#{symbol}")
end
end
end
# Provide write access only. Take a list of symbols and create a
# method that will all the user to write each symbol.
def access_w(*symbols)
symbols.each do |symbol|
define_method("#{symbol}=") do |val|
instance_variable_set("@#{symbol}", val)
end
end
end
# Provide read/write access. Take a list of symbols and create two
# methods that will all the user to read and write each symbol.
def access_rw(*symbols)
symbols.each do |symbol|
define_method(symbol) do
instance_variable_get("@#{symbol}")
end
define_method("#{symbol}=") do |val|
instance_variable_set("@#{symbol}", val)
end
end
end
end
if __FILE__ == $PROGRAM_NAME
# Using the new attribute accessor methods.
class Foo
access_r :bar
access_w :qux
access_rw :baz, :quux
# Since bar is read only from the outside, we'll just initialize
# it here.
def initialize(bar)
@bar = bar
end
# Since qux is write only, we'll create a method that lets us view
# it.
def show_qux
puts "qux = #{@qux}"
end
end
# Create a new foo and initialize bar (read only) with goodbye.
# Show that we can then access it.
foo = Foo.new ("goodbye")
puts "foo.bar = #{foo.bar}"
# Set and then access the two variables we set to
# read/write.
foo.baz = "hello"
puts "foo.baz = #{foo.baz}"
foo.quux = "world"
puts "foo.quux = #{foo.quux}"
# Set the write only field and then display it using the show_qux
# method.
foo.qux = "test"
foo.show_qux
# Try to access the write only field for reading. This should
# fail with an undefined method.
puts foo.qux
end
Like I said, it's all pretty straightforward. Also, here's a link to someone who's done something very similar using the same technique (there's some other good posts in there, so take some time and read a bit of it).
As always, let me know if you have questions or comments and thanks to Gregory Brown for starting me down this path.