I am getting an error when running this code. The Following is the output:
L
Bicycle#Ex3.rb:32:in `spares': private method `select' called for nil:NilClass (NoMethodError)
from Bicycle#Ex3.rb:10:in `spares'
from Bicycle#Ex3.rb:111:in `<main>'
Here is the code:
class Bicycle
attr_reader :size, :parts
def initialize(args={})
@size = args[:size]
@parts = args[:parts]
end
def spares
parts.spares # return an array
end
def lead_days
1
end
#...
end
class Parts
attr_reader :parts
def initialize(args={})
@parts = parts
end
def size
parts.size
end
def spares
parts.select{|part| part.needs_spare}
end
end
class Part
attr_reader :name, :description, :needs_spare
def initialize(args)
@name = args[:name]
@description = args[:description]
@needs_spare = args.fetch(:needs_spare, true)
end
end
class RoadBikeParts < Parts
attr_reader :tape_color
def post_initialize(args)
@tape_color = args[:tape_color]
end
def local_spares
{tape_color: tape_color}
end
def default_tire_size
'23'
end
end
class MountainBikeParts < Parts
attr_reader :front_shock, :rear_shock
def post_initialize(args)
@front_shock = args[:front_shock]
@rear_shock = args[:rear_shock]
end
def local_spares
{ rear_shock: rear_shock}
end
def default_tire_size
'2.1'
end
end
chain = Part.new(
name: 'chain',
description: '10 speed')
road_tire = Part.new(
name: 'tape_size',
description: '23')
tape = Part.new(
name: 'tape_color',
description: 'red')
mountain_tire = Part.new(
name: 'tire_size',
description: '2.1')
rear_shock = Part.new(
name: 'rear_shock',
description: 'Fox')
front_shock = Part.new(
name: 'front_shock',
description: 'Manitou',
needs_spare: false)
road_bike_part = Parts.new([chain, road_tire, tape])
road_bike = Bicycle.new(
size: 'L',
parts: Parts.new([chain,
road_tire,
tape]))
puts road_bike.size
#puts road_bike.parts.size
puts road_bike.spares.size
It is clear this line --> puts road_bike.spares.size is given the error NoMethodError, however, I am not sure how I can make a work around to correct this issue for this example. The spares method is returning an array of Part objects, however it seems my problem lies in the fact the spares method .select is private from the calling object.
Any advice to revise this code would be great. Thanks.
What's happening here is that Parts#parts
is nil
. You're getting the error on this line:
# parts is nil
parts.select{|part| part.needs_spare}
In the initializer of Parts
, its parts
attribute does not get assigned properly:
def initialize(args={})
@parts = parts
end
So when being initialized, it assigns @parts
with the value of parts
. But since parts
is not a local variable there, it calls the Parts#parts
method, which returns nil
.
If you change the initializer to the following:
def initialize(parts)
@parts = parts
end
You'll be able to run the code. But subclasses of Parts
seem to expect a Hash
in the initializer, rather than an Array
like their super class does though.