Dynamically created attributes

I’d like to specify a quantity of object attributes when creating an
instance of an object. For example, I would like to create a Grid object
with 4 different ‘row’ attributes like this: Grid.new(4). Here’s some
dirty code that does that:

class Grid
#Creates row1, row2, etc. depending on row arg
def initialize(rows)
row_count = 1
rows.times do
instance_eval “@row#{row_count} = ‘xxx’”
row_count += 1
end
end
end

It’s dirty, but it creates the attributes. I don’t see how to
dynamically create accessor methods for all these attributes though. Any
suggestions? I sense there’s a better way to do this.

Alle lunedì 12 gennaio 2009, Peter M. ha scritto:

  instance_eval "@row#{row_count} = 'xxx'"
  row_count += 1
end

end
end

It’s dirty, but it creates the attributes. I don’t see how to
dynamically create accessor methods for all these attributes though. Any
suggestions? I sense there’s a better way to do this.

Well, the first thing I can think of is to replace your n instance
variables
with a single instance variable @rows which will be an array and contain
the
rows. Something like this:

class Grid

attr_reader :rows
def initialize(rows)
@rows = Array.new(rows){ ‘xxx’ }
end

end

If you don’t want to make the array availlable from outside the
instance, you
can skip the attr_readr line and provide methods to directly access the
rows.
For example, you can define [] and []= methods as array does:

class Grid

def
@rows[idx]
end

def []=(idx, value)
@rows[idx] = value
end

end

If you truly want to use an instance variable for each row, see the
documentation about instance_variable_set and look at the section
“Object
specific classes” in the “Classes and Objects” chapter of the online
edition
of the Pickaxe book
(Programming Ruby: The Pragmatic Programmer's Guide)

I hope this helps

Stefano

On Mon, Jan 12, 2009 at 9:25 AM, Peter M. [email protected]
wrote:

 instance_eval "@row#{row_count} = 'xxx'"

Maybe this is cleaner:

class Object
def singleton_class
class << self; self; end
end
end

class Grid
def initialize rows=0
rows.times do |i|
instance_variable_set “@row#{i}”, “initial value”
singleton_class.instance_eval {attr_accessor “row#{i}”}
end
end
end

irb(main):020:0> a = Grid.new 3
=> #<Grid:0xb7c02008 @row0=“initial value”, @row2=“initial value”,
@row1=“initial value”>
irb(main):021:0> a.methods.grep /row/
=> [“row0”, “row0=”, “row1”, “row1=”, “row2”, “row2=”]

Hope this helps,

Jesus.

On Mon, Jan 12, 2009 at 10:03 AM, Jesús Gabriel y
Galán[email protected] wrote:

rows.times do
Posted via http://www.ruby-forum.com/.

=> #<Grid:0xb7c02008 @row0=“initial value”, @row2=“initial value”,
@row1=“initial value”>
irb(main):021:0> a.methods.grep /row/
=> [“row0”, “row0=”, “row1”, “row1=”, “row2”, “row2=”]

Ooops, my solution starts with 0, while you wanted to start with 1.
Anyway, an easy change. Nevertheless, I agree with Stefano that this
would be better off implemented as an array, instead of having
individual variables for each “field”.

Jesus.

Thanks for the help guys! The arrays sound like a much more suitable way
around this problem. Overthought this one.

Cheers!

Peter