Issue with Dir.glob documentation
From:
Austin Ziegler <halostatue@...>
Date:
2004-08-08 15:00:59 UTC
List:
ruby-core #3263
I noticed this because I'm working on some stuff and needed to do an
"ri Dir.[]", which of course led me to "ri Dir.glob". Dir.glob is,
unfortunately, incomplete, in that it doesn't talk about the recursive
("**") globbing capabilities of Dir at all.
All of my Ruby projects (and a few other things that aren't yet there)
are in "C:\home\Projects". If I do, from this directory:
a = Dir["**/*.rb"]
b = Dir["**/lib"]
c = Dir["**/lib/**/*.rb"]
d = Dir["**/lib/*.rb"]
a.size # => 823
b.size # => 39
c.size # => 437
d.size # => 19
a[0..2] # => ["diff/install.rb", "diff/lib/diff/lcs.rb",
"diff/lib/diff/lcs/array.rb"]
b[0..2] # => ["diff/lib", "diff/[sources]/Text-Diff-0.35/lib",
"diff/[sources]/Text-ParagaphDiff/lib"]
c[0..2] # => ["diff/lib/diff/lcs.rb",
"diff/lib/diff/lcs/array.rb",
"diff/lib/diff/lcs/block.rb"]
d[0..2] # => ["pdf-writer/lib/pdf.rb",
"pdf-writer/[sources]/lib/pdf.rb",
"pdf-writer/[sources]/ruby-pdf2/lib/pdf.rb"]
I'm attaching a documentation patch for dir.c (from the stable
snapshot) that would include this information. It also completes the
File.fnmatch and Dir.glob documentation to include the allowed
patterns. Note as well that the {p,q} form for File.fnmatch is not
implemented on either 1.8.2 or 1.9.0, but it is implemented for
Dir.glob.
It would be good to see this in Ruby 1.8.2.
Dave, I know that content changes are closed for pickaxe2, but this
may be of value in any case, and I hope you can manage to put this in.
-austin
--
Austin Ziegler * halostatue@gmail.com
* Alternate: austin@halostatue.ca
Attachments (1)
dir.c.diff
(7.15 KB, text/x-diff)
--- dir.c.old 2004-07-17 14:24:16 Eastern Daylight Time
+++ dir.c 2004-08-08 10:57:17 Eastern Daylight Time
@@ -1252,18 +1252,59 @@
* Returns the filenames found by expanding the pattern given in
* <i>string</i>, either as an <i>array</i> or as parameters to the
* block. Note that this pattern is not a regexp (it's closer to a
- * shell glob). See <code>File::fnmatch</code> for
- * details of file name matching and the meaning of the <i>flags</i>
- * parameter.
+ * shell glob). See <code>File::fnmatch</code> for the meaning of the
+ * <i>flags</i> parameter. The pattern may be character literals or
+ * one of the metapatterns below:
*
+ * <code>*</code>:: Matches any file. Can be restricted by
+ * other values in the glob. <code>*</code>
+ * will match all files; <code>c*</code> will
+ * match all files beginning with
+ * <code>c</code>; <code>*c</code> will match
+ * all files ending with <code>c</code>; and
+ * <code>*c*</code> will match all files that
+ * have <code>c</code> in them (including at
+ * the beginning or end). Equivalent to
+ * <code>/ .* /x</code> in regexp.
+ * <code>**</code>:: Matches directories recursively.
+ * <code>?</code>:: Matches any one character. Equivalent to
+ * <code>/.{1}/</code> in regexp.
+ * <code>[set]</code>:: Matches any one character in +set+.
+ * Behaves exactly like character sets in
+ * Regexp, including set negation
+ * (<code>[^a-z]</code>).
+ * <code>{p,q}</code>:: Matches either literal <code>p</code> or
+ * literal <code>q</code>. Matching literals
+ * may be more than one character in length.
+ * More than two literals may be specified.
+ * Equivalent to pattern alternation in
+ * regexp.
+ * <code>\</code>:: Escapes the next metacharacter.
+ *
* Dir["config.?"] #=> ["config.h"]
* Dir.glob("config.?") #=> ["config.h"]
* Dir.glob("*.[a-z][a-z]") #=> ["main.rb"]
* Dir.glob("*.[^r]*") #=> ["config.h"]
* Dir.glob("*.{rb,h}") #=> ["main.rb", "config.h"]
* Dir.glob("*") #=> ["config.h", "main.rb"]
- * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h", "main.rb"]
+ * Dir.glob("*", File::FNM_DOTMATCH) #=> [".", "..", "config.h",
+ * "main.rb"]
+ * Dir.glob("**.rb") #=> []
*
+ * rbfiles = File.join("**", "*.rb")
+ * Dir.glob(rbfiles) #=> ["main.rb",
+ * "lib/song.rb",
+ * "lib/song/karaoke.rb"]
+ * libdirs = File.join("**", "lib")
+ * Dir.glob(libdirs) #=> ["lib"]
+ *
+ * librbfiles = File.join("**", "lib", "**", "*.rb")
+ * Dir.glob(librbfiles) #=> ["lib/song.rb",
+ * "lib/song/karaoke.rb"]
+ *
+ * librbfiles = File.join("**", "lib", "*.rb")
+ * Dir.glob(librbfiles) #=> ["lib/song.rb"]
+ *
*/
static VALUE
dir_s_glob(argc, argv, obj)
@@ -1338,28 +1379,54 @@
*
* Returns true if <i>path</i> matches against <i>pattern</i> The
* pattern is not a regular expression; instead it follows rules
- * similar to shell filename globbing. It may contain the following
- * metacharacters:
+ * similar to shell filename globbing. The pattern may be character
+ * literals or one of the metapatterns below:
*
- * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code> parameters.
- * The same glob pattern and flags are used by <code>Dir::glob</code>.
+ * <code>*</code>:: Matches any file. Can be restricted by
+ * other values in the glob. <code>*</code>
+ * will match all files; <code>c*</code> will
+ * match all files beginning with
+ * <code>c</code>; <code>*c</code> will match
+ * all files ending with <code>c</code>; and
+ * <code>*c*</code> will match all files that
+ * have <code>c</code> in them (including at
+ * the beginning or end). Equivalent to
+ * <code>/ .* /x</code> in regexp.
+ * <code>**</code>:: Matches directories recursively or files
+ * expansively.
+ * <code>?</code>:: Matches any one character. Equivalent to
+ * <code>/.{1}/</code> in regexp.
+ * <code>[set]</code>:: Matches any one character in +set+.
+ * Behaves exactly like character sets in
+ * Regexp, including set negation
+ * (<code>[^a-z]</code>).
+ * <code>\</code>:: Escapes the next metacharacter.
*
+ * <i>flags</i> is a bitwise OR of the <code>FNM_xxx</code>
+ * parameters. The same glob pattern and flags are used by
+ * <code>Dir::glob</code>.
+ *
* File.fnmatch('cat', 'cat') #=> true
* File.fnmatch('cat', 'category') #=> false
- * File.fnmatch('c{at,ub}s', 'cats') #=> false
- * File.fnmatch('c{at,ub}s', 'cubs') #=> false
- * File.fnmatch('c{at,ub}s', 'cat') #=> false
*
* File.fnmatch('c?t', 'cat') #=> true
* File.fnmatch('c\?t', 'cat') #=> false
* File.fnmatch('c??t', 'cat') #=> false
* File.fnmatch('c*', 'cats') #=> true
- * File.fnmatch('c/ * FIXME * /t', 'c/a/b/c/t') #=> true
+ * File.fnmatch('c/ * FIXME * /t', 'c/a/b/c/t') #=> true
* File.fnmatch('c*t', 'cat') #=> true
* File.fnmatch('c\at', 'cat') #=> true
* File.fnmatch('c\at', 'cat', File::FNM_NOESCAPE) #=> false
* File.fnmatch('a?b', 'a/b') #=> true
* File.fnmatch('a?b', 'a/b', File::FNM_PATHNAME) #=> false
+ *
+ * rbfiles = File.join("**", "*.rb")
+ * File.fnmatch(rbfiles, 'main.rb') #=> false
+ * File.fnmatch(rbfiles, './main.rb') #=> false
+ * File.fnmatch(rbfiles, 'lib/song.rb') #=> true
+ * File.fnmatch('**.rb', 'main.rb') #=> true
+ * File.fnmatch('**.rb', './main.rb') #=> false
+ * File.fnmatch('**.rb', 'lib/song.rb') #=> true
*
* File.fnmatch('*', '.profile') #=> false
* File.fnmatch('*', '.profile', File::FNM_DOTMATCH) #=> true