Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: rubinius/rubinius
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: 9fec1fd68336
Choose a base ref
...
head repository: rubinius/rubinius
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: d95487ca490e
Choose a head ref
  • 2 commits
  • 2 files changed
  • 1 contributor

Commits on Nov 6, 2014

  1. Copy the full SHA
    cc3d506 View commit details
  2. Copy the full SHA
    d95487c View commit details
Showing with 90 additions and 1 deletion.
  1. +86 −1 kernel/common/file.rb
  2. +4 −0 spec/ruby/core/file/shared/fnmatch.rb
87 changes: 86 additions & 1 deletion kernel/common/file.rb
Original file line number Diff line number Diff line change
@@ -596,12 +596,97 @@ def self.file?(path)
# File.fnmatch(pattern, 'c:/a/b/c/foo', File::FNM_PATHNAME) #=> true
# File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME) #=> false
# File.fnmatch(pattern, 'a/.b/c/foo', File::FNM_PATHNAME | File::FNM_DOTMATCH) #=> true
#def self.fnmatch(pattern, path, flags=0)
#pattern = StringValue(pattern)
#path = Rubinius::Type.coerce_to_path(path)
#flags = Rubinius::Type.coerce_to(flags, Fixnum, :to_int)

#super pattern, path, flags
#end

def self.braces(pattern, flags=0, patterns=[])
escape = (flags & FNM_NOESCAPE) == 0

rbrace = nil
lbrace = nil

# Do a quick search for a { to start the search better
i = pattern.index("{")

if i
nest = 0

while i < pattern.size
char = pattern[i]

if char == "{"
lbrace = i if nest == 0
nest += 1
end

if char == "}"
nest -= 1
end

if nest == 0
rbrace = i
break
end

if char == "\\" and escape
i += 1
end

i += 1
end
end

# There was a full {} expression detected, expand each part of it
# recursively.
if lbrace and rbrace
pos = lbrace
front = pattern[0...lbrace]
back = pattern[(rbrace + 1)..-1]

while pos < rbrace
nest = 0
pos += 1
last = pos

while pos < rbrace and not (pattern[pos] == "," and nest == 0)
nest += 1 if pattern[pos] == "{"
nest -= 1 if pattern[pos] == "}"

if pattern[pos] == "\\" and escape
pos += 1
break if pos == rbrace
end

pos += 1
end

brace_pattern = "#{front}#{pattern[last...pos]}#{back}"
patterns << brace_pattern

braces(brace_pattern, flags, patterns)
end
end
patterns
end

def self.fnmatch(pattern, path, flags=0)
pattern = StringValue(pattern)
path = Rubinius::Type.coerce_to_path(path)
flags = Rubinius::Type.coerce_to(flags, Fixnum, :to_int)

super pattern, path, flags
if (flags & FNM_EXTGLOB) != 0
patterns = braces(pattern, flags)
return false if patterns.empty?

patterns.any? { |p| super(p, path, flags) }
else
super pattern, path, flags
end
end

##
4 changes: 4 additions & 0 deletions spec/ruby/core/file/shared/fnmatch.rb
Original file line number Diff line number Diff line change
@@ -16,6 +16,10 @@
File.send(@method, 'c{at,ub}s', 'cats', File::FNM_EXTGLOB).should == true
end

it "doesn't match an extra } when File::FNM_EXTGLOB is passed" do
File.send(@method, 'c{at,ub}}s', 'cats', File::FNM_EXTGLOB).should == false
end

it "matches a single character for each ? character" do
File.send(@method, 'c?t', 'cat').should == true
File.send(@method, 'c??t', 'cat').should == false