mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Dir.glob base option
* dir.c (dir_s_aref, dir_s_glob): add new optional keyword argument, `base`. [Feature#13056] git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@58858 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
2ba68008b5
commit
52419a6e10
3 changed files with 67 additions and 21 deletions
5
NEWS
5
NEWS
|
@ -25,6 +25,11 @@ with all sufficient information, see the ChangeLog file or Redmine
|
||||||
* Array#append [Feature #12746]
|
* Array#append [Feature #12746]
|
||||||
* Array#prepend [Feature #12746]
|
* Array#prepend [Feature #12746]
|
||||||
|
|
||||||
|
* Dir
|
||||||
|
|
||||||
|
* Dir.glob provides new optional keyword argument, :base.
|
||||||
|
[Feature#13056]
|
||||||
|
|
||||||
* Integer
|
* Integer
|
||||||
|
|
||||||
* Integer.sqrt [Feature #13219]
|
* Integer.sqrt [Feature #13219]
|
||||||
|
|
77
dir.c
77
dir.c
|
@ -2082,7 +2082,7 @@ glob_helper(
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
ruby_glob0(const char *path, int flags,
|
ruby_glob0(const char *path, const char *base, int flags,
|
||||||
const ruby_glob_funcs_t *funcs, VALUE arg,
|
const ruby_glob_funcs_t *funcs, VALUE arg,
|
||||||
rb_encoding *enc)
|
rb_encoding *enc)
|
||||||
{
|
{
|
||||||
|
@ -2090,7 +2090,7 @@ ruby_glob0(const char *path, int flags,
|
||||||
const char *root, *start;
|
const char *root, *start;
|
||||||
char *buf;
|
char *buf;
|
||||||
size_t n;
|
size_t n;
|
||||||
int status;
|
int status, dirsep = FALSE;
|
||||||
|
|
||||||
start = root = path;
|
start = root = path;
|
||||||
flags |= FNM_SYSCASE;
|
flags |= FNM_SYSCASE;
|
||||||
|
@ -2101,6 +2101,11 @@ ruby_glob0(const char *path, int flags,
|
||||||
if (*root == '/') root++;
|
if (*root == '/') root++;
|
||||||
|
|
||||||
n = root - start;
|
n = root - start;
|
||||||
|
if (!n && base) {
|
||||||
|
n = strlen(base);
|
||||||
|
start = base;
|
||||||
|
dirsep = TRUE;
|
||||||
|
}
|
||||||
buf = GLOB_ALLOC_N(char, n + 1);
|
buf = GLOB_ALLOC_N(char, n + 1);
|
||||||
if (!buf) return -1;
|
if (!buf) return -1;
|
||||||
MEMCPY(buf, start, char, n);
|
MEMCPY(buf, start, char, n);
|
||||||
|
@ -2111,7 +2116,7 @@ ruby_glob0(const char *path, int flags,
|
||||||
GLOB_FREE(buf);
|
GLOB_FREE(buf);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
status = glob_helper(buf, n, 0, path_unknown, &list, &list + 1,
|
status = glob_helper(buf, n, dirsep, path_unknown, &list, &list + 1,
|
||||||
flags, funcs, arg, enc);
|
flags, funcs, arg, enc);
|
||||||
glob_free_pattern(list);
|
glob_free_pattern(list);
|
||||||
GLOB_FREE(buf);
|
GLOB_FREE(buf);
|
||||||
|
@ -2125,7 +2130,7 @@ ruby_glob(const char *path, int flags, ruby_glob_func *func, VALUE arg)
|
||||||
ruby_glob_funcs_t funcs;
|
ruby_glob_funcs_t funcs;
|
||||||
funcs.match = func;
|
funcs.match = func;
|
||||||
funcs.error = NULL;
|
funcs.error = NULL;
|
||||||
return ruby_glob0(path, flags & ~GLOB_VERBOSE,
|
return ruby_glob0(path, 0, flags & ~GLOB_VERBOSE,
|
||||||
&funcs, arg, rb_ascii8bit_encoding());
|
&funcs, arg, rb_ascii8bit_encoding());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2154,7 +2159,7 @@ rb_glob(const char *path, void (*func)(const char *, VALUE, void *), VALUE arg)
|
||||||
args.value = arg;
|
args.value = arg;
|
||||||
args.enc = rb_ascii8bit_encoding();
|
args.enc = rb_ascii8bit_encoding();
|
||||||
|
|
||||||
status = ruby_glob0(path, GLOB_VERBOSE, &rb_glob_funcs,
|
status = ruby_glob0(path, 0, GLOB_VERBOSE, &rb_glob_funcs,
|
||||||
(VALUE)&args, args.enc);
|
(VALUE)&args, args.enc);
|
||||||
if (status) GLOB_JUMP_TAG(status);
|
if (status) GLOB_JUMP_TAG(status);
|
||||||
}
|
}
|
||||||
|
@ -2243,7 +2248,7 @@ glob_brace(const char *path, VALUE val, void *enc)
|
||||||
{
|
{
|
||||||
struct brace_args *arg = (struct brace_args *)val;
|
struct brace_args *arg = (struct brace_args *)val;
|
||||||
|
|
||||||
return ruby_glob0(path, arg->flags, &arg->funcs, arg->value, enc);
|
return ruby_glob0(path, 0, arg->flags, &arg->funcs, arg->value, enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
|
@ -2267,6 +2272,7 @@ ruby_brace_glob(const char *str, int flags, ruby_glob_func *func, VALUE arg)
|
||||||
|
|
||||||
struct push_glob_args {
|
struct push_glob_args {
|
||||||
struct glob_args glob;
|
struct glob_args glob;
|
||||||
|
const char *base;
|
||||||
int flags;
|
int flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -2275,12 +2281,12 @@ push_caller(const char *path, VALUE val, void *enc)
|
||||||
{
|
{
|
||||||
struct push_glob_args *arg = (struct push_glob_args *)val;
|
struct push_glob_args *arg = (struct push_glob_args *)val;
|
||||||
|
|
||||||
return ruby_glob0(path, arg->flags, &rb_glob_funcs,
|
return ruby_glob0(path, arg->base, arg->flags, &rb_glob_funcs,
|
||||||
(VALUE)&arg->glob, enc);
|
(VALUE)&arg->glob, enc);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
push_glob(VALUE ary, VALUE str, int flags)
|
push_glob(VALUE ary, VALUE str, VALUE base, int flags)
|
||||||
{
|
{
|
||||||
struct push_glob_args args;
|
struct push_glob_args args;
|
||||||
rb_encoding *enc = rb_enc_get(str);
|
rb_encoding *enc = rb_enc_get(str);
|
||||||
|
@ -2296,7 +2302,11 @@ push_glob(VALUE ary, VALUE str, int flags)
|
||||||
args.glob.func = push_pattern;
|
args.glob.func = push_pattern;
|
||||||
args.glob.value = ary;
|
args.glob.value = ary;
|
||||||
args.glob.enc = enc;
|
args.glob.enc = enc;
|
||||||
|
args.base = 0;
|
||||||
args.flags = flags;
|
args.flags = flags;
|
||||||
|
if (!NIL_P(base) && rb_enc_check(str, base)) {
|
||||||
|
args.base = RSTRING_PTR(base);
|
||||||
|
}
|
||||||
#if defined _WIN32 || defined __APPLE__
|
#if defined _WIN32 || defined __APPLE__
|
||||||
enc = rb_utf8_encoding();
|
enc = rb_utf8_encoding();
|
||||||
#endif
|
#endif
|
||||||
|
@ -2307,7 +2317,7 @@ push_glob(VALUE ary, VALUE str, int flags)
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
|
rb_push_glob(VALUE str, VALUE base, int flags) /* '\0' is delimiter */
|
||||||
{
|
{
|
||||||
long offset = 0;
|
long offset = 0;
|
||||||
VALUE ary;
|
VALUE ary;
|
||||||
|
@ -2320,7 +2330,7 @@ rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
|
||||||
int status;
|
int status;
|
||||||
p = RSTRING_PTR(str) + offset;
|
p = RSTRING_PTR(str) + offset;
|
||||||
status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
|
status = push_glob(ary, rb_enc_str_new(p, strlen(p), rb_enc_get(str)),
|
||||||
flags);
|
base, flags);
|
||||||
if (status) GLOB_JUMP_TAG(status);
|
if (status) GLOB_JUMP_TAG(status);
|
||||||
if (offset >= RSTRING_LEN(str)) break;
|
if (offset >= RSTRING_LEN(str)) break;
|
||||||
p += strlen(p) + 1;
|
p += strlen(p) + 1;
|
||||||
|
@ -2334,7 +2344,7 @@ rb_push_glob(VALUE str, int flags) /* '\0' is delimiter */
|
||||||
}
|
}
|
||||||
|
|
||||||
static VALUE
|
static VALUE
|
||||||
dir_globs(long argc, const VALUE *argv, int flags)
|
dir_globs(long argc, const VALUE *argv, VALUE base, int flags)
|
||||||
{
|
{
|
||||||
VALUE ary = rb_ary_new();
|
VALUE ary = rb_ary_new();
|
||||||
long i;
|
long i;
|
||||||
|
@ -2343,16 +2353,36 @@ dir_globs(long argc, const VALUE *argv, int flags)
|
||||||
int status;
|
int status;
|
||||||
VALUE str = argv[i];
|
VALUE str = argv[i];
|
||||||
GlobPathValue(str, TRUE);
|
GlobPathValue(str, TRUE);
|
||||||
status = push_glob(ary, str, flags);
|
status = push_glob(ary, str, base, flags);
|
||||||
if (status) GLOB_JUMP_TAG(status);
|
if (status) GLOB_JUMP_TAG(status);
|
||||||
}
|
}
|
||||||
|
|
||||||
return ary;
|
return ary;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
dir_glob_options(VALUE opt, VALUE *base, int *flags)
|
||||||
|
{
|
||||||
|
ID kw[2];
|
||||||
|
VALUE args[2];
|
||||||
|
kw[0] = rb_intern("base");
|
||||||
|
if (flags) kw[1] = rb_intern("flags");
|
||||||
|
rb_get_kwargs(opt, kw, 0, flags ? 2 : 1, args);
|
||||||
|
if (args[0] == Qundef) {
|
||||||
|
*base = Qnil;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
GlobPathValue(args[0], TRUE);
|
||||||
|
*base = args[0];
|
||||||
|
}
|
||||||
|
if (flags && args[1] != Qundef) {
|
||||||
|
*flags = NUM2INT(args[1]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* Dir[ string [, string ...] ] -> array
|
* Dir[ string [, string ...], [base: path] ] -> array
|
||||||
*
|
*
|
||||||
* Equivalent to calling
|
* Equivalent to calling
|
||||||
* <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
|
* <code>Dir.glob([</code><i>string,...</i><code>],0)</code>.
|
||||||
|
@ -2361,16 +2391,19 @@ dir_globs(long argc, const VALUE *argv, int flags)
|
||||||
static VALUE
|
static VALUE
|
||||||
dir_s_aref(int argc, VALUE *argv, VALUE obj)
|
dir_s_aref(int argc, VALUE *argv, VALUE obj)
|
||||||
{
|
{
|
||||||
|
VALUE opts, base;
|
||||||
|
argc = rb_scan_args(argc, argv, "*:", NULL, &opts);
|
||||||
|
dir_glob_options(opts, &base, NULL);
|
||||||
if (argc == 1) {
|
if (argc == 1) {
|
||||||
return rb_push_glob(argv[0], 0);
|
return rb_push_glob(argv[0], base, 0);
|
||||||
}
|
}
|
||||||
return dir_globs(argc, argv, 0);
|
return dir_globs(argc, argv, base, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* call-seq:
|
* call-seq:
|
||||||
* Dir.glob( pattern, [flags] ) -> matches
|
* Dir.glob( pattern, [flags], [base: path] ) -> matches
|
||||||
* Dir.glob( pattern, [flags] ) { |filename| block } -> nil
|
* Dir.glob( pattern, [flags], [base: path] ) { |filename| block } -> nil
|
||||||
*
|
*
|
||||||
* Expands +pattern+, which is an Array of patterns or a pattern String, and
|
* Expands +pattern+, which is an Array of patterns or a pattern String, and
|
||||||
* returns the results as +matches+ or as arguments given to the block.
|
* returns the results as +matches+ or as arguments given to the block.
|
||||||
|
@ -2445,21 +2478,23 @@ dir_s_aref(int argc, VALUE *argv, VALUE obj)
|
||||||
static VALUE
|
static VALUE
|
||||||
dir_s_glob(int argc, VALUE *argv, VALUE obj)
|
dir_s_glob(int argc, VALUE *argv, VALUE obj)
|
||||||
{
|
{
|
||||||
VALUE str, rflags, ary;
|
VALUE str, rflags, ary, opts, base;
|
||||||
int flags;
|
int flags;
|
||||||
|
|
||||||
if (rb_scan_args(argc, argv, "11", &str, &rflags) == 2)
|
argc = rb_scan_args(argc, argv, "11:", &str, &rflags, &opts);
|
||||||
|
if (argc == 2)
|
||||||
flags = NUM2INT(rflags);
|
flags = NUM2INT(rflags);
|
||||||
else
|
else
|
||||||
flags = 0;
|
flags = 0;
|
||||||
|
dir_glob_options(opts, &base, &flags);
|
||||||
|
|
||||||
ary = rb_check_array_type(str);
|
ary = rb_check_array_type(str);
|
||||||
if (NIL_P(ary)) {
|
if (NIL_P(ary)) {
|
||||||
ary = rb_push_glob(str, flags);
|
ary = rb_push_glob(str, base, flags);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
VALUE v = ary;
|
VALUE v = ary;
|
||||||
ary = dir_globs(RARRAY_LEN(v), RARRAY_CONST_PTR(v), flags);
|
ary = dir_globs(RARRAY_LEN(v), RARRAY_CONST_PTR(v), base, flags);
|
||||||
RB_GC_GUARD(v);
|
RB_GC_GUARD(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -202,6 +202,12 @@ class TestDir < Test::Unit::TestCase
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def test_glob_base
|
||||||
|
files = %w[a/foo.c c/bar.c].map {|n| File.join(@root, n)}
|
||||||
|
files.each {|n| File.write(n, "")}
|
||||||
|
assert_equal(files, Dir.glob("*/*.c", base: @root))
|
||||||
|
end
|
||||||
|
|
||||||
def assert_entries(entries)
|
def assert_entries(entries)
|
||||||
entries.sort!
|
entries.sort!
|
||||||
assert_equal(%w(. ..) + ("a".."z").to_a, entries)
|
assert_equal(%w(. ..) + ("a".."z").to_a, entries)
|
||||||
|
|
Loading…
Add table
Reference in a new issue