Forum: Ruby Dynamically created attributes

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
19168f90634d83872ca3803b328b3c41?d=identicon&s=25 Peter Marks (petermarks)
on 2009-01-12 09:25
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.
C40020a47c6b625af6422b5b1302abaf?d=identicon&s=25 Stefano Crocco (crocco)
on 2009-01-12 10:00
(Received via mailing list)
Alle lunedì 12 gennaio 2009, Peter Marks 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 [](idx)
    @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
(http://www.ruby-doc.org/docs/ProgrammingRuby/html/...)

I hope this helps

Stefano
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2009-01-12 10:04
(Received via mailing list)
On Mon, Jan 12, 2009 at 9:25 AM, Peter Marks <petertmarks@gmail.com>
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.
E088bb5c80fd3c4fd02c2020cdacbaf0?d=identicon&s=25 Jesús Gabriel y Galán (Guest)
on 2009-01-12 10:10
(Received via mailing list)
On Mon, Jan 12, 2009 at 10:03 AM, Jesús Gabriel y
Galán<jgabrielygalan@gmail.com> 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.
19168f90634d83872ca3803b328b3c41?d=identicon&s=25 Peter Marks (petermarks)
on 2009-01-12 11:03
Thanks for the help guys! The arrays sound like a much more suitable way
around this problem. Overthought this one.

Cheers!

Peter
This topic is locked and can not be replied to.