How do you associate the items of a collection instance with the collection in a smart Ruby way?

This is a conceptual question about Ruby. I think I may be thinking of
this wrong:

I have a Form class that is a container for FormItems.

In initialize, Form takes in a bunch of row data that is used to
initialize the FormItems. Form has an each method to iterate over
FormItems.

FormItems has a bunch of methods and attributes.

I want to associate information to instances of Form that FormItems can
use.

How do I associate the object of a container with the container? Or what
is a smart Ruby way (I know there are a lot of ways)?

Thank you for taking all that time Jesus.

I came up with the same answer. Almost the same code, except I don’t
need the Form to know which Items are its. They’re read only, and Form
has all the data. But Form has defaults and variables FormItems needs to
read/write.

I was looking for something like a .Net interface. I guess I just have
to stop fighting it.

Thanks again.

On Fri, Feb 15, 2013 at 7:36 PM, Jesse F. [email protected] wrote:

I want to associate information to instances of Form that FormItems can
use.

How do I associate the object of a container with the container? Or what
is a smart Ruby way (I know there are a lot of ways)?

So a FormItem belongs to one Form, and you want it to be able to read
things from it?
One way would be to pass the Form instance to the FormItems, either in
the constructor, if the Form is constructing the items, or in the code
that tells a Form that this item belongs to it.

First case:

class Form
def initialize
@items = []
@items << FormItem.new(:item, :init, :params, self)
[…] # other items
end
end

class FormItem
def initialize item, init, params, container
@container = container
[…] #rest of initialization
end
end

Note in the constructor of the Form, we are passing self to the form
items. Form items would be able then to call methods of form using
their instance variable @container.

Second way:

class Form
def initialize
@items = []
end
def add_item item
item.container = self
@items << item
end
end

class FormItem
attr_reader :container
def initialize item, init, params
[…] #rest of initialization
end
end

f = Form.new
item = FormItem.new :a, :b, :c
f.add_item item

Hope this gives you some ideas,

Jesus.

On Fri, Feb 15, 2013 at 11:54 PM, Jesse F. [email protected] wrote:

I came up with the same answer. Almost the same code, except I don’t
need the Form to know which Items are its.

but you said earlier:

Form has an each method to iterate over FormItems.

Then how do you access them (e.g. in #each) if they are created in
Form’s constructor and immediately forgotten?

They’re read only, and Form
has all the data. But Form has defaults and variables FormItems needs to
read/write.

So FormItems are read only but they modify their container? You could
then make them immutable.

FormItem = Struct.new :container, :data do
def display
puts “This is a silly example: #{data}”
container.shown += 1
self
end
end

class Form
attr_accessor :shown

def initialize(data)
@items = data.map {|d| FormItem[self, d].freeze}
@shown = 0
end

include Enumerable

def each(&b)
@items.each(&b)
self
end
end

ff = Form.new 5.times.to_a

ff.each {|fi| fi.display}
puts ff.shown

ff.first.data = “boom”

I was looking for something like a .Net interface. I guess I just have
to stop fighting it.

It’s always a good strategy to not expect your new programming
language to be the same as the old one. :slight_smile:

Kind regards

robert