Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ruby IO - File input/output indirectly

Tags:

file

ruby

Recently I've been learning Ruby.I hit a problem while I'm writing a subclass of File.

class MyFile < File

end

file_path = "text_file"

file = MyFile.open(file_path) do | file |
    file.each_line do | line |
        puts line
    end
    file.close
end

result:

line 1
line 2
line 3

If I want output by calling a method:

class MyFile < File
    def foo
        self.each_line do | line |
            puts line
        end
    end
end

file_path = "text_file"

my_file = MyFile.open(file_path) do | file |
    file.foo
    file.close
end

Result:

/Users/veightz/Developer/RubyCode/io_error.rb:4:in `write': not opened for writing (IOError)
    from /Users/veightz/Developer/RubyCode/io_error.rb:4:in `puts'
    from /Users/veightz/Developer/RubyCode/io_error.rb:4:in `block in foo'
    from /Users/veightz/Developer/RubyCode/io_error.rb:3:in `each_line'
    from /Users/veightz/Developer/RubyCode/io_error.rb:3:in `foo'
    from /Users/veightz/Developer/RubyCode/io_error.rb:20:in `block in <main>'
    from /Users/veightz/Developer/RubyCode/io_error.rb:19:in `open'
    from /Users/veightz/Developer/RubyCode/io_error.rb:19:in `<main>'

Then I add new method bar

class MyFile < File
    def foo
        self.each_line do | line |
            puts line
        end
    end

    def bar
        self.each_line do | line |
            p line
        end
    end
end

my_file = MyFile.open(file_path) do | file |
    file.bar
    file.close
end

Result:

"line 1\n"
"line 2\n"
"line 3\n"

So, I'm so confused about IO in Ruby.Why puts line in foo can't work well.

like image 906
Veight Zhou Avatar asked Jul 05 '15 00:07

Veight Zhou


1 Answers

There is a puts method in IO and IO is a superclass of File. That means that this:

puts line

is actually self.puts rather than Kernel#puts as it is pretty much everywhere else that you use puts. Hence the "not opened for writing" error message.

You need an explicit receiver to get the same effect as Kernel#puts; Kernel#puts is equivalent to $stdout.puts so you want:

file.each_line do | line |
  $stdout.puts line
end

Your p line version works fine because there is no IO#p or File#p method, p is Kernel#p just like it is everywhere else.

Keep in mind that we don't have functions in Ruby the way other languages have global functions. Methods that you use like a function are almost always methods in Kernel.

like image 156
mu is too short Avatar answered Oct 18 '22 13:10

mu is too short