Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Merge pull request #298 from defunkt/fix-nested-glob-groups

Fix nested glob groups
  • Loading branch information...
commit a4cb885f4a0edfde63bfbb8f952e35b29581a450 2 parents 4cce640 + 2c690e7
@eventualbuddha eventualbuddha authored
View
28 lib/fakefs/file_system.rb
@@ -24,7 +24,10 @@ def find(path)
parts = path_parts(normalize_path(path))
return fs if parts.empty? # '/'
- entries = find_recurser(fs, parts).flatten
+ entries = Globber.expand(path).flat_map do |pattern|
+ parts = path_parts(normalize_path(pattern))
+ find_recurser(fs, parts).flatten
+ end
case entries.length
when 0 then nil
@@ -93,7 +96,7 @@ def chdir(dir, &blk)
end
def path_parts(path)
- drop_root(path.split(File::SEPARATOR)).reject(&:empty?)
+ Globber.path_components(path)
end
def normalize_path(path)
@@ -113,14 +116,6 @@ def current_dir
private
- def drop_root(path_parts)
- # we need to remove parts from root dir at least for windows and jruby
- return path_parts if path_parts.nil? || path_parts.empty?
- root = RealFile.expand_path('/').split(File::SEPARATOR).first
- path_parts.shift if path_parts.first == root
- path_parts
- end
-
def find_recurser(dir, parts)
return [] unless dir.respond_to? :[]
@@ -143,16 +138,9 @@ def find_recurser(dir, parts)
directories_under(dir)
end
else
- regex_body = pattern.gsub('.', '\.')
- .gsub('?', '.')
- .gsub('*', '.*')
- .gsub('(', '\(')
- .gsub(')', '\)')
- .gsub(/\{(.*?)\}/) do
- "(#{Regexp.last_match[1].gsub(',', '|')})"
- end
- .gsub(/\A\./, '(?!\.).')
- dir.matches(/\A#{regex_body}\Z/)
+ Globber.expand(pattern).flat_map do |subpattern|
+ dir.matches(Globber.regexp(subpattern))
+ end
end
if parts.empty? # we're done recursing
View
97 lib/fakefs/globber.rb
@@ -0,0 +1,97 @@
+module FakeFS
+ # Handles globbing for FakeFS.
+ module Globber
+ extend self
+
+ def expand(pattern)
+ return [pattern] if pattern[0] != '{' || pattern[-1] != '}'
+
+ part = ''
+ result = []
+
+ each_char_with_levels pattern, '{', '}' do |chr, level|
+ case level
+ when 0
+ case chr
+ when '{'
+ # noop
+ else
+ part << chr
+ end
+ when 1
+ case chr
+ when ','
+ result << part
+ part = ''
+ when '}'
+ # noop
+ else
+ part << chr
+ end
+ else
+ part << chr
+ end
+ end
+
+ result << part
+
+ result
+ end
+
+ def path_components(pattern)
+ part = ''
+ result = []
+
+ each_char_with_levels pattern, '{', '}' do |chr, level|
+ if level == 0 && chr == File::SEPARATOR
+ result << part
+ part = ''
+ else
+ part << chr
+ end
+ end
+
+ result << part
+
+ drop_root(result).reject(&:empty?)
+ end
+
+ def regexp(pattern)
+ regex_body = pattern.gsub('.', '\.')
+ .gsub('?', '.')
+ .gsub('*', '.*')
+ .gsub('(', '\(')
+ .gsub(')', '\)')
+ .gsub(/\{(.*?)\}/) do
+ "(#{Regexp.last_match[1].gsub(',', '|')})"
+ end
+ .gsub(/\A\./, '(?!\.).')
+ /\A#{regex_body}\Z/
+ end
+
+ private
+
+ def each_char_with_levels(string, level_start, level_end)
+ level = 0
+
+ string.each_char do |chr|
+ yield chr, level
+
+ case chr
+ when level_start
+ level += 1
+ when level_end
+ level -= 1
+ end
+ end
+ end
+
+ def drop_root(path_parts)
+ # we need to remove parts from root dir at least for windows and jruby
+ return path_parts if path_parts.nil? || path_parts.empty?
+ root = RealFile.expand_path('/').split(File::SEPARATOR).first
+ path_parts.shift if path_parts.first == root
+ path_parts
+ end
+ end
+end
View
1  lib/fakefs/safe.rb
@@ -9,5 +9,6 @@
require 'fakefs/file'
require 'fakefs/file_test'
require 'fakefs/dir'
+require 'fakefs/globber'
require 'fakefs/pathname' if RUBY_VERSION >= '1.9.3'
require 'fakefs/kernel'
View
3  test/fakefs_test.rb
@@ -1073,6 +1073,9 @@ def test_dir_globs_paths
assert_equal ['/path/bar', '/path/bar2'], Dir['/path/bar{2,}']
+ assert_equal ['/path/bar', '/path/foo'], Dir['{/nowhere,/path/{foo,bar}}']
+ assert_equal ['/path/bar', '/path/foo'], Dir['{/nowhere,/path/{foo,{bar,bar2/baz}}}']
+
Dir.chdir '/path' do
assert_equal ['foo'], Dir['foo']
end
View
28 test/globber_test.rb
@@ -0,0 +1,28 @@
+require 'test_helper'
+
+# Globber test class
+class GlobberTest < Minitest::Test
+ def test_expand_without_brace_groups_returns_single_entry
+ assert_equal ['*.rb'], FakeFS::Globber.expand('*.rb')
+ end
+
+ def test_expand_with_brace_group_with_one_entry_returns_single_entry
+ assert_equal ['abc'], FakeFS::Globber.expand('{abc}')
+ end
+
+ def test_expand_with_brace_group_with_multiple_entries_returns_all_entries
+ assert_equal %w(a b c), FakeFS::Globber.expand('{a,b,c}')
+ end
+
+ def test_expand_with_brace_group_with_nested_entries_expands_only_first_level
+ assert_equal ['a', 'b', '{c,d}'], FakeFS::Globber.expand('{a,b,{c,d}}')
+ end
+
+ def test_path_components_with_no_globbing_splits_on_path_separator
+ assert_equal %w(a b c), FakeFS::Globber.path_components('/a/b/c')
+ end
+
+ def test_path_components_with_path_separator_inside_brace_group
+ assert_equal ['a', '{b,c/d}', 'e'], FakeFS::Globber.path_components('/a/{b,c/d}/e')
+ end
+end
Please sign in to comment.
Something went wrong with that request. Please try again.