diff options
-rwxr-xr-x | bin/ri | 32 | ||||
-rw-r--r-- | error.c | 125 | ||||
-rw-r--r-- | eval.c | 78 | ||||
-rw-r--r-- | file.c | 1182 | ||||
-rw-r--r-- | lib/rdoc/generators/ri_generator.rb | 8 | ||||
-rw-r--r-- | lib/rdoc/parsers/parse_c.rb | 109 | ||||
-rw-r--r-- | lib/rdoc/ri/ri_descriptions.rb | 19 | ||||
-rw-r--r-- | lib/rdoc/ri/ri_formatter.rb | 30 | ||||
-rw-r--r-- | object.c | 48 |
9 files changed, 1564 insertions, 67 deletions
@@ -48,7 +48,7 @@ class RiDisplay exit 1 end @ri_reader = RI::RiReader.new(RI::RiCache.new(paths)) - @formatter = RI::RiFormatter.new(@options.width, " ") + @formatter = RI::TextFormatter.create(@options, " ") end @@ -127,7 +127,7 @@ end def display_class_info(class_entry) klass = @ri_reader.get_class(class_entry) - @formatter.draw_line("Class: " + klass.full_name) + @formatter.draw_line(klass.display_name + ": " + klass.full_name) display_flow(klass.comment) @formatter.draw_line @@ -190,12 +190,15 @@ end def report_method_stuff(requested_method_name, methods) if methods.size == 1 display_method_info(methods[0]) - elsif (entry = methods.find {|m| m.name == requested_method_name}) - display_method_info(entry) else - puts "More than one method matched your request. You can refine" - puts "your search by asking for information on one of:\n\n" - @formatter.wrap(methods.map {|m| m.full_name} .join(", ")) + entries = methods.find_all {|m| m.name == requested_method_name} + if entries.size == 1 + display_method_info(entries[0]) + else + puts "More than one method matched your request. You can refine" + puts "your search by asking for information on one of:\n\n" + @formatter.wrap(methods.map {|m| m.full_name} .join(", ")) + end end end @@ -204,12 +207,15 @@ end def report_class_stuff(requested_class_name, namespaces) if namespaces.size == 1 display_class_info(namespaces[0]) - elsif (entry = namespaces.find {|m| m.name == requested_class_name}) - display_class_info(entry) - else - puts "More than one class or module matched your request. You can refine" - puts "your search by asking for information on one of:\n\n" - @formatter.wrap(namespaces.map {|m| m.full_name}.join(", ")) + else + entries = namespaces.find_all {|m| m.name == requested_class_name} + if entries.size == 1 + display_class_info(entries[0]) + else + puts "More than one class or module matched your request. You can refine" + puts "your search by asking for information on one of:\n\n" + @formatter.wrap(namespaces.map {|m| m.full_name}.join(", ")) + end end end @@ -318,6 +318,14 @@ rb_exc_new3(etype, str) return rb_exc_new(etype, RSTRING(str)->ptr, RSTRING(str)->len); } +/* + * call-seq: + * Exception.new(msg = nil) => exception + * + * Construct a new Exception object, optionally passing in + * a message. + */ + static VALUE exc_initialize(argc, argv, exc) int argc; @@ -336,6 +344,17 @@ exc_initialize(argc, argv, exc) return exc; } +/* + * call-seq: + * exc.exception(string) -> an_exception or exc + * + * With no argument, or if the argument is the same as the receiver, + * return the receiver. Otherwise, create a new + * exception object of the same class as the receiver, but with a + * message equal to <code>string.to_str</code>. + * + */ + static VALUE exc_exception(argc, argv, self) int argc; @@ -352,6 +371,14 @@ exc_exception(argc, argv, self) return exc; } +/* + * call-seq: + * exception.to_s => string + * + * Returns exception's message (or the name of the exception if + * no message is set). + */ + static VALUE exc_to_s(exc) VALUE exc; @@ -363,6 +390,17 @@ exc_to_s(exc) return mesg; } +/* + * call-seq: + * exception.message => string + * exception.to_str => string + * + * Returns the result of invoking <code>exception.to_s</code>. + * Normally this returns the exception's message or name. By + * supplying a to_str method, exceptions are agreeing to + * be used where Strings are expected. + */ + static VALUE exc_to_str(exc) VALUE exc; @@ -370,6 +408,13 @@ exc_to_str(exc) return rb_funcall(exc, rb_intern("to_s"), 0, 0); } +/* + * call-seq: + * exception.inspect => string + * + * Return this exception's class name an message + */ + static VALUE exc_inspect(exc) VALUE exc; @@ -392,6 +437,35 @@ exc_inspect(exc) return str; } +/* + * call-seq: + * exception.backtrace => array + * + * Returns any backtrace associated with the exception. The backtrace + * is an array of strings, each containing either ``filename:lineNo: in + * `method''' or ``filename:lineNo.'' + * + * def a + * raise "boom" + * end + * + * def b + * a() + * end + * + * begin + * b() + * rescue => detail + * print detail.backtrace.join("\n") + * end + * + * <em>produces:</em> + * + * prog.rb:2:in `a' + * prog.rb:6:in `b' + * prog.rb:10 +*/ + static VALUE exc_backtrace(exc) VALUE exc; @@ -425,6 +499,16 @@ check_backtrace(bt) return bt; } +/* + * call-seq: + * exc.set_backtrace(array_ => array + * + * Sets the backtrace information associated with <i>exc</i>. The + * argument must be an array of <code>String</code> objects in the + * format described in <code>Exception#backtrace</code>. + * + */ + static VALUE exc_set_backtrace(exc, bt) VALUE exc; @@ -529,6 +613,37 @@ rb_invalid_str(str, type) rb_raise(rb_eArgError, "invalid value for %s: %s", type, RSTRING(s)->ptr); } +/* + * Document-module: Errno + * + * Ruby exception objects are subclasses of <code>Exception</code>. + * However, operating systems typically report errors using plain + * integers. Module <code>Errno</code> is created dynamically to map + * these operating system errors to Ruby classes, with each error + * number generating its own subclass of <code>SystemCallError</code>. + * As the subclass is created in module <code>Errno</code>, its name + * will start <code>Errno::</code>. + * + * The names of the <code>Errno::</code> classes depend on + * the environment in which Ruby runs. On a typical Unix or Windows + * platform, there are <code>Errno</code> classes such as + * <code>Errno::EACCES</code>, <code>Errno::EAGAIN</code>, + * <code>Errno::EINTR</code>, and so on. + * + * The integer operating system error number corresponding to a + * particular error is available as the class constant + * <code>Errno::</code><em>error</em><code>::Errno</code>. + * + * Errno::EACCES::Errno #=> 13 + * Errno::EAGAIN::Errno #=> 11 + * Errno::EINTR::Errno #=> 4 + * + * The full list of operating system errors on your particular platform + * are available as the constants of <code>Errno</code>. + * + * Errno.constants #=> E2BIG, EACCES, EADDRINUSE, EADDRNOTAVAIL, ... + */ + static st_table *syserr_tbl; static VALUE @@ -642,6 +757,16 @@ syserr_eqq(self, exc) return Qfalse; } +/* + * Descendents of class <code>Exception</code> are used to communicate + * between <code>raise</code> methods and <code>rescue</code> + * statements in <code>begin/end</code> blocks. <code>Exception</code> + * objects carry information about the exception---its type (the + * exception's class name), an optional descriptive string, and + * optional traceback information. Programs may subclass + * <code>Exception</code> to add additional information. + */ + void Init_Exception() { @@ -10134,8 +10134,70 @@ rb_thread_atfork() curr_thread->prev = curr_thread; } + +/* + * Document-class: Continuation + * + * Continuation objects are generated by + * <code>Kernel#callcc</code>. They hold a return address and execution + * context, allowing a nonlocal return to the end of the + * <code>callcc</code> block from anywhere within a program. + * Continuations are somewhat analogous to a structured version of C's + * <code>setjmp/longjmp</code> (although they contain more state, so + * you might consider them closer to threads). + * + * For instance: + * + * arr = [ "Freddie", "Herbie", "Ron", "Max", "Ringo" ] + * callcc{|$cc|} + * puts(message = arr.shift) + * $cc.call unless message =~ /Max/ + * + * <em>produces:</em> + * + * Freddie + * Herbie + * Ron + * Max + * + * This (somewhat contrived) example allows the inner loop to abandon + * processing early: + * + * callcc {|cont| + * for i in 0..4 + * print "\n#{i}: " + * for j in i*5...(i+1)*5 + * cont.call() if j == 17 + * printf "%3d", j + * end + * end + * } + * print "\n" + * + * <em>produces:</em> + * + * 0: 0 1 2 3 4 + * 1: 5 6 7 8 9 + * 2: 10 11 12 13 14 + * 3: 15 16 + */ + static VALUE rb_cCont; +/* + * call-seq: + * callcc {|cont| block } => obj + * + * Generates a <code>Continuation</code> object, which it passes to the + * associated block. Performing a <em>cont</em><code>.call</code> will + * cause the <code>callcc</code> to return (as will falling through the + * end of the block). The value returned by the <code>callcc</code> is + * the value of the block, or the value passed to + * <em>cont</em><code>.call</code>. See class <code>Continuation</code> + * for more details. Also see <code>Kernel::throw</code> for + * an alternative mechanism for unwinding a call stack. + */ + static VALUE rb_callcc(self) VALUE self; @@ -10169,6 +10231,22 @@ rb_callcc(self) } } +/* + * call-seq: + * cont.call(args, ...) + * cont[args, ...] + * + * Invokes the continuation. The program continues from the end of the + * <code>callcc</code> block. If no arguments are given, the original + * <code>callcc</code> returns <code>nil</code>. If one argument is + * given, <code>callcc</code> returns it. Otherwise, an array + * containing <i>args</i> is returned. + * + * callcc {|cont| cont.call } #=> nil + * callcc {|cont| cont.call 1 } #=> 1 + * callcc {|cont| cont.call 1, 2, 3 } #=> [1, 2, 3] + */ + static VALUE rb_cont_call(argc, argv, cont) int argc; @@ -91,6 +91,18 @@ apply2files(func, vargs, arg) return args->len; } +/* + * call-seq: + * file.path -> file_ame + * + * Returns the pathname used to create <i>file</i> as a string. Does + * not normalize the name. + * + * File.new("testfile").path #=> "testfile" + * File.new("/tmp/../tmp/xxx", "w").path #=> "/tmp/../tmp/xxx" + * + */ + static VALUE rb_file_path(obj) VALUE obj; @@ -133,6 +145,19 @@ get_stat(self) return st; } +/* + * call-seq: + * stat <=> other_stat => -1, 0, 1 + * + * Compares <code>File::Stat</code> objects by comparing their + * respective modification times. + * + * f1 = File.new("f1", "w") + * sleep 1 + * f2 = File.new("f2", "w") + * f1.stat <=> f2.stat #=> -1 + */ + static VALUE rb_stat_cmp(self, other) VALUE self, other; @@ -150,6 +175,16 @@ rb_stat_cmp(self, other) return Qnil; } +/* + * call-seq: + * stat.dev => fixnum + * + * Returns an integer representing the device on which <i>stat</i> + * resides. + * + * File.stat("testfile").dev #=> 774 + */ + static VALUE rb_stat_dev(self) VALUE self; @@ -157,6 +192,17 @@ rb_stat_dev(self) return INT2NUM(get_stat(self)->st_dev); } + +/* + * call-seq: + * stat.ino => fixnum + * + * Returns the inode number for <i>stat</i>. + * + * File.stat("testfile").ino #=> 1083669 + * + */ + static VALUE rb_stat_ino(self) VALUE self; @@ -168,6 +214,19 @@ rb_stat_ino(self) #endif } +/* + * call-seq: + * stat.mode => fixnum + * + * Returns an integer representing the permission bits of + * <i>stat</i>. The meaning of the bits is platform dependent; on + * Unix systems, see <code>stat(2)</code>. + * + * File.chmod(0644, "testfile") #=> 1 + * s = File.stat("testfile") + * sprintf("%o", s.mode) #=> "100644" + */ + static VALUE rb_stat_mode(self) VALUE self; @@ -179,6 +238,18 @@ rb_stat_mode(self) #endif } +/* + * call-seq: + * stat.nlink => fixnum + * + * Returns the number of hard links to <i>stat</i>. + * + * File.stat("testfile").nlink #=> 1 + * File.link("testfile", "testfile.bak") #=> 0 + * File.stat("testfile").nlink #=> 2 + * + */ + static VALUE rb_stat_nlink(self) VALUE self; @@ -186,6 +257,17 @@ rb_stat_nlink(self) return UINT2NUM(get_stat(self)->st_nlink); } + +/* + * call-seq: + * stat.uid => fixnum + * + * Returns the numeric user id of the owner of <i>stat</i>. + * + * File.stat("testfile").uid #=> 501 + * + */ + static VALUE rb_stat_uid(self) VALUE self; @@ -193,6 +275,16 @@ rb_stat_uid(self) return UINT2NUM(get_stat(self)->st_uid); } +/* + * call-seq: + * stat.gid => fixnum + * + * Returns the numeric group id of the owner of <i>stat</i>. + * + * File.stat("testfile").gid #=> 500 + * + */ + static VALUE rb_stat_gid(self) VALUE self; @@ -200,6 +292,19 @@ rb_stat_gid(self) return UINT2NUM(get_stat(self)->st_gid); } + +/* + * call-seq: + * stat.rdev => fixnum or nil + * + * Returns an integer representing the device type on which + * <i>stat</i> resides. Returns <code>nil</code> if the operating + * system doesn't support this feature. + * + * File.stat("/dev/fd1").rdev #=> 513 + * File.stat("/dev/tty").rdev #=> 1280 + */ + static VALUE rb_stat_rdev(self) VALUE self; @@ -211,6 +316,17 @@ rb_stat_rdev(self) #endif } +/* + * call-seq: + * stat.rdev_major => fixnum + * + * Returns the major part of <code>File_Stat#rdev</code> or + * <code>nil</code>. + * + * File.stat("/dev/fd1").rdev_major #=> 2 + * File.stat("/dev/tty").rdev_major #=> 5 + */ + static VALUE rb_stat_rdev_major(self) VALUE self; @@ -223,6 +339,17 @@ rb_stat_rdev_major(self) #endif } +/* + * call-seq: + * stat.rdev_minor => fixnum + * + * Returns the minor part of <code>File_Stat#rdev</code> or + * <code>nil</code>. + * + * File.stat("/dev/fd1").rdev_minor #=> 1 + * File.stat("/dev/tty").rdev_minor #=> 0 + */ + static VALUE rb_stat_rdev_minor(self) VALUE self; @@ -235,6 +362,15 @@ rb_stat_rdev_minor(self) #endif } +/* + * call-seq: + * stat.size => fixnum + * + * Returns the size of <i>stat</i> in bytes. + * + * File.stat("testfile").size #=> 66 + */ + static VALUE rb_stat_size(self) VALUE self; @@ -242,6 +378,17 @@ rb_stat_size(self) return OFFT2NUM(get_stat(self)->st_size); } +/* + * call-seq: + * stat.blksize => integer or nil + * + * Returns the native file system's block size. Will return <code>nil</code> + * on platforms that don't support this information. + * + * File.stat("testfile").blksize #=> 4096 + * + */ + static VALUE rb_stat_blksize(self) VALUE self; @@ -253,6 +400,17 @@ rb_stat_blksize(self) #endif } +/* + * call-seq: + * stat.blocks => integer or nil + * + * Returns the number of native file system blocks allocated for this + * file, or <code>nil</code> if the operating system doesn't + * support this feature. + * + * File.stat("testfile").blocks #=> 2 + */ + static VALUE rb_stat_blocks(self) VALUE self; @@ -264,6 +422,18 @@ rb_stat_blocks(self) #endif } + +/* + * call-seq: + * stat.atime => time + * + * Returns the last access time for this file as an object of class + * <code>Time</code>. + * + * File.stat("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969 + * + */ + static VALUE rb_stat_atime(self) VALUE self; @@ -271,6 +441,16 @@ rb_stat_atime(self) return rb_time_new(get_stat(self)->st_atime, 0); } +/* + * call-seq: + * stat.mtime -> aTime + * + * Returns the modification time of <i>stat</i>. + * + * File.stat("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003 + * + */ + static VALUE rb_stat_mtime(self) VALUE self; @@ -278,6 +458,18 @@ rb_stat_mtime(self) return rb_time_new(get_stat(self)->st_mtime, 0); } +/* + * call-seq: + * stat.ctime -> aTime + * + * Returns the change time for <i>stat</i> (that is, the time + * directory information about the file was changed, not the file + * itself). + * + * File.stat("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003 + * + */ + static VALUE rb_stat_ctime(self) VALUE self; @@ -285,6 +477,20 @@ rb_stat_ctime(self) return rb_time_new(get_stat(self)->st_ctime, 0); } +/* + * call-seq: + * stat.inspect => string + * + * Produce a nicely formatted descriptin of <i>stat</i>. + * + * File.stat("/etc/passwd").inspect + * #=> "#<File::Stat dev=0xe000005, ino=1078078, mode=0100644, + * nlink=1, uid=0, gid=0, rdev=0x0, size=1374, blksize=4096, + * blocks=8, atime=Wed Dec 10 10:16:12 CST 2003, + * mtime=Fri Sep 12 15:41:41 CDT 2003, + * ctime=Mon Oct 27 11:20:27 CST 2003>" + */ + static VALUE rb_stat_inspect(self) VALUE self; @@ -364,6 +570,17 @@ rb_stat(file, st) return stat(StringValueCStr(file), st); } +/* + * call-seq: + * File.stat(file_name) => stat + * + * Returns a <code>File::Stat</code> object for the named file (see + * <code>File::Stat</code>). + * + * File.stat("testfile").mtime #=> Tue Apr 08 12:58:04 CDT 2003 + * + */ + static VALUE rb_file_s_stat(klass, fname) VALUE klass, fname; @@ -377,6 +594,21 @@ rb_file_s_stat(klass, fname) return stat_new(&st); } +/* + * call-seq: + * ios.stat => stat + * + * Returns status information for <em>ios</em> as an object of type + * <code>File::Stat</code>. + * + * f = File.new("testfile") + * s = f.stat + * "%o" % s.mode #=> "100644" + * s.blksize #=> 4096 + * s.atime #=> Wed Apr 09 08:53:54 CDT 2003 + * + */ + static VALUE rb_io_stat(obj) VALUE obj; @@ -391,6 +623,20 @@ rb_io_stat(obj) return stat_new(&st); } +/* + * call-seq: + * File.lstat(file_name) => stat + * + * Same as <code>File::stat</code>, but does not follow the last symbolic + * link. Instead, reports on the link itself. + * + * File.symlink("testfile", "link2test") #=> 0 + * File.stat("testfile").size #=> 66 + * File.lstat("link2test").size #=> 8 + * File.stat("link2test").size #=> 66 + * + */ + static VALUE rb_file_s_lstat(klass, fname) VALUE klass, fname; @@ -408,6 +654,21 @@ rb_file_s_lstat(klass, fname) #endif } + +/* + * call-seq: + * file.lstat => stat + * + * Same as <code>IO#stat</code>, but does not follow the last symbolic + * link. Instead, reports on the link itself. + * + * File.symlink("testfile", "link2test") #=> 0 + * File.stat("testfile").size #=> 66 + * f = File.new("link2test") + * f.lstat.size #=> 8 + * f.stat.size #=> 66 + */ + static VALUE rb_file_lstat(obj) VALUE obj; @@ -501,6 +762,28 @@ eaccess(path, mode) #endif } + +/* + * Document-class: FileTest + * + * <code>FileTest</code> implements file test operations similar to + * those used in <code>File::Stat</code>. It exists as a standalone + * module, and its methods are also insinuated into the <code>File</code> + * class. (Note that this is not done by inclusion: the interpreter cheats). + * + */ + + +/* + * call-seq: + * File.directory?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a directory, + * <code>false</code> otherwise. + * + * File.directory?(".") + */ + static VALUE test_d(obj, fname) VALUE obj, fname; @@ -516,6 +799,13 @@ test_d(obj, fname) return Qfalse; } +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a pipe. + */ + static VALUE test_p(obj, fname) VALUE obj, fname; @@ -534,6 +824,13 @@ test_p(obj, fname) return Qfalse; } +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a symbolic link. + */ + static VALUE test_l(obj, fname) VALUE obj, fname; @@ -571,6 +868,13 @@ test_l(obj, fname) return Qfalse; } +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a socket. + */ + static VALUE test_S(obj, fname) VALUE obj, fname; @@ -607,6 +911,13 @@ test_S(obj, fname) return Qfalse; } +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a block device. + */ + static VALUE test_b(obj, fname) VALUE obj, fname; @@ -629,6 +940,12 @@ test_b(obj, fname) return Qfalse; } +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a character device. + */ static VALUE test_c(obj, fname) VALUE obj, fname; @@ -645,6 +962,15 @@ test_c(obj, fname) return Qfalse; } + +/* + * call-seq: + * File.exist?(file_name) => true or false + * File.exists?(file_name) => true or false (obsolete) + * + * Return <code>true</code> if the named file exists. + */ + static VALUE test_e(obj, fname) VALUE obj, fname; @@ -655,6 +981,14 @@ test_e(obj, fname) return Qtrue; } +/* + * call-seq: + * File.readable?(file_name) => true or false + * + * Returns <code>true</code> if the named file is readable by the effective + * user id of this process. + */ + static VALUE test_r(obj, fname) VALUE obj, fname; @@ -664,6 +998,14 @@ test_r(obj, fname) return Qtrue; } +/* + * call-seq: + * File.readable_real?(file_name) => true or false + * + * Returns <code>true</code> if the named file is readable by the real + * user id of this process. + */ + static VALUE test_R(obj, fname) VALUE obj, fname; @@ -673,6 +1015,15 @@ test_R(obj, fname) return Qtrue; } + +/* + * call-seq: + * File.writable?(file_name) => true or false + * + * Returns <code>true</code> if the named file is writable by the effective + * user id of this process. + */ + static VALUE test_w(obj, fname) VALUE obj, fname; @@ -682,6 +1033,14 @@ test_w(obj, fname) return Qtrue; } +/* + * call-seq: + * File.writable_real?(file_name) => true or false + * + * Returns <code>true</code> if the named file is writable by the real + * user id of this process. + */ + static VALUE test_W(obj, fname) VALUE obj, fname; @@ -691,6 +1050,14 @@ test_W(obj, fname) return Qtrue; } +/* + * call-seq: + * File.executable?(file_name) => true or false + * + * Returns <code>true</code> if the named file is executable by the effective + * user id of this process. + */ + static VALUE test_x(obj, fname) VALUE obj, fname; @@ -700,6 +1067,14 @@ test_x(obj, fname) return Qtrue; } +/* + * call-seq: + * File.executable_real?(file_name) => true or false + * + * Returns <code>true</code> if the named file is executable by the real + * user id of this process. + */ + static VALUE test_X(obj, fname) VALUE obj, fname; @@ -713,6 +1088,14 @@ test_X(obj, fname) # define S_ISREG(m) ((m & S_IFMT) == S_IFREG) #endif +/* + * call-seq: + * File.file?(file_name) => true or false + * + * Returns <code>true</code> if the named file exists and is a + * regular file. + */ + static VALUE test_f(obj, fname) VALUE obj, fname; @@ -724,6 +1107,14 @@ test_f(obj, fname) return Qfalse; } +/* + * call-seq: + * File.zero?(file_name) => true or false + * + * Returns <code>true</code> if the named file exists and has + * a zero size. + */ + static VALUE test_z(obj, fname) VALUE obj, fname; @@ -735,6 +1126,14 @@ test_z(obj, fname) return Qfalse; } +/* + * call-seq: + * File.file?(file_name) => integer or nil + * + * Returns <code>nil</code> if <code>file_name</code> doesn't + * exist or has zero size, the size of the file otherwise. + */ + static VALUE test_s(obj, fname) VALUE obj, fname; @@ -746,6 +1145,15 @@ test_s(obj, fname) return OFFT2NUM(st.st_size); } +/* + * call-seq: + * File.owned?(file_name) => true or false + * + * Returns <code>true</code> if the named file exists and the + * effective used id of the calling process is the owner of + * the file. + */ + static VALUE test_owned(obj, fname) VALUE obj, fname; @@ -768,6 +1176,15 @@ test_rowned(obj, fname) return Qfalse; } +/* + * call-seq: + * File.grpowned?(file_name) => true or false + * + * Returns <code>true</code> if the named file exists and the + * effective group id of the calling process is the owner of + * the file. Returns <code>false</code> on Windows. + */ + static VALUE test_grpowned(obj, fname) VALUE obj, fname; @@ -796,6 +1213,13 @@ check3rdbyte(fname, mode) } #endif +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a has the setuid bit set. + */ + static VALUE test_suid(obj, fname) VALUE obj, fname; @@ -807,6 +1231,13 @@ test_suid(obj, fname) #endif } +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a has the setgid bit set. + */ + static VALUE test_sgid(obj, fname) VALUE obj, fname; @@ -818,6 +1249,13 @@ test_sgid(obj, fname) #endif } +/* + * call-seq: + * File.pipe?(file_name) => true or false + * + * Returns <code>true</code> if the named file is a has the sticky bit set. + */ + static VALUE test_sticky(obj, fname) VALUE obj, fname; @@ -829,6 +1267,13 @@ test_sticky(obj, fname) #endif } +/* + * call-seq: + * File.size(file_name) => integer + * + * Returns the size of <code>file_name</code>. + */ + static VALUE rb_file_s_size(klass, fname) VALUE klass, fname; @@ -882,6 +1327,21 @@ rb_file_ftype(st) return rb_str_new2(t); } +/* + * call-seq: + * File.ftype(file_name) => string + * + * Identifies the type of the named file; the return string is one of + * ``<code>file</code>'', ``<code>directory</code>'', + * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'', + * ``<code>fifo</code>'', ``<code>link</code>'', + * ``<code>socket</code>'', or ``<code>unknown</code>''. + * + * File.ftype("testfile") #=> "file" + * File.ftype("/dev/tty") #=> "characterSpecial" + * File.ftype("/tmp/.X11-unix/X0") #=> "socket" + */ + static VALUE rb_file_s_ftype(klass, fname) VALUE klass, fname; @@ -896,6 +1356,16 @@ rb_file_s_ftype(klass, fname) return rb_file_ftype(&st); } +/* + * call-seq: + * File.atime(file_name) => time + * + * Returns the last access time for the named file as a Time object). + * + * File.atime("testfile") #=> Wed Apr 09 08:51:48 CDT 2003 + * + */ + static VALUE rb_file_s_atime(klass, fname) VALUE klass, fname; @@ -907,6 +1377,17 @@ rb_file_s_atime(klass, fname) return rb_time_new(st.st_atime, 0); } +/* + * call-seq: + * file.atime => time + * + * Returns the last access time (a <code>Time</code> object) + * for <i>file</i>, or epoch if <i>file</i> has not been accessed. + * + * File.new("testfile").atime #=> Wed Dec 31 18:00:00 CST 1969 + * + */ + static VALUE rb_file_atime(obj) VALUE obj; @@ -921,6 +1402,16 @@ rb_file_atime(obj) return rb_time_new(st.st_atime, 0); } +/* + * call-seq: + * File.mtime(file_name) => time + * + * Returns the modification time for the named file as a Time object. + * + * File.mtime("testfile") #=> Tue Apr 08 12:58:04 CDT 2003 + * + */ + static VALUE rb_file_s_mtime(klass, fname) VALUE klass, fname; @@ -932,6 +1423,16 @@ rb_file_s_mtime(klass, fname) return rb_time_new(st.st_mtime, 0); } +/* + * call-seq: + * file.mtime -> time + * + * Returns the modification time for <i>file</i>. + * + * File.new("testfile").mtime #=> Wed Apr 09 08:53:14 CDT 2003 + * + */ + static VALUE rb_file_mtime(obj) VALUE obj; @@ -946,6 +1447,18 @@ rb_file_mtime(obj) return rb_time_new(st.st_mtime, 0); } +/* + * call-seq: + * File.ctime(file_name) => time + * + * Returns the change time for the named file (the time at which + * directory information about the file was changed, not the file + * itself). + * + * File.ctime("testfile") #=> Wed Apr 09 08:53:13 CDT 2003 + * + */ + static VALUE rb_file_s_ctime(klass, fname) VALUE klass, fname; @@ -957,6 +1470,17 @@ rb_file_s_ctime(klass, fname) return rb_time_new(st.st_ctime, 0); } +/* + * call-seq: + * file.ctime -> time + * + * Returns the change time for <i>file</i> (that is, the time directory + * information about the file was changed, not the file itself). + * + * File.new("testfile").ctime #=> Wed Apr 09 08:53:14 CDT 2003 + * + */ + static VALUE rb_file_ctime(obj) VALUE obj; @@ -980,6 +1504,19 @@ chmod_internal(path, mode) rb_sys_fail(path); } +/* + * call-seq: + * File.chmod(mode_int, file_name, ... ) -> integer + * + * Changes permission bits on the named file(s) to the bit pattern + * represented by <i>mode_int</i>. Actual effects are operating system + * dependent (see the beginning of this section). On Unix systems, see + * <code>chmod(2)</code> for details. Returns the number of files + * processed. + * + * File.chmod(0644, "testfile", "out") #=> 2 + */ + static VALUE rb_file_s_chmod(argc, argv) int argc; @@ -998,6 +1535,19 @@ rb_file_s_chmod(argc, argv) return LONG2FIX(n); } +/* + * call-seq: + * file.chmod(mode_int) => 0 + * + * Changes permission bits on <i>file</i> to the bit pattern + * represented by <i>mode_int</i>. Actual effects are platform + * dependent; on Unix systems, see <code>chmod(2)</code> for details. + * Follows symbolic links. Also see <code>File#lchmod</code>. + * + * f = File.new("out", "w"); + * f.chmod(0644) #=> 0 + */ + static VALUE rb_file_chmod(obj, vmode) VALUE obj, vmode; @@ -1031,6 +1581,16 @@ lchmod_internal(path, mode) rb_sys_fail(path); } +/* + * call-seq: + * File.lchmod(mode_int, file_name, ...) => integer + * + * Equivalent to <code>File::chmod</code>, but does not follow symbolic + * links (so it will change the permissions associated with the link, + * not the file referenced by the link). Often not available. + * + */ + static VALUE rb_file_s_lchmod(argc, argv) int argc; @@ -1072,6 +1632,21 @@ chown_internal(path, args) rb_sys_fail(path); } +/* + * call-seq: + * File.chown(owner_int, group_int, file_name,... ) -> integer + * + * Changes the owner and group of the named file(s) to the given + * numeric owner and group id's. Only a process with superuser + * privileges may change the owner of a file. The current owner of a + * file may change the file's group to any group to which the owner + * belongs. A <code>nil</code> or -1 owner or group id is ignored. + * Returns the number of files processed. + * + * File.chown(nil, 100, "testfile") + * + */ + static VALUE rb_file_s_chown(argc, argv) int argc; @@ -1100,6 +1675,21 @@ rb_file_s_chown(argc, argv) return LONG2FIX(n); } +/* + * call-seq: + * file.chown(owner_int, group_int ) => 0 + * + * Changes the owner and group of <i>file</i> to the given numeric + * owner and group id's. Only a process with superuser privileges may + * change the owner of a file. The current owner of a file may change + * the file's group to any group to which the owner belongs. A + * <code>nil</code> or -1 owner or group id is ignored. Follows + * symbolic links. See also <code>File#lchown</code>. + * + * File.new("testfile").chown(502, 1000) + * + */ + static VALUE rb_file_chown(obj, owner, group) VALUE obj, owner, group; @@ -1130,6 +1720,18 @@ lchown_internal(path, args) rb_sys_fail(path); } + +/* + * call-seq: + * file.lchown(owner_int, group_int, file_name,..) => integer + * + * Equivalent to <code>File::chown</code>, but does not follow symbolic + * links (so it will change the owner associated with the link, not the + * file referenced by the link). Often not available. Returns number + * of files in the argument list. + * + */ + static VALUE rb_file_s_lchown(argc, argv) int argc; @@ -1180,6 +1782,15 @@ utime_internal(path, tvp) rb_sys_fail(path); } +/* + * call-seq: + * File.utime(atime, mtime, file_name,...) => integer + * + * Sets the access and modification times of each + * named file to the first two arguments. Returns + * the number of file names in the argument list. + */ + static VALUE rb_file_s_utime(argc, argv) int argc; @@ -1253,6 +1864,18 @@ sys_fail2(s1, s2) rb_sys_fail(buf); } +/* + * call-seq: + * File.link(old_name, new_name) => 0 + * + * Creates a new name for an existing file using a hard link. Will not + * overwrite <i>new_name</i> if it already exists (raising a subclass + * of <code>SystemCallError</code>). Not available on all platforms. + * + * File.link("testfile", ".testfile") #=> 0 + * IO.readlines(".testfile")[0] #=> "This is line one\n" + */ + static VALUE rb_file_s_link(klass, from, to) VALUE klass, from, to; @@ -1266,6 +1889,18 @@ rb_file_s_link(klass, from, to) return INT2FIX(0); } +/* + * call-seq: + * File.symlink(old_name, new_name) => 0 + * + * Creates a symbolic link called <i>new_name</i> for the existing file + * <i>old_name</i>. Raises a <code>NotImplemented</code> exception on + * platforms that do not support symbolic links. + * + * File.symlink("testfile", "link2test") #=> 0 + * + */ + static VALUE rb_file_s_symlink(klass, from, to) VALUE klass, from, to; @@ -1284,6 +1919,17 @@ rb_file_s_symlink(klass, from, to) #endif } +/* + * call-seq: + * File.readlink(link_name) -> file_name + * + * Returns the name of the file referenced by the given link. + * Not available on all platforms. + * + * File.symlink("testfile", "link2test") #=> 0 + * File.readlink("link2test") #=> "testfile" + */ + static VALUE rb_file_s_readlink(klass, path) VALUE klass, path; @@ -1322,6 +1968,16 @@ unlink_internal(path) rb_sys_fail(path); } +/* + * call-seq: + * File.delete(file_name, ...) => integer + * File.unlink(file_name, ...) => integer + * + * Deletes the named files, returning the number of names + * passed as arguments. Raises an exception on any error. + * See also <code>Dir::rmdir</code>. + */ + static VALUE rb_file_s_unlink(klass, args) VALUE klass, args; @@ -1333,6 +1989,16 @@ rb_file_s_unlink(klass, args) return LONG2FIX(n); } +/* + * call-seq: + * File.rename(old_name, new_name) => 0 + * + * Renames the given file to the new name. Raises a + * <code>SystemCallError</code> if the file cannot be renamed. + * + * File.rename("afile", "afile.bak") #=> 0 + */ + static VALUE rb_file_s_rename(klass, from, to) VALUE klass, from, to; @@ -1365,6 +2031,21 @@ rb_file_s_rename(klass, from, to) return INT2FIX(0); } +/* + * call-seq: + * File.umask() => integer + * File.umask(integer) => integer + * + * Returns the current umask value for this process. If the optional + * argument is given, set the umask to that value and return the + * previous value. Umask values are <em>subtracted</em> from the + * default permissions, so a umask of <code>0222</code> would make a + * file read-only for everyone. + * + * File.umask(0006) #=> 18 + * File.umask #=> 6 + */ + static VALUE rb_file_s_umask(argc, argv) int argc; @@ -1758,6 +2439,23 @@ rb_file_expand_path(fname, dname) return file_expand_path(fname, dname, rb_str_new(0, MAXPATHLEN + 2)); } +/* + * call-seq: + * File.expand_path(file_name [, dir_string] ) -> abs_file_name + * + * Converts a pathname to an absolute pathname. Relative paths are + * referenced from the current working directory of the process unless + * <i>dir_string</i> is given, in which case it will be used as the + * starting point. The given pathname may start with a + * ``<code>~</code>'', which expands to the process owner's home + * directory (the environment variable <code>HOME</code> must be set + * correctly). ``<code>~</code><i>user</i>'' expands to the named + * user's home directory. + * + * File.expand_path("~oracle/bin") #=> "/home/oracle/bin" + * File.expand_path("../../bin", "/tmp/x") #=> "/bin" + */ + VALUE rb_file_s_expand_path(argc, argv) int argc; @@ -1796,6 +2494,20 @@ rmext(p, e) return 0; } +/* + * call-seq: + * File.basename(file_name [, suffix] ) -> base_name + * + * Returns the last component of the filename given in <i>file_name</i>, + * which must be formed using forward slashes (``<code>/</code>'') + * regardless of the separator used on the local file system. If + * <i>suffix</i> is given and present at the end of <i>file_name</i>, + * it is removed. + * + * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb" + * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" + */ + static VALUE rb_file_s_basename(argc, argv) int argc; @@ -1839,6 +2551,18 @@ rb_file_s_basename(argc, argv) return basename; } +/* + * call-seq: + * File.dirname(file_name ) -> dir_name + * + * Returns all components of the filename given in <i>file_name</i> + * except the last one. The filename must be formed using forward + * slashes (``<code>/</code>'') regardless of the separator used on the + * local file system. + * + * File.dirname("/home/gumby/work/ruby.rb") #=> "/home/gumby/work" + */ + static VALUE rb_file_s_dirname(klass, fname) VALUE klass, fname; @@ -1870,6 +2594,20 @@ rb_file_s_dirname(klass, fname) return dirname; } +/* + * call-seq: + * File.extname(path) -> string + * + * Returns the extension (the portion of file name in <i>path</i> + * after the period). + * + * File.extname("test.rb") #=> ".rb" + * File.extname("a/b/d/test.rb") #=> ".rb" + * File.extname("test") #=> "" + * File.extname(".profile") #=> "" + * + */ + static VALUE rb_file_s_extname(klass, fname) VALUE klass, fname; @@ -1892,6 +2630,17 @@ rb_file_s_extname(klass, fname) return extname; } +/* + * call-seq: + * File.split(file_name) => array + * + * Splits the given string into a directory and a file component and + * returns them in a two-element array. See also + * <code>File::dirname</code> and <code>File::basename</code>. + * + * File.split("/home/gumby/.profile") #=> ["/home/gumby", ".profile"] + */ + static VALUE rb_file_s_split(klass, path) VALUE klass, path; @@ -1969,6 +2718,17 @@ rb_file_join(ary, sep) return result; } +/* + * call-seq: + * File.join(string, ...) -> path + * + * Returns a new string formed by joining the strings using + * <code>File::SEPARATOR</code>. + * + * File.join("usr", "mail", "gumby") #=> "usr/mail/gumby" + * + */ + static VALUE rb_file_s_join(klass, args) VALUE klass, args; @@ -1976,6 +2736,21 @@ rb_file_s_join(klass, args) return rb_file_join(args, separator); } +/* + * call-seq: + * File.truncate(file_name, integer) => 0 + * + * Truncates the file <i>file_name</i> to be at most <i>integer</i> + * bytes long. Not available on all platforms. + * + * f = File.new("out", "w") + * f.write("1234567890") #=> 10 + * f.close #=> nil + * File.truncate("out", 5) #=> 0 + * File.size("out") #=> 5 + * + */ + static VALUE rb_file_s_truncate(klass, path, len) VALUE klass, path, len; @@ -2013,6 +2788,20 @@ rb_file_s_truncate(klass, path, len) return INT2FIX(0); } +/* + * call-seq: + * file.truncate(integer) => 0 + * + * Truncates <i>file</i> to at most <i>integer</i> bytes. The file + * must be opened for writing. Not available on all platforms. + * + * f = File.new("out", "w") + * f.syswrite("1234567890") #=> 10 + * f.truncate(5) #=> 0 + * f.close() #=> nil + * File.size("out") #=> 5 + */ + static VALUE rb_file_truncate(obj, len) VALUE obj, len; @@ -2080,6 +2869,35 @@ rb_thread_flock(fd, op, fptr) #define flock(fd, op) rb_thread_flock(fd, op, fptr) #endif +/* + * call-seq: + * file.flock (locking_constant ) => 0 or false + * + * Locks or unlocks a file according to <i>locking_constant</i> (a + * logical <em>or</em> of the values in the table below). + * Returns <code>false</code> if <code>File::LOCK_NB</code> is + * specified and the operation would otherwise have blocked. Not + * available on all platforms. + * + * Locking constants (in class File): + * + * LOCK_EX | Exclusive lock. Only one process may hold an + * | exclusive lock for a given file at a time. + * ----------+------------------------------------------------ + * LOCK_NB | Don't block when locking. May be combined + * | with other lock options using logical or. + * ----------+------------------------------------------------ + * LOCK_SH | Shared lock. Multiple processes may each hold a + * | shared lock for a given file at the same time. + * ----------+------------------------------------------------ + * LOCK_UN | Unlock. + * + * Example: + * + * File.new("testfile").flock(File::LOCK_UN) #=> 0 + * + */ + static VALUE rb_file_flock(obj, operation) VALUE obj; @@ -2143,6 +2961,65 @@ test_check(n, argc, argv) #define CHECK(n) test_check((n), argc, argv) +/* + * call-seq: + * test(int_cmd, file1 [, file2] ) => obj + * + * Uses the integer <i>aCmd</i> to perform various tests on + * <i>file1</i> (first table below) or on <i>file1</i> and + * <i>file2</i> (second table). + * + * File tests on a single file: + * + * Test Returns Meaning + * ?A | Time | Last access time for file1 + * ?b | boolean | True if file1 is a block device + * ?c | boolean | True if file1 is a character device + * ?C | Time | Last change time for file1 + * ?d | boolean | True if file1 exists and is a directory + * ?e | boolean | True if file1 exists + * ?f | boolean | True if file1 exists and is a regular file + * ?g | boolean | True if files has the \CF{setgid} bit + * | | set (false under NT) + * ?G | boolean | True if file1 exists and has a group + * | | ownership equal to the caller's group + * ?k | boolean | True if file1 exists and has the sticky bit set + * ?l | boolean | True if files exists and is a symbolic link + * ?M | Time | Last modification time for file1 + * ?o | boolean | True if files exists and is owned by + * | | the caller's effective uid + * ?O | boolean | True if file1 exists and is owned by + * | | the caller's real uid + * ?p | boolean | True if file1 exists and is a fifo + * ?r | boolean | True if file1 is readable by the effective + * | | uid/gid of the caller + * ?R | boolean | True if file is readable by the real + * | | uid/gid of the caller + * ?s | int/nil | If files has nonzero size, return the size, + * | | otherwise return nil + * ?S | boolean | True if file1 exists and is a socket + * ?u | boolean | True if file1 has the setuid bit set + * ?w | boolean | True if file1 exists and is writable by + * | | the effective uid/gid + * ?W | boolean | True if file1 exists and is writable by + * | | the real uid/gid + * ?x | boolean | True if file1 exists and is executable by + * | | the effective uid/gid + * ?X | boolean | True if file1 exists and is executable by + * | | the real uid/gid + * ?z | boolean | True if file1 exists and has a zero length + * + * Tests that take two files: + * + * ?- | boolean | True if file1 is a hard link to file2 + * ?= | boolean | True if the modification times of file1 + * | | and file2 are equal + * ?< | boolean | True if the modification time of file1 + * | | is prior to that of file2 + * ?> | boolean | True if the modification time of file1 + * | | is after that of file2 + */ + static VALUE rb_f_test(argc, argv) int argc; @@ -2279,6 +3156,22 @@ rb_f_test(argc, argv) return Qnil; /* not reached */ } + + +/* + * Document-class: File::Stat + * + * Objects of class <code>File::Stat</code> encapsulate common status + * information for <code>File</code> objects. The information is + * recorded at the moment the <code>File::Stat</code> object is + * created; changes made to the file after that point will not be + * reflected. <code>File::Stat</code> objects are returned by + * <code>IO#stat</code>, <code>File::stat</code>, + * <code>File#lstat</code>, and <code>File::lstat</code>. Many of these + * methods return platform-specific values, and not all values are + * meaningful on all systems. See also <code>Kernel#test</code>. + */ + static VALUE rb_stat_s_alloc _((VALUE)); static VALUE rb_stat_s_alloc(klass) @@ -2287,6 +3180,15 @@ rb_stat_s_alloc(klass) return stat_new_0(klass, 0); } +/* + * call-seq: + * + * File::Stat.new(file_name) => stat + * + * Create a File::Stat object for the given file name (raising an + * exception if the file doesn't exist). + */ + static VALUE rb_stat_init(obj, fname) VALUE obj, fname; @@ -2334,6 +3236,20 @@ rb_stat_init_copy(copy, orig) return copy; } +/* + * call-seq: + * stat.ftype => string + * + * Identifies the type of <i>stat</i>. The return string is one of: + * ``<code>file</code>'', ``<code>directory</code>'', + * ``<code>characterSpecial</code>'', ``<code>blockSpecial</code>'', + * ``<code>fifo</code>'', ``<code>link</code>'', + * ``<code>socket</code>'', or ``<code>unknown</code>''. + * + * File.stat("/dev/tty").ftype #=> "characterSpecial" + * + */ + static VALUE rb_stat_ftype(obj) VALUE obj; @@ -2341,6 +3257,17 @@ rb_stat_ftype(obj) return rb_file_ftype(get_stat(obj)); } +/* + * call-seq: + * stat.directory? => true or false + * + * Returns <code>true</code> if <i>stat</i> is a directory, + * <code>false</code> otherwise. + * + * File.stat("testfile").directory? #=> false + * File.stat(".").directory? #=> true + */ + static VALUE rb_stat_d(obj) VALUE obj; @@ -2349,6 +3276,14 @@ rb_stat_d(obj) return Qfalse; } +/* + * call-seq: + * stat.pipe? => true or false + * + * Returns <code>true</code> if the operating system supports pipes and + * <i>stat</i> is a pipe; <code>false</code> otherwise. + */ + static VALUE rb_stat_p(obj) VALUE obj; @@ -2360,6 +3295,23 @@ rb_stat_p(obj) return Qfalse; } +/* + * call-seq: + * stat.symlink? => true or false + * + * Returns <code>true</code> if <i>stat</i> is a symbolic link, + * <code>false</code> if it isn't or if the operating system doesn't + * support this feature. As <code>File::stat</code> automatically + * follows symbolic links, <code>symlink?</code> will always be + * <code>false</code> for an object returned by + * <code>File::stat</code>. + * + * File.symlink("testfile", "alink") #=> 0 + * File.stat("alink").symlink? #=> false + * File.lstat("alink").symlink? #=> true + * + */ + static VALUE rb_stat_l(obj) VALUE obj; @@ -2370,6 +3322,18 @@ rb_stat_l(obj) return Qfalse; } +/* + * call-seq: + * stat.socket? => true or false + * + * Returns <code>true</code> if <i>stat</i> is a socket, + * <code>false</code> if it isn't or if the operating system doesn't + * support this feature. + * + * File.stat("testfile").socket? #=> false + * + */ + static VALUE rb_stat_S(obj) VALUE obj; @@ -2381,6 +3345,19 @@ rb_stat_S(obj) return Qfalse; } +/* + * call-seq: + * stat.blockdev? => true or false + * + * Returns <code>true</code> if the file is a block device, + * <code>false</code> if it isn't or if the operating system doesn't + * support this feature. + * + * File.stat("testfile").blockdev? #=> false + * File.stat("/dev/hda1").blockdev? #=> true + * + */ + static VALUE rb_stat_b(obj) VALUE obj; @@ -2392,6 +3369,18 @@ rb_stat_b(obj) return Qfalse; } +/* + * call-seq: + * stat.chardev? => true or false + * + * Returns <code>true</code> if the file is a character device, + * <code>false</code> if it isn't or if the operating system doesn't + * support this feature. + * + * File.stat("/dev/tty").chardev? #=> true + * + */ + static VALUE rb_stat_c(obj) VALUE obj; @@ -2401,6 +3390,18 @@ rb_stat_c(obj) return Qfalse; } +/* + * call-seq: + * stat.owned? => true or false + * + * Returns <code>true</code> if the effective user id of the process is + * the same as the owner of <i>stat</i>. + * + * File.stat("testfile").owned? #=> true + * File.stat("/etc/passwd").owned? #=> false + * + */ + static VALUE rb_stat_owned(obj) VALUE obj; @@ -2417,6 +3418,18 @@ rb_stat_rowned(obj) return Qfalse; } +/* + * call-seq: + * stat.grpowned? => true or false + * + * Returns true if the effective group id of the process is the same as + * the group id of <i>stat</i>. On Windows NT, returns <code>false</code>. + * + * File.stat("testfile").grpowned? #=> true + * File.stat("/etc/passwd").grpowned? #=> false + * + */ + static VALUE rb_stat_grpowned(obj) VALUE obj; @@ -2427,6 +3440,17 @@ rb_stat_grpowned(obj) return Qfalse; } +/* + * call-seq: + * stat.readable? => true or false + * + * Returns <code>true</code> if <i>stat</i> is readable by the + * effective user id of this process. + * + * File.stat("testfile").readable? #=> true + * + */ + static VALUE rb_stat_r(obj) VALUE obj; @@ -2447,6 +3471,19 @@ rb_stat_r(obj) return Qtrue; } + + +/* + * call-seq: + * stat.readable_real? -> true or false + * + * Returns <code>true</code> if <i>stat</i> is readable by the real + * user id of this process. + * + * File.stat("testfile").readable_real? #=> true + * + */ + static VALUE rb_stat_R(obj) VALUE obj; @@ -2467,6 +3504,17 @@ rb_stat_R(obj) return Qtrue; } +/* + * call-seq: + * stat.writable? -> true or false + * + * Returns <code>true</code> if <i>stat</i> is writable by the + * effective user id of this process. + * + * File.stat("testfile").writable? #=> true + * + */ + static VALUE rb_stat_w(obj) VALUE obj; @@ -2487,6 +3535,17 @@ rb_stat_w(obj) return Qtrue; } +/* + * call-seq: + * stat.writable_real? -> true or false + * + * Returns <code>true</code> if <i>stat</i> is writable by the real + * user id of this process. + * + * File.stat("testfile").writable_real? #=> true + * + */ + static VALUE rb_stat_W(obj) VALUE obj; @@ -2507,6 +3566,19 @@ rb_stat_W(obj) return Qtrue; } +/* + * call-seq: + * stat.executable? => true or false + * + * Returns <code>true</code> if <i>stat</i> is executable or if the + * operating system doesn't distinguish executable files from + * nonexecutable files. The tests are made using the effective owner of + * the process. + * + * File.stat("testfile").executable? #=> false + * + */ + static VALUE rb_stat_x(obj) VALUE obj; @@ -2527,6 +3599,15 @@ rb_stat_x(obj) return Qtrue; } +/* + * call-seq: + * stat.executable_real? => true or false + * + * Same as <code>executable?</code>, but tests using the real owner of + * the process. + */ + + static VALUE rb_stat_X(obj) VALUE obj; @@ -2547,6 +3628,17 @@ rb_stat_X(obj) return Qtrue; } +/* + * call-seq: + * stat.file? => true or false + * + * Returns <code>true</code> if <i>stat</i> is a regular file (not + * a device file, pipe, socket, etc.). + * + * File.stat("testfile").file? #=> true + * + */ + static VALUE rb_stat_f(obj) VALUE obj; @@ -2555,6 +3647,17 @@ rb_stat_f(obj) return Qfalse; } +/* + * call-seq: + * stat.zero? => true or false + * + * Returns <code>true</code> if <i>stat</i> is a zero-length file; + * <code>false</code> otherwise. + * + * File.stat("testfile").zero? #=> false + * + */ + static VALUE rb_stat_z(obj) VALUE obj; @@ -2563,6 +3666,17 @@ rb_stat_z(obj) return Qfalse; } + +/* + * call-seq: + * state.size => integer + * + * Returns the size of <i>stat</i> in bytes. + * + * File.stat("testfile").size #=> 66 + * + */ + static VALUE rb_stat_s(obj) VALUE obj; @@ -2573,6 +3687,17 @@ rb_stat_s(obj) return OFFT2NUM(size); } +/* + * call-seq: + * stat.setuid? => true or false + * + * Returns <code>true</code> if <i>stat</i> has the set-user-id + * permission bit set, <code>false</code> if it doesn't or if the + * operating system doesn't support this feature. + * + * File.stat("/bin/su").setuid? #=> true + */ + static VALUE rb_stat_suid(obj) VALUE obj; @@ -2583,6 +3708,18 @@ rb_stat_suid(obj) return Qfalse; } +/* + * call-seq: + * stat.setgid? => true or false + * + * Returns <code>true</code> if <i>stat</i> has the set-group-id + * permission bit set, <code>false</code> if it doesn't or if the + * operating system doesn't support this feature. + * + * File.stat("/usr/sbin/lpc").setgid? #=> true + * + */ + static VALUE rb_stat_sgid(obj) VALUE obj; @@ -2593,6 +3730,18 @@ rb_stat_sgid(obj) return Qfalse; } +/* + * call-seq: + * stat.sticky? => true or false + * + * Returns <code>true</code> if <i>stat</i> has its sticky bit set, + * <code>false</code> if it doesn't or if the operating system doesn't + * support this feature. + * + * File.stat("testfile").sticky? #=> false + * + */ + static VALUE rb_stat_sticky(obj) VALUE obj; @@ -2863,6 +4012,39 @@ define_filetest_function(name, func, argc) rb_define_singleton_method(rb_cFile, name, func, argc); } + +/* + * A <code>File</code> is an abstraction of any file object accessible + * by the program and is closely associated with class <code>IO</code> + * <code>File</code> includes the methods of module + * <code>FileTest</code> as class methods, allowing you to write (for + * example) <code>File.exist?("foo")</code>. + * + * In the description of File methods, + * <em>permission bits</em> are a platform-specific + * set of bits that indicate permissions of a file. On Unix-based + * systems, permissions are viewed as a set of three octets, for the + * owner, the group, and the rest of the world. For each of these + * entities, permissions may be set to read, write, or execute the + * file: + * + * The permission bits <code>0644</code> (in octal) would thus be + * interpreted as read/write for owner, and read-only for group and + * other. Higher-order bits may also be used to indicate the type of + * file (plain, directory, pipe, socket, and so on) and various other + * special features. If the permissions are for a directory, the + * meaning of the execute bit changes; when set the directory can be + * searched. + * + * On non-Posix operating systems, there may be only the ability to + * make a file read-only or read-write. In this case, the remaining + * permission bits will be synthesized to resemble typical values. For + * instance, on Windows NT the default permission bits are + * <code>0644</code>, which means read/write for owner, read-only for + * all others. The only change that can be made is to make the file + * read-only, which is reported as <code>0444</code>. + */ + void Init_File() { diff --git a/lib/rdoc/generators/ri_generator.rb b/lib/rdoc/generators/ri_generator.rb index 4e842d09e9..22467e4ba9 100644 --- a/lib/rdoc/generators/ri_generator.rb +++ b/lib/rdoc/generators/ri_generator.rb @@ -96,10 +96,14 @@ module Generators end def generate_class_info(cls) - cls_desc = RI::ClassDescription.new + if cls === RDoc::NormalModule + cls_desc = RI::ClassDescription.new + cls_desc.superclass = cls.superclass + else + cls_desc = RI::ModuleDescription.new + end cls_desc.name = cls.name cls_desc.full_name = cls.full_name - cls_desc.superclass = cls.superclass cls_desc.comment = markup(cls.comment) cls_desc.attributes =cls.attributes.sort.map do |a| diff --git a/lib/rdoc/parsers/parse_c.rb b/lib/rdoc/parsers/parse_c.rb index 0cc19d851f..1de4797c5f 100644 --- a/lib/rdoc/parsers/parse_c.rb +++ b/lib/rdoc/parsers/parse_c.rb @@ -156,7 +156,6 @@ module RDoc end def handle_class_module(var_name, class_mod, class_name, parent, in_module) - @known_classes[var_name] = class_name parent_name = @known_classes[parent] || parent if in_module @@ -176,8 +175,10 @@ module RDoc cm = enclosure.add_module(NormalModule, class_name) end cm.record_location(enclosure.toplevel) - find_class_comment(class_name, cm) + + find_class_comment(cm.full_name, cm) @classes[var_name] = cm + @known_classes[var_name] = cm.full_name end @@ -186,8 +187,8 @@ module RDoc if @body =~ %r{((?>/\*.*?\*/\s+)) (static\s+)?void\s+Init_#{class_name}\s*\(\)}xm comment = $1 - elsif @body =~ %r{Document-class:\s#{class_name}.*?\n((?>.*?\*/))}m - comment = $1 + elsif @body =~ %r{Document-(class|module):\s#{class_name}.*?\n((?>.*?\*/))}m + comment = $2 end class_meth.comment = mangle_comment(comment) if comment end @@ -198,16 +199,6 @@ module RDoc handle_class_module(var_name, "module", class_name, nil, nil) end - @body.scan(/(\w+)\s* = \s*rb_define_module_under - \( - \s*(\w+), - \s*"(\w+)" - \)/mx) do - - |var_name, in_module, class_name| - handle_class_module(var_name, "module", class_name, nil, in_module) - end - @body.scan(/(\w+)\s* = \s*rb_define_class \( \s*"(\w+)", @@ -224,6 +215,16 @@ module RDoc handle_class_module(var_name, "class", class_name, parent, nil) end + @body.scan(/(\w+)\s* = \s*rb_define_module_under + \( + \s*(\w+), + \s*"(\w+)" + \)/mx) do + + |var_name, in_module, class_name| + handle_class_module(var_name, "module", class_name, nil, in_module) + end + @body.scan(/(\w+)\s* = \s*rb_define_class_under \( \s*(\w+), @@ -247,32 +248,56 @@ module RDoc next if meth_name == "initialize_copy" - class_name = @known_classes[var_name] || var_name - class_obj = find_class(var_name, class_name) + handle_method(type, var_name, meth_name, meth_body, param_count) + end + + @body.scan(/rb_define_global_function\( + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, + \s*(-?\w+)\s*\)/xm) do #" + |meth_name, meth_body, param_count| - if class_obj - if meth_name == "initialize" - meth_name = "new" - type = "singleton_method" - end - meth_obj = AnyMethod.new("", meth_name) - meth_obj.singleton = type == "singleton_method" - - p_count = (Integer(param_count) rescue -1) - - if p_count < 0 - meth_obj.params = "(...)" - elsif p_count == 0 - meth_obj.params = "()" - else - meth_obj.params = "(" + - (1..p_count).map{|i| "p#{i}"}.join(", ") + - ")" - end - - find_body(meth_body, meth_obj) - class_obj.add_method(meth_obj) + handle_method("method", "rb_mKernel", meth_name, meth_body, param_count) + end + + @body.scan(/define_filetest_function\( + \s*"([^"]+)", + \s*(?:RUBY_METHOD_FUNC\(|VALUEFUNC\()?(\w+)\)?, + \s*(-?\w+)\s*\)/xm) do #" + |meth_name, meth_body, param_count| + + handle_method("method", "rb_mFileTest", meth_name, meth_body, param_count) + handle_method("singleton_method", "rb_cFile", meth_name, meth_body, param_count) + end + end + + + def handle_method(type, var_name, meth_name, meth_body, param_count) + class_name = @known_classes[var_name] || var_name + class_obj = find_class(var_name, class_name) + + if class_obj + if meth_name == "initialize" + meth_name = "new" + type = "singleton_method" end + meth_obj = AnyMethod.new("", meth_name) + meth_obj.singleton = type == "singleton_method" + + p_count = (Integer(param_count) rescue -1) + + if p_count < 0 + meth_obj.params = "(...)" + elsif p_count == 0 + meth_obj.params = "()" + else + meth_obj.params = "(" + + (1..p_count).map{|i| "p#{i}"}.join(", ") + + ")" + end + + find_body(meth_body, meth_obj) + class_obj.add_method(meth_obj) end end @@ -331,14 +356,14 @@ module RDoc end def find_class(raw_name, name) - unless @classes[name] + unless @classes[raw_name] if raw_name =~ /^rb_m/ - @classes[name] = @top_level.add_module(NormalModule, name) + @classes[raw_name] = @top_level.add_module(NormalModule, name) else - @classes[name] = @top_level.add_class(NormalClass, name, nil) + @classes[raw_name] = @top_level.add_class(NormalClass, name, nil) end end - @classes[name] + @classes[raw_name] end end diff --git a/lib/rdoc/ri/ri_descriptions.rb b/lib/rdoc/ri/ri_descriptions.rb index 9e280abf94..9bd5c2d13b 100644 --- a/lib/rdoc/ri/ri_descriptions.rb +++ b/lib/rdoc/ri/ri_descriptions.rb @@ -76,13 +76,12 @@ module RI end end - class ClassDescription < Description + class ModuleDescription < Description attr_accessor :class_methods attr_accessor :instance_methods attr_accessor :attributes attr_accessor :constants - attr_accessor :superclass attr_accessor :includes # merge in another class desscription into this one @@ -92,6 +91,13 @@ module RI merge(@attributes, old.attributes) merge(@constants, old.constants) merge(@includes, old.includes) + if @comment.nil? || @comment.empty? + @comment = old.comment + end + end + + def display_name + "Module" end private @@ -104,6 +110,15 @@ module RI end end + class ClassDescription < ModuleDescription + attr_accessor :superclass + + def display_name + "Class" + end + end + + class MethodDescription < Description attr_accessor :is_class_method diff --git a/lib/rdoc/ri/ri_formatter.rb b/lib/rdoc/ri/ri_formatter.rb index 1e70529bfe..b3024d4c6c 100644 --- a/lib/rdoc/ri/ri_formatter.rb +++ b/lib/rdoc/ri/ri_formatter.rb @@ -1,11 +1,16 @@ module RI - class RiFormatter + class TextFormatter + + def TextFormatter.create(options, indent) + new(options, indent) + end attr_reader :indent - def initialize(width, indent) - @width = width - @indent = indent + def initialize(options, indent) + @options = options + @width = options.width + @indent = indent end @@ -23,7 +28,7 @@ module RI def wrap(txt, prefix=@indent, linelen=@width) return unless txt && !txt.empty? - work = txt.dup + work = conv_markup(txt) textLen = linelen - prefix.length patt = Regexp.new("^(.{0,#{textLen}})[ \n]") next_prefix = prefix.tr("^ ", " ") @@ -53,9 +58,6 @@ module RI # convert HTML entities back to ASCII def conv_html(txt) txt. - gsub(%r{<tt>(.*?)</tt>}) { "+#$1+" } . - gsub(%r{<b>(.*?)</b>}) { "*#$1*" } . - gsub(%r{<em>(.*?)</em>}) { "_#$1_" } . gsub(/>/, '>'). gsub(/</, '<'). gsub(/"/, '"'). @@ -63,6 +65,15 @@ module RI end + # convert markup into display form + def conv_markup(txt) + txt. + gsub(%r{<tt>(.*?)</tt>}) { "+#$1+" } . + gsub(%r{<code>(.*?)</code>}) { "+#$1+" } . + gsub(%r{<b>(.*?)</b>}) { "*#$1*" } . + gsub(%r{<em>(.*?)</em>}) { "_#$1_" } + end + ###################################################################### def display_list(list) @@ -167,4 +178,7 @@ module RI end end end + end + + @@ -476,6 +476,24 @@ true_xor(obj, obj2) return RTEST(obj2)?Qfalse:Qtrue; } + +/* + * Document-class: FalseClass + * + * The global value <code>false</code> is the only instance of class + * <code>FalseClass</code> and represents a logically false value in + * boolean expressions. The class provides operators allowing + * <code>false</code> to participate correctly in logical expressions. + * + */ + +/* + * call-seq: + * false.to_s => "false" + * + * 'nuf said... + */ + static VALUE false_to_s(obj) VALUE obj; @@ -483,6 +501,15 @@ false_to_s(obj) return rb_str_new2("false"); } +/* + * call-seq: + * false & obj => false + * + * And---Returns <code>false</code>. <i>obj</i> is always + * evaluated as it is the argument to a method call---there is no + * short-circuit evaluation in this case. + */ + static VALUE false_and(obj, obj2) VALUE obj, obj2; @@ -490,6 +517,15 @@ false_and(obj, obj2) return Qfalse; } + +/* + * call-seq: + * false | obj => true or false + * + * Or---Returns <code>false</code> if <i>obj</i> is + * <code>nil</code> or <code>false</code>; <code>true</code> otherwise. + */ + static VALUE false_or(obj, obj2) VALUE obj, obj2; @@ -497,6 +533,18 @@ false_or(obj, obj2) return RTEST(obj2)?Qtrue:Qfalse; } + + +/* + * call-seq: + * false ^ obj => true or false + * + * Exclusive Or---If <i>obj</i> is <code>nil</code> or + * <code>false</code>, returns <code>false</code>; otherwise, returns + * <code>true</code>. + * + */ + static VALUE false_xor(obj, obj2) VALUE obj, obj2; |