I am really new to this so I apologize for my ignorance and I have searched for resources before asking.
I am using regular ruby and I am using an API.
I keep receiving undefined method error when I run things and I cannot figure out why.
So, this is my code.... the issue is the last two methods I think... but I don't understand what it is that is cause the method I am calling #print_lighting_time to come up as undefined. Other resources have stated that it is usually an issue with an object but I guess that isn't making sense to me...
here is the code for the CLI that isn't working
class Cli
def start
puts "Shabbat Shalom!"
Api.get_data
check_date_options
end
def check_date_options
puts "Curious when to light your candles for Shabbos? Type 'Dates' to find out!"
check_date
end
def check_date
input = get_input
if input == "Dates"
list_dates
else
invalid_date
end
end
def get_input
gets.chomp
end
def invalid_date
puts "Invalid date! Check your date and reenter!"
binding.pry
end
def list_dates
CandleLighting.all.each_with_index do |title, index|
puts "#{index}. #{title.date}"
end
lighting_times_info_list
end
def lighting_times_info_list
puts "Select the date to view the lighting time!"
lighting_times_info
end
def lighting_times_info
input = get_input
if input.to_i.between?(0, 60)
index = input.to_i
date = CandleLighting.all[index]
print_lighting_time(date)
else
invalid_date
lighting_times_info_list
end
def print_lighting_time(date)
puts "Shabbos is:#{date}"
puts "Light candles by: #{date.title}"
end
end
end
and here is the code for the CandleLighting class
class CandleLighting
attr_accessor :title, :date
##all = []
def initialize(title, date)
#title = title
#date = date
##all << self
end
def self.all
##all
end
end
and the code for the API
class Api
def self.get_data
load_candlelightings
end
def self.load_candlelightings
response = RestClient.get("https://www.hebcal.com/hebcal?v=1&cfg=json&maj=on&min=on&mod=on&nx=on&year=now&month=x&ss=on&mf=on&c=on&geo=geoname&geonameid=5128581&m=50&s=on")
data = JSON.parse(response.body)
data["items"].each do |hash|
CandleLighting.new(hash["title"], hash["date"]) if hash["title"].include?("Candle lighting")
end
end
end
and finally the error message that relates to line 52 of the CLI the line being "print_lighting_time(date)
Traceback (most recent call last):
6: from bin/run:4:in `<main>'
5: from /Users/allisonperry/Development/code/Mod1/candle-lighting-times/lib/cli.rb:5:in `start'
4: from /Users/allisonperry/Development/code/Mod1/candle-lighting-times/lib/cli.rb:10:in `check_date_options'
3: from /Users/allisonperry/Development/code/Mod1/candle-lighting-times/lib/cli.rb:17:in `check_date'
2: from /Users/allisonperry/Development/code/Mod1/candle-lighting-times/lib/cli.rb:37:in `list_dates'
1: from /Users/allisonperry/Development/code/Mod1/candle-lighting-times/lib/cli.rb:42:in `lighting_times_info_list'
/Users/allisonperry/Development/code/Mod1/candle-lighting-times/lib/cli.rb:52:in `lighting_times_info': undefined method `print_lighting_time' for #<Cli:0x00007fa94f883e48> (NoMethodError)
I am not sure if all this code is even necessary in order to help... but I have been trying to fix this for quite some time and its not happening.
Thank you in advance!
Putting this into a code editor and properly indenting it reveals the problem. print_lighting_time is defined inside lighting_times_info.
def lighting_times_info
input = get_input
if input.to_i.between?(0, 60)
index = input.to_i
date = CandleLighting.all[index]
print_lighting_time(date)
else
invalid_date
lighting_times_info_list
end
def print_lighting_time(date)
puts "Shabbos is:#{date}"
puts "Light candles by: #{date.title}"
end
end
It should instead be...
def lighting_times_info
input = get_input
if input.to_i.between?(0, 60)
index = input.to_i
date = CandleLighting.all[index]
print_lighting_time(date)
else
invalid_date
lighting_times_info_list
end
end
def print_lighting_time(date)
puts "Shabbos is:#{date}"
puts "Light candles by: #{date.title}"
end
Indentation is an important visual guide to prevent these sorts of mistakes.
A good editor like Atom or VSCode will indent for you and can warn you of common mistakes. Tools such as rubocop will audit your code for common mistakes.
Related
I am trying to write some functionality which allows me to take a broken bike to a garage to have it fixed, whilst implementing this i have come across this issue. i understand that this usually is because it cannot find the file but have ran out of ideas on how to fix it. If you need any of the other code let me know but i thought this would be all the code needed.
dockingstation.rb:
require_relative 'Bike'
require_relative 'van'
require_relative 'garage'
class DockingStation
attr_reader :dock, :max_dock, :DEFAULT_CAPACITY
DEFAULT_CAPACITY = 20
def initialize(capacity = DEFAULT_CAPACITY)
#max_dock = capacity
#dock = []
end
def release_bike
if !empty?
#dock.each_with_index do |bike, index|
if bike.working?
#dock.delete_at(index)
return bike
else
raise "Bike is broken"
end
end
else
raise "No bikes to release"
end
end
def dock_bike(bike, working = true)
if !full?
#dock << bike
else
raise "Too many bikes"
end
end
def show_dock
#dock.each do |el|
return el
end
end
def van_takes_broken_bikes(van)
puts #dock
#dock.each_with_index do |bike, index|
if bike.working? == true
van.storage.append(bike)
else
van.storage.append(bike)
end
end
end
private def full?
#dock.length == #max_dock
end
private def empty?
#dock.length == 0
end
end
dock = DockingStation.new
bike = Bike.new
van = Van.new
bike.report_broken
dock.dock_bike(bike)
dock.van_takes_broken_bikes(van)
van.rb:
require_relative 'dockingstation'
require_relative 'garage'
class Van
attr_reader :storage
def initialize
#storage = []
end
def take_broken_bikes_to_garage(bikes)
end
end
Have a problem, when run a code allways have error.
Expect: for the user add win or reduce his balance.
undefined method `balance=' for #<Dice:0x0000563d4d4dfd88 #name="foo", #balance=600, #bet=300>
Did you mean? balance
(repl):22:in `increase_decrease_cash'
(repl):62:in `<class:Game>'
(repl):29:in `<main>'
This error always comes out, retried everything I could guess, but nothing came of it and I don’t understand how it can be googled
class Dice
attr_accessor :name, :bet
attr_reader :balance
def initialize(name, balance, bet)
#name = name
#balance = balance
#bet = bet
end
def self.roll
#roll_dice = rand(1..2)
end
def self.check_bet
if #player.bet > #player.balance
puts "Enter number from 1 to #{#player.balance}"
end
end
def self.increase_decrease_cash
if #roll == #my_number
#player.balance += #player.bet
else
#player.balance -= #player.bet
end
end
end
class Game < Dice
#player = Dice.new("foo", 600, 0)
puts "Hello #{#player.name} your balance is: #{#player.balance}"
puts "Bones throwing count times"
a = 2 #gets.chomp.to_i
while a > 0 do
puts ""
puts "Enter your bet !!!"
# PLAYER BET
#player.bet = 300 #gets.chomp.to_i
check_bet
puts "Respected #{#player.name} your bet is: #{#player.bet}"
puts "Now select number 1-2"
# BONES ROLL
#my_number = roll # gets.chomp.to_i
puts "###################"
puts "Now we throw bones"
#roll = roll
puts "Nuber is #{roll}"
if #roll == #my_number
puts "Your win, you get #{#player.bet}"
else
puts "You lose #{#player.bet}"
end
p "$$$$"
p #player.balance
p "$$$$"
a -= 1
increase_decrease_cash
end
end
This error always comes out, retried everything I could guess, but nothing came of it and I don’t understand how it can be googled
attr_reader creates only the get method for balance. You need both get and set method for balance. Because you set balance in the initialize method. So, you should use attr_accessor instead of attr_reader.
attr_accessor :balance
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
I'm learning Ruby and RSpec, and I've hit a snag wherein most learning materials available have become deprecated and I lack the vocabulary to sift through the wreckage.
class Session
def initialize(winning_score = 0)
#winning_score = winning_score
play
end
def play
get_players
max_score
while #game is in play
print_score
#play game
end
winner
end
def get_players
puts "\nPlayer X name:"
p1 = gets.chomp.upcase
#player1 = Player.new(p1, "X", 0)
puts "\nPlayer O name:"
p2 = gets.chomp.upcase
#player2 = Player.new(p2, "O", 0)
end
def max_score
puts "\nBest out of how many?"
max = gets.chomp
#winning_score = (max.to_f/2).ceil
end
def print_score
puts "\n#{#player1.name}: #{#player1.score} \n#{#player2.name}: #{#player2.score}"
end
def winner
if #player1.score == #winning_score
puts "\n#{#player1.name} WINS!!!"
elsif #player2.score == #winning_score
puts "\n#{#player2.name} WINS!!!"
end
end
end
class Player
attr_accessor :name, :mark, :score
def initialize(name, mark, score)
#name = name
#mark = mark
#score = score
end
end
Rpec:
describe "Play" do
before(:each) do
allow(x).to receive(:puts)
allow(x).to receive(:print)
end
let(:x) { Session.new }
it "displays game score" do
#player1 = Player.new("p1", "X", 0)
#player2 = Player.new("p2", "O", 2)
expect(x).to receive(:puts).with("\np1: 0 \np2: 2")
x.print_score
x.play
end
end
... I think that's all the applicable bits of code... The problem is that the file being tested and the RSpec file keep talking through each other, and I keep getting this sort of thing:
1) play displays game score
Failure/Error: expect(x).to receive(:puts).with("\np1: 0 \np2: 2")
#<Session:0x007fc16b9f5d38> received :puts with unexpected arguments
expected: ("\np1: 0 \np2: 2")
got: ("\n\t\t: 0 \n\tEND: 0"), ("\nPlayer X name:"), ("\nPlayer O name:"), ("\nBest out of how many?"), ("\n\tIT \"GETS AND CREATES PLAYERS\" DO WINS!!!")
# ./tictactoe_spec.rb:36:in `block (2 levels) in <top (required)>'
...where the noise is other methods gets.chomping the running RSpec code and storing it as the player names... I can't figure out how to prevent this from happening, clear/reset it, or what the correct course of action even is... Please advise.
Well, you are setting the #player1 and #player2 instance variables in the test context. While you need them inside your session object.
I think a good approach here would be to stub the get_players method, but we will have to change it a bit.
class Session
#...
def get_players
#player1 = get_player("X")
#player2 = get_player("O")
end
def get_player(mark)
puts "\nPlayer #{mark} name:"
name = gets.chomp.upcase
Player.new(name, mark, 0)
end
#...
end
Now you can stub those get_player calls
# ...
it "displays game score" do
allow(x).to recive(:get_player).with("X") { Player.new("p1", "X", 0) }
allow(x).to recive(:get_player).with("O") { Player.new("p2", "O", 2) }
expect(x).to receive(:puts).with("\np1: 0 \np2: 2")
x.print_score
x.play
end
The solution was to implement an optional output source at initialization that defaults to stdout, then create a double of that output source for the methods to puts to. After talking to a few more experienced devs, it seems to be a fairly common thing to do. Simplifying the code a bit would probably also be pretty thoroughly helpful... It's pretty bad looking back at it.
I'm not sure why my code will not pass the corresponding test. Each time I try the code, the following error is reported: "rb:60:in <main>': undefined local variable or methodtrack' for main:Object (NameError)." What can I do without editing the tests? Thanks! Open to another approach...thanks!
strong text
class Song
attr_reader :song
def initialize(song, artist)
#song = song
#artist = artist
end
def play
puts "#{#song}by #{#artist}"
end
end
class Playlist
def initialize(player_list)
#player_list = player_list
end
def add(add_song)
add_song.each do |song|
#player_list << song
end
end
def track_number
#player_list.length
end
def remove(remove_song)
remove_song.each do |song|
#player_list.delete(song)
end
end
def includes?(from_list)
i = 0
from_list.each do |song|
if #player_list.include?(song)
i+=1
end
end
if i==from_list.length
true
else
false
end
end
def play_all
#player_list.each do |song|
song.play
end
end
def display
#player_list.each do |song|
puts song.song
end
end
end
one_by_one = Song.new("One by One", "Sirenia")
world_so_cold = Song.new("World So Cold", "Three Days Grace")
going_under = Song.new("Going Under", "Evanescence")
my_playlist = Playlist.new(one_by_one, world_so_cold, going_under)
lying_from_you = Song.new("Lying From You", "Linkin Park")
angels = Song.new("Angels", "Within Temptation")
my_playlist.add(lying_from_you, angels)
p my_playlist.track_number == 5
going_under.play
my_playlist.remove(angels)
p my_playlist.includes?(lying_from_you) == true
my_playlist.play_all
my_playlist.display
When you call the "add" method for PlayList, it is expecting a single Song. However, the "add" method is trying to call .each() which would work for an array of Songs but not for a single song.
The best solution, without changing your test code, would be to remove the ".each" calls in the "add", "remove" and "includes?" methods for PlayList. Have them each add, remove or check for a single song at a time.