1

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.

Kyle Chadha
  • 3,741
  • 2
  • 33
  • 42
  • You're chaining the `read` method on your `open` method, thereby you get the results from `read` returned to `input`, which is probably not what you intended. – Donovan Dec 24 '13 at 17:31
  • Also, Ruby 2.0 defaults to UTF-8 - you are not reporting the number of bytes but the number of chars. – steenslag Dec 24 '13 at 17:52

1 Answers1

5

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()
vee
  • 38,255
  • 7
  • 74
  • 78
  • 2
    @bjhaid, please help me understand `With no associated block, File.open is a synonym for ::new` taken from the link you've posted. – vee Dec 24 '13 at 17:22
  • Answer found [here](http://www.ruby-doc.org/core-2.0.0/IO.html#method-c-read). It's `read` who closes the file, not `open`. – phil pirozhkov Dec 24 '13 at 17:25
  • You're chaining the `read` method on your `open` method, thereby you get the results from `read` returned to `input`, which is not what you intended. – Donovan Dec 24 '13 at 17:26
  • @Donovan, so I suppose it's the way I wrote my answer. I do not think I'm chaining `read` on `open` anywhere. The first code line is to point out what you've said to the OP. – vee Dec 24 '13 at 17:28
  • Whoops, yea, sorry @vee, I meant that for the OP. – Donovan Dec 24 '13 at 17:29
  • @bjhaid, no worries. I would have wished for +1 for the answer instead of anything else :). – vee Dec 24 '13 at 17:31
  • Similar to using `File.read`, instead of opening the file to write, then using `output.write`, just use `File.write(input)`, then discard `output.close()`. – the Tin Man Dec 24 '13 at 18:18
  • And, [`File.read`](http://www.ruby-doc.org/core-2.0.0/IO.html#method-c-read) reads to the end-of-file and automatically closes the input file. [`ios.read`](http://www.ruby-doc.org/core-2.0.0/IO.html#method-i-read) reads to the end-of-file but doesn't close it. It's an important distinction. – the Tin Man Dec 24 '13 at 18:23