Reputation: 433
Here is some code that i know works:
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
def self.create
File.new('motorcycles.csv').readlines[1..-1].map{ |line|
Motorcycle.new( *line.split( ',' ) )
}
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
colors=[]
colorsFile = File.read('colors.csv').split("\n").map { |line| line.split(',') }
for i in (0..colorsFile.flatten.length) do
if (colorsFile.flatten[i].to_s == self.name.to_s)
colors.push(colorsFile.flatten[i+1])
end
end
return colors
end
def contains (name,color)
if(self.name.to_s == name)
else
return color
end
end
def has_abs?
File.open( 'abs.txt' ) do |io|
io.each {|line| line.chomp! ; return true if line.include? self.name.to_s}
end
return false
end
end
Motorcycle.create
the code must pass this tests on rspec:
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, after the first test (where it counts the amount of motrocicle instances) every instance is a nil, thats t say, every test is failed except for the fist one. here is the output log:
Failures:
1) Motorcycle finding a motorcycle by name should return an instance of the Motorcycle class
Failure/Error: Unable to find matching line from backtrace
expected nil to be a kind of Motorcycle
# ./motoapp.rb:76
2) Motorcycle#weight should have a weight of 800 pounds for the 1200 RT
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `weight' for nil:NilClass
# ./motoapp.rb:82
3) Motorcycle#weight should have a weight of 500 pounds for the 600 GS
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `weight' for nil:NilClass
# ./motoapp.rb:86
4) Motorcycle#available colors should find 'red' and 'black' as available colors for the BMW 1200 RT
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `available_colors' for nil:NilClass
# ./motoapp.rb:92
5) Motorcycle#available colors should find 'green' and 'blue' as available colors for the BMW 600 GS
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `available_colors' for nil:NilClass
# ./motoapp.rb:96
6) Motorcycle#has_abs? should be true for a motorcycle that appears in abs_motorcycles.txt
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `has_abs?' for nil:NilClass
# ./motoapp.rb:102
7) Motorcycle#has_abs? should be false for a motorcycle that does not appear in abs_motorcycles.txt
Failure/Error: Unable to find matching line from backtrace
NoMethodError:
undefined method `has_abs?' for nil:NilClass
# ./motoapp.rb:106
Finished in 0.01223 seconds
8 examples, 7 failures
i have been inclined to think this is some kind of bug or something due to my result doing the manual test like this:
puts Motorcycle.count
puts Motorcycle.find("1200 RT")
puts Motorcycle.find("1200 RT").weight
puts Motorcycle.find("600 GS").weight
puts Motorcycle.find("1200 RT").available_colors
puts Motorcycle.find("600 GS").available_colors
puts Motorcycle.find("1200 RT").has_abs?
puts Motorcycle.find("600 GS").has_abs?
which give me this output:
2
#<Motorcycle:0x7fd8bffcfd88>
800 pounds
500 pounds
red
black
green
blue
true
false
so i'm really pretty much on a dead end, ¿does anyone have a clue as to what could be happening?.
Upvotes: 1
Views: 232
Reputation: 2447
it seems to me you are not storing the Motorcycle objects anywhere when doing the create call, so if the GC gets called the instances will just go away. Probably loading loads of more ruby code (rspec) causes the invocation of the GC to happen sooner.
Why don't you just store the instances in a class-level Set
? (e.g. replacing the count call with instances << self
) or Hash
(storing the instances with their name as key)
Also it seems to me you are relying on the rspec order of execution when you should have a before
block in which you read from the CSV.
Example code:
Class Motorcycle
# use a constant, this will always point to the same object even though
# the content of the object changes.
# Using @@instances would also be ok
Instances = Set.new # or you can use Instances = Hash.new
def initialize (name, weight)
@name = name
@weight = weight
#
Instances << self # or store the name/instance mapping Instances[name] = self
end
Upvotes: 2