ruby-changes:46743
From: nobu <ko1@a...>
Date: Tue, 23 May 2017 22:47:43 +0900 (JST)
Subject: [ruby-changes:46743] nobu:r58858 (trunk): Dir.glob base option
nobu 2017-05-23 22:47:36 +0900 (Tue, 23 May 2017) New Revision: 58858 https://svn.ruby-lang.org/cgi-bin/viewvc.cgi?view=revision&revision=58858 Log: Dir.glob base option * dir.c (dir_s_aref, dir_s_glob): add new optional keyword argument, `base`. [Feature#13056] Modified files: trunk/NEWS trunk/dir.c trunk/test/ruby/test_dir.rb Index: test/ruby/test_dir.rb =================================================================== --- test/ruby/test_dir.rb (revision 58857) +++ test/ruby/test_dir.rb (revision 58858) @@ -202,6 +202,12 @@ class TestDir < Test::Unit::TestCase https://github.com/ruby/ruby/blob/trunk/test/ruby/test_dir.rb#L202 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) entries.sort! assert_equal(%w(. ..) + ("a".."z").to_a, entries) Index: dir.c =================================================================== --- dir.c (revision 58857) +++ dir.c (revision 58858) @@ -2082,7 +2082,7 @@ glob_helper( https://github.com/ruby/ruby/blob/trunk/dir.c#L2082 } 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, rb_encoding *enc) { @@ -2090,7 +2090,7 @@ ruby_glob0(const char *path, int flags, https://github.com/ruby/ruby/blob/trunk/dir.c#L2090 const char *root, *start; char *buf; size_t n; - int status; + int status, dirsep = FALSE; start = root = path; flags |= FNM_SYSCASE; @@ -2101,6 +2101,11 @@ ruby_glob0(const char *path, int flags, https://github.com/ruby/ruby/blob/trunk/dir.c#L2101 if (*root == '/') root++; n = root - start; + if (!n && base) { + n = strlen(base); + start = base; + dirsep = TRUE; + } buf = GLOB_ALLOC_N(char, n + 1); if (!buf) return -1; MEMCPY(buf, start, char, n); @@ -2111,7 +2116,7 @@ ruby_glob0(const char *path, int flags, https://github.com/ruby/ruby/blob/trunk/dir.c#L2116 GLOB_FREE(buf); 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); glob_free_pattern(list); GLOB_FREE(buf); @@ -2125,7 +2130,7 @@ ruby_glob(const char *path, int flags, r https://github.com/ruby/ruby/blob/trunk/dir.c#L2130 ruby_glob_funcs_t funcs; funcs.match = func; funcs.error = NULL; - return ruby_glob0(path, flags & ~GLOB_VERBOSE, + return ruby_glob0(path, 0, flags & ~GLOB_VERBOSE, &funcs, arg, rb_ascii8bit_encoding()); } @@ -2154,7 +2159,7 @@ rb_glob(const char *path, void (*func)(c https://github.com/ruby/ruby/blob/trunk/dir.c#L2159 args.value = arg; 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); if (status) GLOB_JUMP_TAG(status); } @@ -2243,7 +2248,7 @@ glob_brace(const char *path, VALUE val, https://github.com/ruby/ruby/blob/trunk/dir.c#L2248 { 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 @@ -2267,6 +2272,7 @@ ruby_brace_glob(const char *str, int fla https://github.com/ruby/ruby/blob/trunk/dir.c#L2272 struct push_glob_args { struct glob_args glob; + const char *base; int flags; }; @@ -2275,12 +2281,12 @@ push_caller(const char *path, VALUE val, https://github.com/ruby/ruby/blob/trunk/dir.c#L2281 { 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); } 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; rb_encoding *enc = rb_enc_get(str); @@ -2296,7 +2302,11 @@ push_glob(VALUE ary, VALUE str, int flag https://github.com/ruby/ruby/blob/trunk/dir.c#L2302 args.glob.func = push_pattern; args.glob.value = ary; args.glob.enc = enc; + args.base = 0; args.flags = flags; + if (!NIL_P(base) && rb_enc_check(str, base)) { + args.base = RSTRING_PTR(base); + } #if defined _WIN32 || defined __APPLE__ enc = rb_utf8_encoding(); #endif @@ -2307,7 +2317,7 @@ push_glob(VALUE ary, VALUE str, int flag https://github.com/ruby/ruby/blob/trunk/dir.c#L2317 } 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; VALUE ary; @@ -2320,7 +2330,7 @@ rb_push_glob(VALUE str, int flags) /* '\ https://github.com/ruby/ruby/blob/trunk/dir.c#L2330 int status; p = RSTRING_PTR(str) + offset; 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 (offset >= RSTRING_LEN(str)) break; p += strlen(p) + 1; @@ -2334,7 +2344,7 @@ rb_push_glob(VALUE str, int flags) /* '\ https://github.com/ruby/ruby/blob/trunk/dir.c#L2344 } 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(); long i; @@ -2343,16 +2353,36 @@ dir_globs(long argc, const VALUE *argv, https://github.com/ruby/ruby/blob/trunk/dir.c#L2353 int status; VALUE str = argv[i]; GlobPathValue(str, TRUE); - status = push_glob(ary, str, flags); + status = push_glob(ary, str, base, flags); if (status) GLOB_JUMP_TAG(status); } 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: - * Dir[ string [, string ...] ] -> array + * Dir[ string [, string ...], [base: path] ] -> array * * Equivalent to calling * <code>Dir.glob([</code><i>string,...</i><code>],0)</code>. @@ -2361,16 +2391,19 @@ dir_globs(long argc, const VALUE *argv, https://github.com/ruby/ruby/blob/trunk/dir.c#L2391 static VALUE 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) { - 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: - * Dir.glob( pattern, [flags] ) -> matches - * Dir.glob( pattern, [flags] ) { |filename| block } -> nil + * Dir.glob( pattern, [flags], [base: path] ) -> matches + * Dir.glob( pattern, [flags], [base: path] ) { |filename| block } -> nil * * 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. @@ -2445,21 +2478,23 @@ dir_s_aref(int argc, VALUE *argv, VALUE https://github.com/ruby/ruby/blob/trunk/dir.c#L2478 static VALUE dir_s_glob(int argc, VALUE *argv, VALUE obj) { - VALUE str, rflags, ary; + VALUE str, rflags, ary, opts, base; 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); else flags = 0; + dir_glob_options(opts, &base, &flags); ary = rb_check_array_type(str); if (NIL_P(ary)) { - ary = rb_push_glob(str, flags); + ary = rb_push_glob(str, base, flags); } else { 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); } Index: NEWS =================================================================== --- NEWS (revision 58857) +++ NEWS (revision 58858) @@ -25,6 +25,11 @@ with all sufficient information, see the https://github.com/ruby/ruby/blob/trunk/NEWS#L25 * Array#append [Feature #12746] * Array#prepend [Feature #12746] +* Dir + + * Dir.glob provides new optional keyword argument, :base. + [Feature#13056] + * Integer * Integer.sqrt [Feature #13219] -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/