ArgumentError on Ruby - ruby

I have been trying to run the Ruby code below but I keep on getting the following error:
Failed: ArgumentError: wrong number of arguments (given 1, expected 0)
stacktrace: ./basic_read_write.rb:3:in write_data_to_file'
/tmp/test.rb:5:inblock (2 levels) in
# writes the number of lines then each line as a string.
def write_data_to_file()
a_file=File.new("mydata.txt","w")
a_file.puts('5')
a_file.puts('Fred')
a_file.puts('Sam')
a_file.puts('Jill')
a_file.puts('Jenny')
a_file.puts('Zorro')
a_file.close
end
def read_data_from_file()
a_file=File.new("mydata.txt","r")
count = a_file.gets.to_i
puts count.to_s
for i in 0..count.to_i
puts a_file.gets
end
a_file.close
def main
# open for writing
write_data_to_file()
# open for reading
read_data_from_file()
end
main
end

The above code looks good except for the end statement in the methods. Every method ends with end.
According to your code, the def read_data_from_file() has an end at the end after the def main.
def write_data_to_file()
a_file=File.new("mydata.txt","w")
a_file.puts('5')
a_file.puts('Fred')
a_file.puts('Sam')
a_file.puts('Jill')
a_file.puts('Jenny')
a_file.puts('Zorro')
a_file.close
end
def read_data_from_file()
a_file=File.new("mydata.txt","r")
count = a_file.gets.to_i
puts count.to_s
for i in 0..count.to_i
puts a_file.gets
end
a_file.close
end
def main
# open for writing
write_data_to_file()
# open for reading
read_data_from_file()
end
main

Related

Receiving undefined method error in ruby (no rails)

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.

How to refactor a long method in ruby

Below is an example of my coding style. Sometimes I end up with 50 line methods.
def make_juice
wash_fruits()
cut_fruits()
while(true) do
if electicity_available?
turn_on_lights()
break
else
pay_electricity_bill()
sleep(60)
end
end
mix_fruits_in_mixer()
add_sugar()
end
# ---------- function definitions ----------
def wash_fruits
# ...
end
def cut_fruits
# ...
end
def electricity_avalable?
# return true if available
end
def turn_on_lights
# turn on
end
def pay_electricity_bill
# pay
end
def create_juice
# steps for creating juice
end
def add_sugar
# steps for adding sugar
end
It is not ruby convention to write long methods, and I would like to know the standard way of refactoring a ruby program. I tried to refactor the code and got the result below:
def wash_fruits
# ...
cut_fruits
end
def cut_fruits
# ...
turn_on_lights
end
def turn_on_lights
while(true) do
if electricity_avalable?
turn_on_lights
break
else
sleep 1.hour
end
end
mix_fruits_in_mixer
end
def mix_fruits_in_mixer
# ...
add_sugar
end
def turn_on_lights
# ...
end
def add_sugar
# ...
# ... program exits
end
The method names in the second style isn't very meaningful. Is this the right way to refactor a program?
I would be inclined to write the following1.
def make_juice
wash_fruits
cut_fruits
turn_on_lights
mix_fruits_in_mixer
add_sugar
end
def turn_on_lights
until electricity_available?
pay_electricity_bill()
sleep(60)
end
flip_switch_on
end
1 The logic suggests that washing and cutting might be done in the dark and one might have to pay the electricity bill multiple times to get power back. ¯\_(ツ)_/¯.

How to fix this error message? syntax error, unexpected tIVAR

I'm trying to run some tests on my code, but I'm running into a problem. For a very simple line of code, I get a weird error message. This test is to make sure my server can receive info from one of my clients.
The tests and file run fine without this line:
client_1.#socket.puts("This gives an error.")
Including that bit of code gives this error:
macowner:WAR3 macowner$ ruby ServerTests1.rb
ServerTests1.rb:160: syntax error, unexpected tIVAR, expecting '('
client_1.#socket.puts("Output for Server to receive.") #Error
^
Help is greatly appreciated. I get this error fairly frequently, but I have no idea what it means (even with searching for it).
enter code here
require 'minitest/autorun'
require 'socket'
require_relative 'WarGame_Class.rb'
require_relative 'ModifiedPlayer_Class.rb'
require_relative 'DeckClass.rb'
class WarServer
def initialize(host, port)
#socket_server = TCPServer.new(host, port)
#players = [Player.new, Player.new]
#deck = CardDeck.new
#deck.deal_cards(#players[0].cards, #players[1].cards)
game = WarGame.new
#clients = {} # keys are sockets, values are players
end
def client_keys(key)
#clients.keys[key] # this should work
end
def input #input reader function
#input
end
def close
#socket_server.close
end
def capture_input ##input client to get what they wrote
#input = #clients.keys[0].read_nonblock(1000) # arbitrary max number of bytes
end
def accept_client
#Hash here to link client to player? (or game?)
client = #socket_server.accept
#clients[client] = #players[#clients.size]
# puts "clients key 0: #{#clients.keys[0]}"
puts
# puts "clients values: #{#clients.values}"
if #clients.size == 2
start_game#####################!!!! Starts game if two clients can put client messages in start game
end
end
def start_game ##############!!!
#clients.keys[0].puts "Welcome to War. Please press enter to play your card"
#clients.keys[1].puts "Welcome to War. Please press enter to play your card"
end
end
class MockWarClient
def initialize
#socket = TCPSocket.new('localhost', 2012)
end
def output
#output
end
def input
#input
end
def capture_output #need to add (socket)? How else read from specific socket?
#output = #socket.read_nonblock(1000) # arbitrary max number of bytes
rescue
#output = "capture_output error."
end
def write_input
#input = #war_server.client_keys.write_nonblock(1000)
end
end
class WarServerTest < MiniTest::Unit::TestCase
def setup #This would be like our INITIALIZE Function
#anything is available through out all tests (i.e., instance vars)
#war_server = WarServer.new('localhost', 2012)
end
def teardown
#war_server.close
end
def test_server_capture_output_from_client
client_1 = MockWarClient.new
#war_server.accept_client
client_2 = MockWarClient.new
#war_server.accept_client
client_1.#socket.puts("Output for Server to receive.") #Line I need to fix
#SOCKETforSERVER
#clien_n.SOCKETforSERVER.puts''
#Replace puts with write_nonblock, perhaps
end
end
If you're trying to access the #socket instance variable then you just need another accessor method in MockWarClient:
def socket
#socket
end
and the say client_1.socket.puts(...) to use it. You could also use attr_reader to simplify things:
class MockWarClient
attr_reader :socket, :input, :output
def initialize
#socket = TCPSocket.new('localhost', 2012)
end
def capture_output #need to add (socket)? How else read from specific socket?
#output = #socket.read_nonblock(1000) # arbitrary max number of bytes
rescue
#output = "capture_output error."
end
def write_input
#input = #war_server.client_keys.write_nonblock(1000)
end
end
That will create the three accessor methods for you.
You cannot call a method named #socket in a usual way as you are trying in client_1.#socket. That method name is very unusual because it is confusing with an instance variable, and it is doubtful that you actually have such method, but if you do, then the way to call such method is:
client_1.send(:#socket)

Ignore no such file found

Greetings,
I've a ruby script thats opening files and inserting the data inside the file into a database. Some of the files are missing so when the script attempts to open the file it throws a file not found exception.
Can anyone tell me how I can continue the process instead of the whole thing coming to an abrupt end. Please note this is the first thing I've ever done with ruby so be gentle! :-)
The code I'm using is as follows
def insertData
for i in (1..93)
puts "now looking at #{i}"
file = File.new("callspan/#{i}", "r")
while(line = file.gets)
with_db do |db|
db.query(line)
end
end
end
Either wrap the opening of the file with a call to File.exists?, or rescue from the exception. I prefer the former, if you expect it to be a common case (exceptions are for "exceptional" problems).
def insertData
for i in (1..93)
puts "now looking at #{i}"
next if !File.exists?("callspan/#{1}")
file = File.new("callspan/#{i}", "r")
while(line = file.gets)
with_db do |db|
db.query(line)
end
end
end
end
Simple one line exception handling:
10 / 0 rescue nil
Rescue only file not found exceptions:
def insert_data
(1..93).each do |i|
puts "now looking at #{i}"
begin
file = File.new("callspan/#{i}", 'r')
while(line = file.gets)
with_db do |db|
db.query(line)
end
end
rescue Errno::ENOENT
puts "skipping #{i}"
end
end
end
Use rescue nil to catch exceptions, like this:
def insertData
for i in (1..93)
puts "now looking at #{i}"
File.open("callspan/#{i}", "r").each_line do |line|
with_db do |db|
db.query(line)
end
end rescue nil
end
end
(i'd also put with_db around the cycle, it's probably more efficient)

CommandLine::Application swallows my exceptions in main, how to avoid?

Example:
require 'commandline'
class App < CommandLine::Application
def initialize
end
def main
raise 'foo'
end
end
results in
$ ruby test.rb
ERROR: foo
And here the problem starts: during development there will always be Exceptions thrown deep somewhere in my code and I need to see the stacktrace and not some mangled message.
Thanks to rampion, I'm now using this solution:
require 'commandline'
class App < CommandLine::Application
def initialize
end
def main
raise 'foo'
rescue Exception => e
puts format_like_real_exception e
end
def format_like_real_exception(e)
s = ''
b = e.backtrace
s << b.shift << ': ' << e.message << "\n"
b.each { |l| s << "\t" << l << "\n" }
s
end
end
Of course the formatter is not necessary, but I prefer it the way they're originally formatted.
Alternately, you could just rescue the errors in main:
require 'rubygems'
require 'commandline'
class App < CommandLine::Application
def initialize
end
def main
raise 'foo'
rescue Exception => e
puts "BACKTRACE:"
puts e.backtrace
end
end
The solution I found so far:
Change CommandLine::Application to CommandLine::Application_wo_AutoRun
rename method main to something else which isn't used, e.g `start
call static method App.run which returns the instance and then call your start method on it
Full example:
require 'commandline'
class App < CommandLine::Application_wo_AutoRun
def initialize
end
def start
raise 'foo'
end
end
app = App.run
app.start
The documentation mentions Application_wo_AutoRun but doesn't assist how to proceed further. Only source studying helped here.

Resources