Undefined method 'close' for main:Object (NoMethodError) in Ruby - ruby

filename = ARGV.first
txt = open filename
puts "Here's your file #{filename}:"
print txt.read
puts "Type the filename again: "
file_again = $stdin.gets.chomp
txt_again = open file_again
print txt_again.read
close(txt)
close(txt_again)
The program runs fine till the end, but crashes with the titled error message right after printing the contents of the second file.
I checked the txt, txt_again using (.class) and confirmed that both are File objects. Why isn't close working?

You need to call close on the file object:
txt.close

Related

ex17.rb:5:in `open': no implicit conversion of nil into String (TypeError) from ex17.rb:5:in `<main>'

I am going through "Ruby the Hard Way". Typing in the exercises as instructed. Got to Exercise 17 and as far as i can tell typed in correctly but when i run it get this error:
ex17.rb:5:in open': no implicit conversion of nil into String (TypeError) from ex17.rb:5:in '
Can anyone tell me what is wrong here?
put the 5 in the code below to show line 5. I think the error means it is in line 5.
This is the exercise:
from_file, to_file = ARGV
puts "Copying from #{from_file} to #{to_file}"
5 in_file = open(from_file)
indata = in_file.read
puts "The input file is #{indata.length} bytes long"
puts "Does the output file exist? #{Fileexist?(to_file)}"
puts "Ready , hit RETURN to continue, CTRL-C to abort."
$stdin.gets
out_file = open(to_file, 'w')
out_file.write(indata)
puts "Alright, all done."
out_file.close
in_file.close
I was running this on the Terminal, I ran it as >ruby ex17.rb, without submitting a filename afterwards. So, on the prompt, I should have submitted it as >ruby ex17.rb with a file name.

Why can't I use `filename.open' instead of `open(filename)'?

In this piece of code which lets you read a file in the terminal, why do you need to use open(filename) rather than filename.open?
filename = ARGV.first
txt = open(filename)
puts "Here's your file #{filename}:"
print txt.read
print "Type the filename again: "
file_again = $stdin.gets.chomp
txt_again = open(file_again)
print txt_again.read
You cant use filename.open, because filename is a String and method open is not defined in String
Use File#open
File.open(filename)
File.open("file")
opens a local file and returns a file object. Here File#open is a method of File class.
open("file")
is actually Kernel#open and looks at the string to decide what to do with it.
Trivializing things:
File.open("file") is telling Ruby specifically to open a file.
In case of open("file") Ruby examines the string "file" to determine what type it is (here a file) and open corresponding type else throws appropriate error.
Ruby has a class for dealing with paths in an object-oriented way: Pathname
require 'pathname'
loop do
print 'Enter filename: '
pn = Pathname(gets.chomp)
if pn.file?
puts "Here's your file '#{pn}':", pn.read
elsif pn.exist?
puts 'That is not a file.'
else
puts 'File does not exist.'
end
end

"Undefined method 'close'" when trying to close a file in Ruby

I'm working through "Learn Ruby the Hard Way" and receive an undefined method 'close' error when trying to run the example file here: http://ruby.learncodethehardway.org/book/ex17.html
My code, specifically is:
from_file, to_file = ARGV
script = $0
puts "Copying from #{from_file} to #{to_file}."
input = File.open(from_file).read()
puts "The input file is #{input.length} bytes long."
puts "Does the output file exist? #{File.exists? to_file}"
puts "Ready, hit RETURN to contine, CTRL-C to abort."
STDIN.gets
output = File.open(to_file, 'w')
output.write(input)
puts "Alright, all done."
output.close()
input.close()
The error I receive is only for the last line 'input.close()', as 'output.close()' seems to work fine. For reference, I'm using a preexisting input file, and creating a new output file.
Thanks in advance.
Your input is not a file object because of the read() method call:
input = File.open(from_file).read()
Since read returns either nil or "" depending upon the length parameter to read, calling input.close() will raise undefined method close as input in your case is a string and String does not have close() method.
So instead of calling File.open(from_file).read() and calling the close() method, you can just call the File.read():
from_file, to_file = ARGV
script = $0
puts "Copying from #{from_file} to #{to_file}."
input = File.read(from_file)
puts "The input file is #{input.length} bytes long."
puts "Does the output file exist? #{File.exists? to_file}"
puts "Ready, hit RETURN to contine, CTRL-C to abort."
STDIN.gets
output = File.open(to_file, 'w')
output.write(input)
puts "Alright, all done."
output.close()

Basic Way to Open Files in Ruby

I'm trying to open local xml file and output its content in terminal.
I've tried this;
puts File.new('file.xml', 'r')
and this;
puts File.open('file.xml', 'r')
output from both is, instead of printing xml file to the screen;
#<File:0x00000000....>
Try this
puts File.read('file.xml')
or
puts File.open('file.xml').read
Documentation: IO.read, IO#read
I would suggest you to use block with File#open method. As with block,you don't need to close the file explicitly.Perform all your task inside the block with the file. The file will be closed automatically,when block will be terminated.
File.open('doc.txt','r') do |file|
puts file.read
end
# >> ,"11: Agriculture, Forestry, Fishing and Hunting",,
# >> ,,"111: Crop Production",
# >> ,,,"111110: Soybean Farming"
# >> ,,,"111120: Oilseed (except Soybean) Farming"

Writing to a file then trying to open it again for parsing

I'm trying to save the xml feed of a twitter user to a file and then try to read it again for parsing onto the screen.
This s what I see hen I try to run it..
Wrote to file #<File:0x000001019257c8>
Now parsing user info..
twitter_stats.rb:20:in `<main>': undefined method `read' for "keva161.txt":String (NoMethodError)
Here's my code...
require "open-uri"
require "rubygems"
require "crack"
twitter_url = "http://api.twitter.com/1/statuses/user_timeline.xml?cout=100&screen_name="
username = "keva161"
full_page = twitter_url + username
local_file = username + ".txt"
tweets = open(full_page).read
my_local_file = open(local_file, "w")
my_local_file.write(tweets)
puts "Wrote to file " + my_local_file.to_s
sleep(1)
puts "Now parsing user info.."
sleep(1)
parsed_xml = Crack::XML.parse(local_file.read)
tweets = parsed_xml["statuses"]
first_tweet = tweets[0]
user = first_tweets["user"]
puts user["screen_name"]
puts user ["name"]
puts users ["created_at"]
puts users ["statuses_count"]
You are calling read on local_file, which is the string containing the filename. You meant to type my_local_file.read, I guess, to use the IO object you got from open. (...or File.read local_file.)
Not that this is the best form: why are you writing to a temporary file anyhow? You have the data in memory, so just pass it directly.
If you do want to write to a local file, I commend the block from of open:
open(local_file, 'w') do |fh|
fh.print ...
end
That way Ruby will take care of closing the file for you and all that.

Resources