filesystem/opening_modes.rb
tests/_examples/filesystem/opening_modes.rb in the metorex repository.
# A mode string is `r`, `w` or `a`, then any of `+`, `b` or `t` but not both
# of the last two, and `x` only after `w`. Anything else is refused.
path = "/tmp/metorex_opening_modes_#{Process.pid}.txt"
File.write path, "hello file\n"
def refusal
yield
rescue StandardError => problem
[problem.class, problem.message]
end
p refusal { File.open path, "q" }
p refusal { File.open path, "rbt" }
p refusal { File.open path, "rx" }
p refusal { File.open path, "rb", newline: :universal }
# `x` asks for a file of its own.
p refusal { File.open path, "wx" }[0]
# A numeric mode says for itself whether the file is written and cut down.
File.open(path, File::WRONLY) { |file| p refusal { file.gets } }
p File.read(path)
File.open(path, File::TRUNC) { |file| p file.gets }
p File.size(path)
p refusal { File.open "#{path}.missing", File::WRONLY }[0]
# A nil mode reads, and `b` in the mode puts the stream in binary mode.
File.open(path, nil, nil) { |file| p file.class }
File.write path, "testing\n"
File.open(path, "rb+") { |file| p [file.binmode?, file.external_encoding, file.pos] }
# With a block the file is closed through `close` after the block, and what
# that `close` raises is raised, except for a stream already closed.
closes = []
File.open path do |file|
file.define_singleton_method(:close) do
super()
closes << :closed
raise StandardError, "from close"
end
end rescue closes << $!.message
p closes
File.delete path
Output:
[ArgumentError, "invalid access mode q"]
[ArgumentError, "invalid access mode rbt"]
[ArgumentError, "invalid access mode rx"]
[ArgumentError, "newline decorator with binary mode"]
Errno::EEXIST
[IOError, "not opened for reading"]
"hello file\n"
nil
0
Errno::ENOENT
File
[true, #<Encoding:BINARY (ASCII-8BIT)>, 0]
[:closed, "from close"]