Dynamic instances of a class

Hi everyone, i’m really new to ruby and i’m trying to solve the next
piece of code:

require ‘csv’

class Motorcycle
attr_reader :name, :weight
@@count = 0

def self.find (name)
found = nil
ObjectSpace.each_object(Motorcycle) { |o|
found = o if o.name == name
}
found
end

#Dynamically create instances of Motrocycle
def self.create
PARAMS = File.read(‘motorcycles.csv’).split("\n").map { |line|
line.split(’,’) }
end

def initialize (name, weight)
@name = name
@weight = weight
self.class.count += 1
end

def self.count
@@count
end

def available_colors
end

def has_abs?
end
end

My code must be able to get trough this test:

#Test that must pass

describe Motorcycle do
describe “loading the motorcycle list” do
it “should load 2 motorcycles from the CSV” do
Motorcycle.count.should == 2
end
end

describe “finding a motorcycle by name” do
it “should return an instance of the Motorcycle class” do
Motorcycle.find(“1200 RT”).should be_a Motorcycle
end
end

describe “#weight” do
it “should have a weight of 800 pounds for the 1200 RT” do
Motorcycle.find(“1200 RT”).weight.should == ‘800 pounds’
end

it "should have a weight of 500 pounds for the 600 GS" do
  Motorcycle.find("600 GS").weight.should == '500 pounds'
end

end

describe “#available colors” do
it “should find ‘red’ and ‘black’ as available colors for the BMW
1200 RT” do
Motorcycle.find(“1200 RT”).available_colors.should == [ ‘red’,
‘black’ ]
end

it "should find 'green' and 'blue' as available colors for the BMW

600 GS" do
Motorcycle.find(“600 GS”).available_colors.should == [ ‘green’,
‘blue’ ]
end
end

describe “#has_abs?” do
it “should be true for a motorcycle that appears in
abs_motorcycles.txt” do
Motorcycle.find(“1200 RT”).has_abs?.should be_true
end

it "should be false for a motorcycle that does not appear in

abs_motorcycles.txt" do
Motorcycle.find(“600 GS”).has_abs?.should be_false
end
end
end

Problem is i don’t know much about ruby. i already got over the fact of
getting a count of how many instances of the class have been created,
also on how to find a instance of the class by its name, but don’t know
how to create the instances of said class dynamically (via the create
method i’m trying to write), i know that the code line inside the create
method gives me an array that contains the information extracted from
the file “motrocycle.csv”, first row contains the headers for each
column (which i’m not sure if its really useful), first column contains
the name that each instance of motorcycle should have, this is where my
big problem is located, not sure how to do that, so please, if anyone
could help me out i would really appreciate it :D.

Thanks in advance, its really urgent.

I’m not an expert, but your question I can answer. Woohoo!

You can create instances with new(). E.g.:

aMotorCycle = Motorcycle.new("blahblah", "800 pounds")

This invokes the initialize method.

But you’re trying to do something a little trickier, which is (I think)
to create many motorcycles at once. You can do that with a class method
that returns an array of motorcycles:

def Motorcycle.getMany(filename)
File.new(filename).readlines.map{ |line|
Motorcycle.new( line.split( ‘,’ ) )
}
end

This could be invoked thus:

manyMotorcycles = Motorcycle.getMany(‘motorcycles.csv’)

(There are a few more improvements you could make to your code but I
won’t clutter this answer with them.)

Good luck, and have fun with Ruby!

ps: I stumbled on your question while checking for an answer to my Rake
question: http://www.ruby-forum.com/topic/3130799#new
No answers yet. Anyone with Rake chops out there? Hello?

Oops, I didn’t take into account the format of your data file, in which
the first line is not data but headings. So here’s a refinement:

def Motorcycle.getMany(filename)
File.new(filename).readlines[1…-1].map{ |line|
Motorcycle.new( line.split( ‘,’ ) )
}
end

La Wi wrote in post #1034939:

Oops, I didn’t take into account the format of your data file, in which
the first line is not data but headings. So here’s a refinement:

def Motorcycle.getMany(filename)
File.new(filename).readlines[1…-1].map{ |line|
Motorcycle.new( line.split( ‘,’ ) )
}
end

wow thanks this really is light in the empty void of my ignorance, i’ll
give it a try now, im guessing that if i change the line
“.readlines[1…-1]” for something like “.readlines[2…-1]” it will start
on the second line of my file, well any way i’ll try it out now and
share my results.

PD: About your problem, i really can’t help you there, not really and
expert on that regard but really wish you luck, if i stumble upon
something related i’ll let you know :D.

Oops again! This should work better:

Motorcycle.new( *line.split( ',' )  )

line.split(’,’) is a single arg that is an array.
The * turns the array into a list of args.

Also, wrt your earlier reply, note that [1…-1] gets the 2nd thru last
elements of an array. The first thru last would be [0…-1].

For some estrange reason it wont let me edit, but i’ll share my results.

I give it a tray but it wont work as my initialize method receives 2
parameters and it seems that “line.split(’,’)” is considered a single
parameter, so i figure i will have to try some way else, or maybe ¿is it
possible to assign the line.split value to 2 different variables at the
same time after the “map{” and then create the new instance with
“Motorcycle.new(var1,var2)”?.

OK, hate to multi-post, but wanted to let you know that i made it, is
not really elegant, i wish there was a better way to do it, but at least
i (kind of) get a solution for the main problem on this post.

Here is the code.

require ‘csv’

class Motorcycle
attr_reader :name, :weight
@@count = 0

def self.find (name)
found = nil
ObjectSpace.each_object(Motorcycle) { |o|
found = o if o.name == name
}
return found
end

#Dynamically create instances of Motrocycle
def self.create
File.new(‘motorcycles.csv’).readlines[1…-1].map{ |line|
first, *rest = line.split(/,/)
Motorcycle.new( first, rest )
}
end

def initialize (name, weight)
@name = name
@weight = weight
self.class.count += 1
end

def self.count
return @@count
end

def self.count=( count )
@@count = count
end

def available_colors
end

def has_abs?
end
end

Is there any way to do it better, like, ¿ what is i didn’t have 2
columns but multiple columns? (i was thinking of creating a array with
the values and then using 2 for loops to retrieve each value, but that
would have been really stupid i believe).

EDIT

Just read your fix lw2011, it works just GREAT !, THANKS !.

Hassan S. wrote in post #1034978:

On Sat, Dec 3, 2011 at 7:05 PM, Andres M. [email protected] wrote:

require ‘csv’

Is there any way to do it better, like, what is i didn’t have 2
columns but multiple columns?

Yes, use the CSV library you’ve required (but never used) to parse
the file – that’s what it’s for :slight_smile:

Ok, i really have no experience, and must say that the library was there
when i started, i didn’t include it :confused: nor did i dig too much into it, i
thought maybe that was required for something(just like in C and C++
where you have a bunch of libraries with each new file).

On Dec 4, 3:05am, “Andres M.” [email protected] wrote:

@@count = 0

def self.find (name)
found = nil
ObjectSpace.each_object(Motorcycle) { |o|
found = o if o.name == name
}
return found
end

Be careful here, because you are only referring to your Motorcycle
instances via ObjectSpace if ruby’s garbage collection runs it will
think that none of those objects are used anymore and would destroy
them. ObjectSpace isn’t something you want to be using as your
‘storage’ system (think of it more as a debugging tool).

Fred

On Sat, Dec 3, 2011 at 7:05 PM, Andres M. [email protected] wrote:

require ‘csv’

Is there any way to do it better, like, what is i didn’t have 2
columns but multiple columns?

Yes, use the CSV library you’ve required (but never used) to parse
the file – that’s what it’s for :slight_smile: