mirror of
https://github.com/mruby/mruby
synced 2026-06-08 16:11:16 +00:00
7b9d1da3fc
Added complete call-seq documentation for the entire mruby-io gem across both Ruby and C implementations: ## Ruby Methods (mrblib/) - 50 methods documented: ### Kernel Module (kernel.rb): - Backtick operator: shell command execution with output capture - open: unified file/subprocess opening with pipe support - p: debug output with inspect formatting and multiple argument handling - print/puts/printf: output methods with proper formatting and separators - gets/readline/readlines: input methods with various line handling options ### File Constants (file_constants.rb): - FNM_* constants: file name matching flags for glob and fnmatch operations with detailed explanations of case sensitivity, escaping, and pattern behavior ### IO Class (io.rb): Class methods: - IO.open: creates IO objects with automatic resource management - IO.popen: subprocess communication with pipe handling - IO.pipe: creates connected pipe endpoints for IPC - IO.read: convenience method for reading entire files Instance methods: - Stream positioning: pos=, rewind, tell with proper seeking behavior - Iteration: each, each_byte, each_char with enumerator support - Output: puts, print, printf with formatting and newline handling - Utility: hash, <<, ungetbyte with proper stream manipulation - Global streams: STDIN/STDOUT/STDERR and $stdin/$stdout/$stderr ### File Class (file.rb): Instance methods: - Constructor: handles both file paths and file descriptors - Timestamps: atime, ctime, mtime with proper Time object conversion - Inspection: inspect method for debugging file objects Class methods: - Path utilities: join with cross-platform separator handling - File iteration: foreach with block and enumerator support - FileTest delegation: complete set of file type and existence checks (directory?, exist?, file?, pipe?, size, socket?, symlink?, zero?) - Path manipulation: extname for extension extraction, path for conversion ## C Methods (src/) - 25 methods documented: ### Core IO Operations (io.c): - File descriptor management: fileno with proper error handling - Stream state: closed?, eof?, sync/sync= for buffering control - Process management: pid for pipe process tracking - Resource management: close_on_exec?/close_on_exec= for FD_CLOEXEC handling ### Reading Operations: - Character reading: getc, readchar with EOF handling differences - Byte reading: getbyte, readbyte with integer conversion - Buffer reading: read with length and output buffer support - Stream manipulation: ungetc for character pushback ### System Operations: - IO multiplexing: IO.select for monitoring multiple streams - Constructor: IO.new for creating IO objects from file descriptors - Stream flushing: flush for forcing output to OS Co-authored-by: Atlassian Rovo Dev
314 lines
6.9 KiB
Ruby
314 lines
6.9 KiB
Ruby
class File < IO
|
|
# The path to the file
|
|
attr_accessor :path
|
|
|
|
#
|
|
# call-seq:
|
|
# File.new(filename, mode="r") -> file
|
|
# File.new(filename [, mode [, perm]]) -> file
|
|
# File.new(fd [, mode]) -> file
|
|
#
|
|
# Opens the file named by filename according to the given mode and returns
|
|
# a new File object. If a file descriptor is given instead of a filename,
|
|
# the new File object will be associated with that descriptor.
|
|
#
|
|
# f = File.new("testfile", "r")
|
|
# f = File.new("newfile", "w+")
|
|
# f = File.new("tmpfile", "a")
|
|
#
|
|
def initialize(fd_or_path, mode = "r", perm = 0666)
|
|
if fd_or_path.kind_of? Integer
|
|
super(fd_or_path, mode)
|
|
else
|
|
@path = fd_or_path
|
|
fd = IO.sysopen(@path, mode, perm)
|
|
super(fd, mode)
|
|
end
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# file.atime -> time
|
|
#
|
|
# Returns the last access time for file, or epoch if the platform
|
|
# doesn't have access time.
|
|
#
|
|
# File.new("testfile").atime #=> Wed Apr 09 08:51:48 CDT 2003
|
|
#
|
|
def atime
|
|
t = self._atime
|
|
t && Time.at(t)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# file.ctime -> time
|
|
#
|
|
# Returns the change time for file (that is, the time directory
|
|
# information about the file was changed, not the file itself).
|
|
#
|
|
# File.new("testfile").ctime #=> Wed Apr 09 08:53:13 CDT 2003
|
|
#
|
|
def ctime
|
|
t = self._ctime
|
|
t && Time.at(t)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# file.mtime -> time
|
|
#
|
|
# Returns the modification time for file.
|
|
#
|
|
# File.new("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003
|
|
#
|
|
def mtime
|
|
t = self._mtime
|
|
t && Time.at(t)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# file.inspect -> string
|
|
#
|
|
# Return a string describing this File object.
|
|
#
|
|
# File.new("testfile").inspect #=> "#<File:testfile>"
|
|
#
|
|
def inspect
|
|
"<#{self.class}:#{@path}>"
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.join(string, ...) -> string
|
|
#
|
|
# Returns a new string formed by joining the strings using the operating
|
|
# system's path separator (File::SEPARATOR).
|
|
#
|
|
# File.join("usr", "mail", "gumby") #=> "usr/mail/gumby"
|
|
# File.join("usr", "mail", "gumby") #=> "usr\\mail\\gumby" (on Windows)
|
|
#
|
|
def self.join(*names)
|
|
return "" if names.empty?
|
|
|
|
names.map! do |name|
|
|
case name
|
|
when String
|
|
name
|
|
when Array
|
|
if names == name
|
|
raise ArgumentError, "recursive array"
|
|
end
|
|
join(*name)
|
|
else
|
|
raise TypeError, "no implicit conversion of #{name.class} into String"
|
|
end
|
|
end
|
|
|
|
return names[0] if names.size == 1
|
|
|
|
if names[0][-1] == File::SEPARATOR
|
|
s = names[0][0..-2]
|
|
else
|
|
s = names[0].dup
|
|
end
|
|
|
|
(1..names.size-2).each { |i|
|
|
t = names[i]
|
|
if t[0] == File::SEPARATOR and t[-1] == File::SEPARATOR
|
|
t = t[1..-2]
|
|
elsif t[0] == File::SEPARATOR
|
|
t = t[1..-1]
|
|
elsif t[-1] == File::SEPARATOR
|
|
t = t[0..-2]
|
|
end
|
|
s += File::SEPARATOR + t if t != ""
|
|
}
|
|
if names[-1][0] == File::SEPARATOR
|
|
s += File::SEPARATOR + names[-1][1..-1]
|
|
else
|
|
s += File::SEPARATOR + names[-1]
|
|
end
|
|
s
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.foreach(name) {|line| block } -> nil
|
|
# File.foreach(name) -> an_enumerator
|
|
#
|
|
# Executes the block for every line in the named I/O port, where lines
|
|
# are separated by sep.
|
|
#
|
|
# File.foreach("testfile") {|x| print "GOT ", x }
|
|
# GOT This is line one
|
|
# GOT This is line two
|
|
# GOT This is line three
|
|
# GOT And so on...
|
|
#
|
|
def self.foreach(file)
|
|
if block_given?
|
|
self.open(file) do |f|
|
|
f.each {|l| yield l}
|
|
end
|
|
else
|
|
return self.new(file)
|
|
end
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.directory?(file_name) -> true or false
|
|
#
|
|
# Returns true if the named file is a directory, or a symlink that points at a directory, and false otherwise.
|
|
#
|
|
# File.directory?(".") #=> true
|
|
#
|
|
def self.directory?(file)
|
|
FileTest.directory?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.exist?(file_name) -> true or false
|
|
#
|
|
# Return true if the named file exists.
|
|
#
|
|
# File.exist?("config.h") #=> true
|
|
# File.exist?("no_such_file") #=> false
|
|
#
|
|
def self.exist?(file)
|
|
FileTest.exist?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.exists?(file_name) -> true or false
|
|
#
|
|
# Deprecated method that is equivalent to File.exist?.
|
|
#
|
|
def self.exists?(file)
|
|
FileTest.exists?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.file?(file) -> true or false
|
|
#
|
|
# Returns true if the named file exists and is a regular file.
|
|
#
|
|
# File.file?("testfile") #=> true
|
|
#
|
|
def self.file?(file)
|
|
FileTest.file?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.pipe?(file_name) -> true or false
|
|
#
|
|
# Returns true if the named file is a pipe.
|
|
#
|
|
# File.pipe?("/dev/stdin") #=> true
|
|
#
|
|
def self.pipe?(file)
|
|
FileTest.pipe?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.size(file_name) -> integer
|
|
#
|
|
# Returns the size of file_name.
|
|
#
|
|
# File.size("testfile") #=> 66
|
|
#
|
|
def self.size(file)
|
|
FileTest.size(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.size?(file_name) -> integer or nil
|
|
#
|
|
# Returns nil if file_name doesn't exist or has zero size, the size of the file otherwise.
|
|
#
|
|
# File.size?("testfile") #=> 66
|
|
#
|
|
def self.size?(file)
|
|
FileTest.size?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.socket?(file_name) -> true or false
|
|
#
|
|
# Returns true if the named file is a socket.
|
|
#
|
|
# File.socket?("/tmp/.X11-unix/X0") #=> true
|
|
#
|
|
def self.socket?(file)
|
|
FileTest.socket?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.symlink?(file_name) -> true or false
|
|
#
|
|
# Returns true if the named file is a symbolic link.
|
|
#
|
|
def self.symlink?(file)
|
|
FileTest.symlink?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.zero?(file_name) -> true or false
|
|
#
|
|
# Returns true if the named file exists and has a zero size.
|
|
#
|
|
# File.zero?("testfile") #=> false
|
|
#
|
|
def self.zero?(file)
|
|
FileTest.zero?(file)
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.extname(path) -> string
|
|
#
|
|
# Returns the extension (the portion of file name in path starting from the
|
|
# last period). If path is a dotfile, or starts with a period, then the starting
|
|
# dot is not dealt with the start of the extension.
|
|
#
|
|
# File.extname("test.rb") #=> ".rb"
|
|
# File.extname("a/b/d/test.rb") #=> ".rb"
|
|
# File.extname("test") #=> ""
|
|
# File.extname(".profile") #=> ""
|
|
#
|
|
def self.extname(filename)
|
|
fname = self.basename(filename)
|
|
epos = fname.rindex('.')
|
|
return '' if epos == 0 || epos.nil?
|
|
return fname[epos..-1]
|
|
end
|
|
|
|
#
|
|
# call-seq:
|
|
# File.path(path) -> string
|
|
#
|
|
# Returns the string representation of the path
|
|
#
|
|
# File.path("/dev/null") #=> "/dev/null"
|
|
# File.path(Pathname.new("/tmp")) #=> "/tmp"
|
|
#
|
|
def self.path(filename)
|
|
if filename.kind_of?(String)
|
|
filename
|
|
else
|
|
raise TypeError, "no implicit conversion of #{filename.class} into String"
|
|
end
|
|
end
|
|
end
|