I've redone the question and included the full code for both files. In the touch_in method I am trying to instantiate a Journey class in the variable called 'journey'.
require_relative 'journey'
class Oystercard
MAXIMUM_BALANCE = 90
MINIMUM_BALANCE = 1
MINIMUM_CHARGE = 1
def initialize
#balance = 0
#journeys = {}
end
def top_up(amount)
fail 'Maximum balance of #{maximum_balance} exceeded' if amount + balance > MAXIMUM_BALANCE
#balance += amount
end
def in_journey?
#in_journey
end
def touch_out(station)
deduct(MINIMUM_CHARGE)
#exit_station = station
#in_journey = false
#journeys.merge!(entry_station => exit_station)
end
def touch_in(station)
fail "Insufficient balance to touch in" if balance < MINIMUM_BALANCE
journey = Journey.new
#in_journey = true
#entry_station = station
end
attr_reader :journeys
attr_reader :balance
attr_reader :entry_station
attr_reader :exit_station
private
def deduct(amount)
#balance -= amount
end
end
The Journey file is as follows:
class Journey
PENALTY_FARE = 6
MINIMUM_CHARGE = 1
def initialize(station = "No entry station")
#previous_journeys = {}
end
def active?
#active
end
def begin(station = "No entry station")
#active = true
#fare = PENALTY_FARE
#entry_station = station
end
def finish(station = "No exit station")
#active = false
#fare = MINIMUM_CHARGE
#exit_station = station
#previous_journeys.merge!(entry_station => exit_station)
end
attr_reader :fare
attr_reader :previous_journeys
attr_reader :entry_station
attr_reader :exit_station
end
I think that the 'touch_in' method should create a 'journey' variable that I called methods on, such as 'finish(station)' or 'active?' etc. When I attempt to do this in IRB I am given the following error:
2.6.3 :007 > journey
Traceback (most recent call last):
4: from /Users/jamesmac/.rvm/rubies/ruby-2.6.3/bin/irb:23:in `<main>'
3: from /Users/jamesmac/.rvm/rubies/ruby-2.6.3/bin/irb:23:in `load'
2: from /Users/jamesmac/.rvm/rubies/ruby-2.6.3/lib/ruby/gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
1: from (irb):7
NameError (undefined local variable or method `journey' for main:Object)
I'm aware that much of the code above is sloppily written and there are probably other bits, beside the 'journey' issue, where it's just incorrect. Please let me know if this is the case, the more I'm told the better.
Apologies to anyone who attempted to help me on my first attempt, as I say I'm still getting used to SO and was trying to make the post easier to read.
class Journey
# ...
def initialize
puts "Journey initialized"
# ...
end
# ...
end
require_relative 'journey'
class Oystercard
def initialize
end
# ...
def touch_in(station)
journey = Journey.new
# ...
end
end
Oystercard.new.touch_in("station")
stack_question$ ruby oystercard.rb
Journey initialized
It works fine - are you having some issue with this that is beyond the scope of the question?
Related
I'm new to ruby and I'm taking a course on it and got a bit stuck. I'm trying to create a class to represent a vending machine and several classes to represent items within it, which inherit from the vending machine.
Here's the code for the vending machine class and I've included a comment on the line throwing an error:
class VendorFood
##total_sales = 0
def initialize(name, price, vending_number)
#name = name
#price = price
#vending_number = vending_number
#supply = 0
end
def stock_item(num)
#supply += num
end
def vend_item
if #supply >= 1
#supply -= 1
self.update_sales(#cost) #getting error here
end
end
def update_sales(cost)
##total_sales += cost
end
def to_s
puts "Total Sales: #{##total_sales}\nName: #{#name}\nPrice: #{#price}\nSupply: #{#supply}"
end
attr_reader :name
attr_writer :name
attr_reader :price
attr_writer :price
attr_reader :vending_number
attr_writer :vending_number
def sales
##total_sales
end
end
class CandyBar < VendorFood
end
So essentially what I'm trying to do is be able to instantiate items without storing an instance of VendorFood. So this works if I remove the problematic line:
myBar = CandyBar.new("Hershey", 1.99, 101)
myBar.stock_item(17)
myBar.vend_item
myBar.to_s
But I want vend_item to then call update sales and increment it by the cost of the item.
This is the exact error message I get:
Traceback (most recent call last):
3: from main.rb:8:in <main>
2: from /mnt/c/users/price/onedrive/desktop/VendorFood.rb:17:in vend_item
1: from /mnt/c/users/price/onedrive/desktop/VendorFood.rb:22:in update_sales
/mnt/c/users/price/onedrive/desktop/VendorFood.rb:22:in `+': nil can't be coerced into Integer (TypeError)
Any help is appreciated.
I am working on Head First Ruby. Here is my code:
class Employee
attr_reader :name
def name=(name)
end
def print_name
puts "Name: #{name}"
end
end
class SalariedEmployee < Employee
attr_reader :salary
def salary=(salary)
# code to validate and set #salary
end
def print_pay_stub
print_name
pay_for_period = (salary / 365.0) * 14
formatted_pay = format("$%.2f", pay_for_period)
puts "Pay this period: #{formatted_pay}"
end
end
class HourlyEmployee < Employee
attr_reader :hourly_wage, :hours_per_week
def hourly_wage=(hourly_wage)
# code to validate and set #hourly_wage
end
def hours_per_week=(hours_per_week)
# code to validate and set #hours_per_week
end
def print_pay_stub
print_name
pay_for_period = hourly_wage * hours_per_week * 2
formatted_pay = format("$%.2f", pay_for_period)
puts "pay This Period: #{formatted_pay}"
end
end
I cannot get this exercise to work. I get this error:
employee.rb:42:in `print_pay_stub': undefined method `*' for nil:NilClass (NoMethodError)
from employee.rb:56:in `<main>'
Could someone look over this code and tell what is going wrong?
Edit: My mistake -- either hourly_wage or hours_per_week is nil. Make sure those are set.
It looks like salary is nil -- at least, that's the only line there with an *. You need to make sure salary is set
Edit: clarification
Edit 2: correction
class Player
attr_accessor :card_pile
def initialize
#bust = false
#card_pile = []
end
def bust?
return #cards.inject(:+) > 21
end
end
I have this Player class and have initazlied card_pile variable
class Game
def initialize
#players = []
end
def playing_game
puts "How many players are playing? "
players_amount = gets.chomp.to_i
(0...players_amount).each do
puts ("What is the players name? ")
name = gets.chomp
#players.push(name)
end
puts #players
player = Player.new
player.initialize
while #card_pile.length < 2 do
new_card = Card.new
#card_pile.push(new_card.value)
end
end
I wish to use this variable in the while loop below. Why cannot this be accessed in the way I am hoping it will be?
The error message is: ``playing_game': private method initialize' called for #<Player:0x007fda53073f48 #bust=false, #card_pile=[]> (NoMethodError)
initialize is called automatically when you make a new instance of a class using Player.new. You don't currently have any arguments being passed in to your initialize method, but you have set the instance variable card_pile with attr_accessor, so you can do this:
player = Player.new
while player.card_pile.length < 2 do
new_card = Card.new
player.card_pile.push(new_card.value)
end
So I'm trying to create a basic text adventure in ruby, and I'm roughly following a tutorial (https://jsrn.gitbooks.io/make-your-first-text-adventure-in-ruby/content/creating_the_framework.html)
But when I try and run my code I get this error:
GameBase.rb:10:in `initialize': uninitialized constant Game::World (NameError)
from GameBase.rb:55:in `new'
from GameBase.rb:55:in `<main>'
This is my code:
From GameBase.rb
Dir["GameDir/**.*"].each { |file| require_relative file }
class Game
Actions = [
:forward, :backward, :look, :attack, :loot, :inventory, :use, :cast
]
def initialize
#world = World.new
#player = Player.new
start_game
end
private
def start_game
while #player.alive?
#current_room = #world.get_room_of(#player)
print_player_status
action = take_player_input
next unless ACTIONS.include? action
take_action(action)
end
end
def take_player_input
print "What do you do?"
gets.chomp.to_sym
end
def take_action(action)
case action
when :forward
#world
when :backward
#world
when :look
#world
when :attack
#current_room.interact(#player)
when :loot
#current_room.interact(#player)
when :inventory
when :use
when :cast
end
end
end
Game.new
And from world.rb
class World
def initialize
#past_rooms = 0
#current_room = 0
end
def move_entity_forward(entity)
#current_room += 1
end
def move_entity_backward(entity)
#current_room -= 1
end
def get_room_of(entity)
if #current_room <= #past_rooms then #current_room
else
Room.new
#past_rooms += 1 end
end
end
class Room
attr_accessor :size, :content
def initialize
#content = get_content
#size = get_size
#adjetive = get_adjetive
end
def interact(player)
if #content
#content.interact(player)
#content = nil
else
puts "There isn't anything here..."
end
end
private
def get_content
[Monster, Item.sample.new]
end
def get_size
dimensions = [5, 10, 15, 20, 25, 30, 40, 50, 75, 100, 200]
"#{dimensions.sample}'x#{dimensions.sample}'"
end
def get_adjetive
["well-lit", "dim", "filthy", "suprisingly clean", "round", "muddy", "oppressive"]
end
end
Try adding this line to the top of GameBase.rb:
require_relative 'world'
This tells the Ruby interpreter to look for a file named world.rb in the same folder as GameBase.rb and run the code in that file, which would define the World class. Then the World class would be available when you try to use it.
So, I ran into the same problem because I didn't see instructions in the tutorial that the extra files (world.rb, player.rb, etc.) are expected to be in a subfolder. I had them all in the same folder, game.rb , which was causing this error.
The first line of code in game.rb is telling Ruby where to load all the related game files
Dir["GameDir/**.*"]
So, if your game.rb file is in a directory 'game' for example, then all the related files need to be in a directory game>GameDir since you are telling it to look in the GameDir folder.
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.