summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog5
-rw-r--r--NEWS5
-rw-r--r--dir.c29
-rw-r--r--test/ruby/envutil.rb7
-rw-r--r--test/ruby/test_fnmatch.rb6
5 files changed, 48 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 7212162947..bf648cf9f5 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+Sun Nov 4 10:19:03 2012 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * dir.c (file_s_fnmatch): match with expanding braces if FNM_EXTGLOB
+ is set. [ruby-core:40037] [Feature #5422]
+
Sat Nov 3 23:38:15 2012 Tadayoshi Funaba <tadf@dotrb.org>
* complex.c: modified doc.
diff --git a/NEWS b/NEWS
index 17b44b18a2..4190fe7a32 100644
--- a/NEWS
+++ b/NEWS
@@ -31,6 +31,11 @@ with all sufficient information, see the ChangeLog file.
* aliased method:
* ENV.to_h is a new alias for ENV.to_hash
+ * File:
+ * extended method:
+ * File.fnmatch? now expands braces in the pattern if
+ File::FNM_EXTGLOB option is given.
+
* Hash
* added method:
* added Hash#to_h as explicit conversion method, like Array#to_a.
diff --git a/dir.c b/dir.c
index 11e3028813..d4b3dd3692 100644
--- a/dir.c
+++ b/dir.c
@@ -85,6 +85,7 @@ char *strchr(char*,char);
#define FNM_PATHNAME 0x02
#define FNM_DOTMATCH 0x04
#define FNM_CASEFOLD 0x08
+#define FNM_EXTGLOB 0x10
#if CASEFOLD_FILESYSTEM
#define FNM_SYSCASE FNM_CASEFOLD
#else
@@ -1912,6 +1913,15 @@ dir_entries(int argc, VALUE *argv, VALUE io)
return rb_ensure(rb_Array, dir, dir_close, dir);
}
+static int
+fnmatch_brace(const char *pattern, VALUE val, void *enc)
+{
+ struct brace_args *arg = (struct brace_args *)val;
+ VALUE path = arg->value;
+
+ return (fnmatch(pattern, enc, RSTRING_PTR(path), arg->flags) == 0);
+}
+
/*
* call-seq:
* File.fnmatch( pattern, path, [flags] ) -> (true or false)
@@ -2008,9 +2018,21 @@ file_s_fnmatch(int argc, VALUE *argv, VALUE obj)
StringValue(pattern);
FilePathStringValue(path);
- if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
- flags) == 0)
- return Qtrue;
+ if (flags & FNM_EXTGLOB) {
+ struct brace_args args;
+
+ args.value = path;
+ args.flags = flags;
+ if (ruby_brace_expand(RSTRING_PTR(pattern), flags, fnmatch_brace,
+ (VALUE)&args, rb_enc_get(pattern)) > 0)
+ return Qtrue;
+ }
+ else {
+ if (fnmatch(RSTRING_PTR(pattern), rb_enc_get(pattern), RSTRING_PTR(path),
+ flags) == 0)
+ return Qtrue;
+ }
+ RB_GC_GUARD(pattern);
return Qfalse;
}
@@ -2111,5 +2133,6 @@ Init_Dir(void)
rb_file_const("FNM_PATHNAME", INT2FIX(FNM_PATHNAME));
rb_file_const("FNM_DOTMATCH", INT2FIX(FNM_DOTMATCH));
rb_file_const("FNM_CASEFOLD", INT2FIX(FNM_CASEFOLD));
+ rb_file_const("FNM_EXTGLOB", INT2FIX(FNM_EXTGLOB));
rb_file_const("FNM_SYSCASE", INT2FIX(FNM_SYSCASE));
}
diff --git a/test/ruby/envutil.rb b/test/ruby/envutil.rb
index 3e04f55c0c..780196a438 100644
--- a/test/ruby/envutil.rb
+++ b/test/ruby/envutil.rb
@@ -229,7 +229,7 @@ module Test
AssertFile
end
- class << (AssertFile = Object.new)
+ class << (AssertFile = Struct.new(:message).new)
include Assertions
def assert_file_predicate(predicate, *args)
if /\Anot_/ =~ predicate
@@ -241,9 +241,14 @@ module Test
mesg = "Expected file " << args.shift.inspect
mesg << mu_pp(args) unless args.empty?
mesg << "#{neg} to be #{predicate}"
+ mesg << " #{message}" if message
assert(result, mesg)
end
alias method_missing assert_file_predicate
+
+ def for(message)
+ clone.tap {|a| a.message = message}
+ end
end
end
end
diff --git a/test/ruby/test_fnmatch.rb b/test/ruby/test_fnmatch.rb
index e5f5ba6a4f..d186638a7b 100644
--- a/test/ruby/test_fnmatch.rb
+++ b/test/ruby/test_fnmatch.rb
@@ -1,4 +1,5 @@
require 'test/unit'
+require_relative 'envutil'
class TestFnmatch < Test::Unit::TestCase
@@ -103,4 +104,9 @@ class TestFnmatch < Test::Unit::TestCase
assert(File.fnmatch('**/foo', 'c:/root/foo', File::FNM_PATHNAME))
end
+ def test_extglob
+ feature5422 = '[ruby-core:40037]'
+ assert_file.for(feature5422).not_fnmatch?( "{.g,t}*", ".gem")
+ assert_file.for(feature5422).fnmatch?("{.g,t}*", ".gem", File::FNM_EXTGLOB)
+ end
end