I have a class that should look something like this:
class Family_Type1
@people = Array.new(3)
@people[0] = Policeman.new(\'Peter\', 0)
@people[1
First off, part of the reason your example code isn't working for you is that you have two different @people
variables - one is an instance variable and the other is a class instance variable.
class Example
# we're in the context of the Example class, so
# instance variables used here belong to the actual class object,
# not instances of that class
self.class #=> Class
self == Example #=> true
@iv = "I'm a class instance variable"
def initialize
# within instance methods, we're in the context
# of an _instance_ of the Example class, so
# instance variables used here belong to that instance.
self.class #=> Example
self == Example #=> false
@iv = "I'm an instance variable"
end
def iv
# another instance method uses the context of the instance
@iv #=> "I'm an instance variable"
end
def self.iv
# a class method, uses the context of the class
@iv #=> "I'm a class instance variable"
end
end
If you want to create variables one time in a class to use in instance methods of that class, use constants
or class variables
.
class Example
# ruby constants start with a capital letter. Ruby prints warnings if you
# try to assign a different object to an already-defined constant
CONSTANT_VARIABLE = "i'm a constant"
# though it's legit to modify the current object
CONSTANT_VARIABLE.capitalize!
CONSTANT_VARIABLE #=> "I'm a constant"
# class variables start with a @@
@@class_variable = "I'm a class variable"
def c_and_c
[ @@class_variable, CONSTANT_VARIABLE ] #=> [ "I'm a class variable", "I'm a constant" ]
end
end
Even so, in the context of your code, you probably don't want all your instances of Family_Type1 to refer to the same Policemen and Accountants right? Or do you?
If we switch to using class variables:
class Family_Type1
# since we're initializing @@people one time, that means
# all the Family_Type1 objects will share the same people
@@people = [ Policeman.new('Peter', 0), Accountant.new('Paul', 0), Policeman.new('Mary', 0) ]
def initialize(*ages)
@@people.zip(ages).each { |person, age| person.age = age }
end
# just an accessor method
def [](person_index)
@@people[person_index]
end
end
fam = Family_Type1.new( 12, 13, 14 )
fam[0].age == 12 #=> true
# this can lead to unexpected side-effects
fam2 = Family_Type1.new( 31, 32, 29 )
fam[0].age == 12 #=> false
fam2[0].age == 31 #=> true
fam[0].age == 31 #=> true
The runtime initialization can be done with metaprogramming, as Chirantan said, but if you are only initializing a few classes, and you know what their name is, you can also do it just by using whatever you read from the file:
PARAMS = File.read('params.csv').split("\n").map { |line| line.split(',') }
make_people = proc do |klasses, params|
klasses.zip(params).map { |klass,name| klass.new(name, 0) }
end
class Example0
@@people = make_people([ Fireman, Accountant, Fireman ], PARAMS[0])
end
class Example1
@@people = make_people([ Butcher, Baker, Candlestickmaker ], PARAMS[0])
end
Assuming you want to create different classes per type/array size at runtime:
If (like in Python) a Ruby class is defined when executed (I think it is), then you can do this:
Define your class inside a function. Have the function recieve array size and type as parameters and return the class in its result. That way, you have a sort of class factory to call for each definition in your spec file :)
If on the other hand you want to just initialize @params
based on actual data, keep in mind, that Ruby is a dynamically typed language: Just reassign @params
in your constructor to the new array!
From what I understand, you need meta-programming. Here is a snippet of code for creating classes dynamically (on the fly) with initialize method that initializes instance variables-
class_name = 'foo'.capitalize
klass = Object.const_set(class_name,Class.new)
names = ['instance1', 'instance2'] # Array of instance vars
klass.class_eval do
attr_accessor *names
define_method(:initialize) do |*values|
names.each_with_index do |name,i|
instance_variable_set("@"+name, values[i])
end
end
# more...
end
Hope you can tweak it to suit your requirements.