fast_ignore 0.17.2 → 0.17.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +0 -13
  4. data/lib/fast_ignore/builders/gitignore.rb +15 -0
  5. data/lib/fast_ignore/builders/shebang.rb +17 -0
  6. data/lib/fast_ignore/builders/shebang_or_gitignore.rb +15 -0
  7. data/lib/fast_ignore/candidate.rb +85 -0
  8. data/lib/fast_ignore/gitconfig_parser.rb +1 -1
  9. data/lib/fast_ignore/gitignore_include_rule_builder.rb +40 -63
  10. data/lib/fast_ignore/gitignore_rule_builder.rb +49 -26
  11. data/lib/fast_ignore/gitignore_rule_group.rb +31 -0
  12. data/lib/fast_ignore/gitignore_rule_scanner.rb +12 -0
  13. data/lib/fast_ignore/matchers/allow_any_dir.rb +39 -0
  14. data/lib/fast_ignore/matchers/allow_path_regexp.rb +45 -0
  15. data/lib/fast_ignore/matchers/ignore_path_regexp.rb +45 -0
  16. data/lib/fast_ignore/matchers/shebang_regexp.rb +46 -0
  17. data/lib/fast_ignore/matchers/unmatchable.rb +31 -0
  18. data/lib/fast_ignore/matchers/within_dir.rb +50 -0
  19. data/lib/fast_ignore/path_expander.rb +11 -0
  20. data/lib/fast_ignore/path_regexp_builder.rb +130 -0
  21. data/lib/fast_ignore/patterns.rb +33 -0
  22. data/lib/fast_ignore/relative_candidate.rb +20 -0
  23. data/lib/fast_ignore/rule_group.rb +42 -0
  24. data/lib/fast_ignore/rule_groups.rb +55 -0
  25. data/lib/fast_ignore/version.rb +1 -1
  26. data/lib/fast_ignore/walkers/base.rb +26 -0
  27. data/lib/fast_ignore/walkers/file_system.rb +46 -0
  28. data/lib/fast_ignore/walkers/gitignore_collecting_file_system.rb +48 -0
  29. data/lib/fast_ignore.rb +54 -84
  30. metadata +23 -11
  31. data/lib/fast_ignore/file_root.rb +0 -35
  32. data/lib/fast_ignore/gitignore_rule_regexp_builder.rb +0 -76
  33. data/lib/fast_ignore/rule.rb +0 -65
  34. data/lib/fast_ignore/rule_builder.rb +0 -37
  35. data/lib/fast_ignore/rule_set.rb +0 -76
  36. data/lib/fast_ignore/rule_sets.rb +0 -109
  37. data/lib/fast_ignore/shebang_rule.rb +0 -80
  38. data/lib/fast_ignore/unmatchable_rule.rb +0 -41
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 56582bce9b3eae6e761585c77846530bb96b287c2d6938dd7213c31b84567560
4
- data.tar.gz: c2aabc49876831524acc8f14bc483aa8ec44ec715941a562bf4a6d5c4ac76b5c
3
+ metadata.gz: c81120885ae42b4893295ecd66b501ed6962d2742adc2bd59433796ca0e41995
4
+ data.tar.gz: 0a15d4651cc7dfc7eeed32b919da373ebee92195385ff0cf22acd92751258b68
5
5
  SHA512:
6
- metadata.gz: bc5e6b69f903bf2bb0beed6001bfa01bfa2f8b7e452eca9270884a38a1924649e336866d94085bd59ff72549d495d3857035227a7b3b0cf22859fd939c1e32ac
7
- data.tar.gz: e286d5802e0a0857552b9c9dbe03999546817478f2960fdbd057709485a862e876e3e9328a12fafc34388ba1aad0893f10ea318e7bdff728fb3ef41facc1568a
6
+ metadata.gz: c38a391c2a05c7439899144c2af1db29281538c855a18be47725b3e92f8fc40ecca2f69f15a26508d5f63d7f45f998cbba73ac41feaa1541356daf20067b4ce9
7
+ data.tar.gz: 0e355b08fbb00c9cca020ac06b0062f73477a59f673f6b465bf71d11c0228889dbeeb487e8e519eeccd09afa84290681f65f75300695332b0a4e44ecbec1b445
data/CHANGELOG.md CHANGED
@@ -1,3 +1,14 @@
1
+ # v0.17.4
2
+ - Deprecated `follow_symlinks:`, it's inaccurately named and awkward.
3
+
4
+ - Plus lots of refactoring that _should_ have no effect on behaviour
5
+ - Some performance regression due to the deprecation logic. we'll improve more than we lost after the deprecations are gone entirely.
6
+
7
+ # v0.17.3
8
+ - Add fuzz tests, fix a couple more edge cases it revealed:
9
+ - `~not_a_user` will be considered literal rather than raising an error, `~a_user` will continue to be expanded to the home directory of `a_user` when used in an `argv_rules:` or `allowed?`
10
+ - an `include_rule:` with a trailing `/` was raising a FrozenError in some circumstances.
11
+
1
12
  # v0.17.2
2
13
  - Remove unnecessary backport code that was leftover when support for 2.4 was dropped
3
14
  - Tiny performance improvements from rubocop-performance's suggestions
data/README.md CHANGED
@@ -166,19 +166,6 @@ When `relative: true`: FastIgnore#each will yield paths relative to the [`root:`
166
166
  FastIgnore.new(relative: true).to_a
167
167
  ```
168
168
 
169
- ### `follow_symlinks: true`
170
-
171
- **Default: false**
172
-
173
- When `follow_symlinks: false`: FastIgnore#each will match git's behaviour and not follow symbolic links.
174
- When `follow_symlinks: true`: FastIgnore#each will check if a symlink points to a directory, and files in linked directories must also match rules using the symlink path as the directory location, not the real directory location.
175
-
176
- **This doesn't use the real path for matching or yield or return it.**
177
-
178
- ```ruby
179
- FastIgnore.new(follow_symlinks: true).to_a
180
- ```
181
-
182
169
  ### `root:`
183
170
 
184
171
  **Default: Dir.pwd ($PWD, the current working directory)**
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module Builders
5
+ module Gitignore
6
+ def self.build(rule, allow, expand_path_with: nil)
7
+ if allow
8
+ ::FastIgnore::GitignoreIncludeRuleBuilder.new(rule, expand_path_with: expand_path_with).build
9
+ else
10
+ ::FastIgnore::GitignoreRuleBuilder.new(rule, expand_path_with: expand_path_with).build
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module Builders
5
+ module Shebang
6
+ def self.build(shebang, allow)
7
+ shebang.strip!
8
+ pattern = /\A#!.*\b#{::Regexp.escape(shebang)}\b/i
9
+ rule = ::FastIgnore::Matchers::ShebangRegexp.new(pattern, allow)
10
+ return rule unless allow
11
+
12
+ # also allow all directories in case they include a file with the matching shebang file
13
+ [::FastIgnore::Matchers::AllowAnyDir, rule]
14
+ end
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module Builders
5
+ module ShebangOrGitignore
6
+ def self.build(rule, allow, expand_path_with: nil)
7
+ if rule.delete_prefix!('#!:')
8
+ ::FastIgnore::Builders::Shebang.build(rule, allow)
9
+ else
10
+ ::FastIgnore::Builders::Gitignore.build(rule, allow, expand_path_with: expand_path_with)
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,85 @@
1
+ # frozen-string-literal: true
2
+
3
+ class FastIgnore
4
+ class Candidate
5
+ class << self
6
+ def root
7
+ @root ||= new('/', nil, true, true, nil)
8
+ end
9
+ end
10
+
11
+ def initialize(full_path, filename, directory, exists, content)
12
+ @full_path = full_path
13
+ @filename = filename
14
+ (@directory = directory) unless directory.nil?
15
+ (@exists = exists) unless exists.nil?
16
+ (@first_line = content.slice(/.*/)) if content # we only care about the first line
17
+ end
18
+
19
+ def parent
20
+ @parent ||= ::FastIgnore::Candidate.new(::File.dirname(@full_path), nil, true, true, nil)
21
+ end
22
+
23
+ # use \0 because it can't be in paths
24
+ def key
25
+ @key ||= :"#{
26
+ "\0" if defined?(@directory) && @directory
27
+ }#{
28
+ @full_path
29
+ }\0#{
30
+ @first_line if defined?(@first_line)
31
+ }"
32
+ end
33
+
34
+ def relative_to(dir)
35
+ return unless @full_path.start_with?(dir)
36
+
37
+ ::FastIgnore::RelativeCandidate.new(@full_path.delete_prefix(dir), self)
38
+ end
39
+
40
+ def directory?
41
+ return @directory if defined?(@directory)
42
+
43
+ @directory = ::File.lstat(@full_path).directory?
44
+ rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENAMETOOLONG
45
+ @exists ||= false
46
+ @directory = false
47
+ end
48
+
49
+ def exists?
50
+ return @exists if defined?(@exists)
51
+
52
+ @exists = ::File.exist?(@full_path)
53
+ rescue ::Errno::EACCES, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
54
+ # :nocov: can't quite get this set up in a test
55
+ @exists = false
56
+ # :nocov:
57
+ end
58
+
59
+ def filename
60
+ @filename ||= ::File.basename(@full_path)
61
+ end
62
+
63
+ # how long can a shebang be?
64
+ # https://www.in-ulm.de/~mascheck/various/shebang/
65
+ def first_line # rubocop:disable Metrics/MethodLength
66
+ @first_line ||= begin
67
+ file = ::File.new(@full_path)
68
+ first_line = file.sysread(64)
69
+ if first_line.start_with?('#!')
70
+ first_line += file.readline unless first_line.include?("\n")
71
+ file.close
72
+ first_line
73
+ else
74
+ file.close
75
+ ''
76
+ end
77
+ rescue ::EOFError, ::SystemCallError
78
+ # :nocov:
79
+ file&.close
80
+ # :nocov:
81
+ ''
82
+ end
83
+ end
84
+ end
85
+ end
@@ -55,7 +55,7 @@ class FastIgnore
55
55
  include_path = scan_value(file)
56
56
 
57
57
  value = ::FastIgnore::GitconfigParser.parse(
58
- ::File.expand_path(include_path, ::File.dirname(path)),
58
+ PathExpander.expand_path(include_path, ::File.dirname(path)),
59
59
  root: root,
60
60
  nesting: nesting + 1
61
61
  )
@@ -2,22 +2,10 @@
2
2
 
3
3
  class FastIgnore
4
4
  class GitignoreIncludeRuleBuilder < GitignoreRuleBuilder
5
- def initialize(rule, file_path, expand_path_from = nil)
6
- super(rule, file_path)
5
+ def initialize(rule, expand_path_with: nil)
6
+ super
7
7
 
8
- @parent_segments = []
9
8
  @negation = true
10
- @expand_path_from = expand_path_from
11
- end
12
-
13
- def expand_rule_path
14
- anchored! unless @s.match?(/\*/) # rubocop:disable Performance/StringInclude # it's StringScanner#match?
15
- return unless @s.match?(%r{(?:[~/]|\.{1,2}/|.*/\.\./)})
16
-
17
- dir_only! if @s.match?(%r{.*/\s*\z})
18
- @s.string.replace(::File.expand_path(@s.rest))
19
- @s.string.delete_prefix!(@expand_path_from)
20
- @s.pos = 0
21
9
  end
22
10
 
23
11
  def negated!
@@ -25,74 +13,63 @@ class FastIgnore
25
13
  end
26
14
 
27
15
  def unmatchable_rule!
28
- throw :abort_build, ::FastIgnore::UnmatchableRule
29
- end
30
-
31
- def nothing_emitted?
32
- @re.empty? && @parent_segments.empty?
33
- end
34
-
35
- def emit_dir
36
- anchored!
37
-
38
- @parent_segments << @re
39
- @re = ::FastIgnore::GitignoreRuleRegexpBuilder.new
16
+ throw :abort_build, ::FastIgnore::Matchers::Unmatchable
40
17
  end
41
18
 
42
19
  def emit_end
43
- @dir_only || @re.append_end_dir_or_anchor
20
+ if @dir_only
21
+ @child_re = @re.dup
22
+ @re.append_end_anchor
23
+ else
24
+ @re.append_dir_or_end_anchor
25
+ end
26
+
44
27
  break!
45
28
  end
46
29
 
47
- def parent_dir_re # rubocop:disable Metrics/MethodLength
48
- segment_joins_count = @parent_segments.length
49
- parent_prefix = if @file_path
50
- segment_joins_count += @file_path.escaped_segments_length
30
+ def build_parent_dir_rules
31
+ return unless @negation
51
32
 
52
- if @anchored
53
- "\\A#{@file_path.escaped_segments_joined}"
54
- else
55
- "\\A#{@file_path.escaped_segments_joined}(?:.*/)?"
33
+ if @anchored
34
+ parent_pattern = @s.string.dup
35
+ if parent_pattern.sub!(%r{/[^/]+/?\s*\z}, '/')
36
+ ::FastIgnore::GitignoreIncludeRuleBuilder.new(parent_pattern).build_as_parent
56
37
  end
57
38
  else
58
- prefix
39
+ [::FastIgnore::Matchers::AllowAnyDir]
59
40
  end
41
+ end
60
42
 
61
- out = parent_prefix.dup
62
- unless @parent_segments.empty?
63
- out << '(?:'
64
- out << @parent_segments.join('/(?:')
65
- out << '/'
43
+ def build_child_file_rule # rubocop:disable Metrics/MethodLength
44
+ if @child_re.end_with?('/')
45
+ @child_re.append_many_non_dir.append_dir if @dir_only
46
+ else
47
+ @child_re.append_dir
66
48
  end
67
- out << (')?' * segment_joins_count)
68
- out
69
- end
70
49
 
71
- def build_parent_dir_rule
72
- # Regexp::IGNORECASE = 1
73
- ::FastIgnore::Rule.new(::Regexp.new(parent_dir_re, 1), true, anchored_or_file_path, true)
74
- end
50
+ @child_re.prepend(prefix)
75
51
 
76
- def build_child_file_rule
77
- # Regexp::IGNORECASE = 1
78
- ::FastIgnore::Rule.new(@re.append_dir.to_regexp, @negation, anchored_or_file_path, false)
52
+ if @negation
53
+ ::FastIgnore::Matchers::AllowPathRegexp.new(@child_re.to_regexp, @anchored, false)
54
+ else
55
+ ::FastIgnore::Matchers::IgnorePathRegexp.new(@child_re.to_regexp, @anchored, false)
56
+ end
79
57
  end
80
58
 
81
- def build_rule
82
- joined_re = ::FastIgnore::GitignoreRuleRegexpBuilder.new
83
- joined_re.append(@parent_segments.join('/'))
84
- joined_re.append_dir unless @parent_segments.empty?
85
- joined_re.append(@re)
86
- @re = joined_re
59
+ def build_as_parent
60
+ anchored!
61
+ dir_only!
87
62
 
88
- rules = [super, build_parent_dir_rule]
89
- (rules << build_child_file_rule) if @dir_only
90
- rules
63
+ catch :abort_build do
64
+ process_rule
65
+ build_rule(child_file_rule: false)
66
+ end
91
67
  end
92
68
 
93
- def process_rule
94
- expand_rule_path if @expand_path_from
95
- super
69
+ def build_rule(child_file_rule: true)
70
+ @child_re ||= @re.dup # in case emit_end wasn't called
71
+
72
+ [super(), *build_parent_dir_rules, (build_child_file_rule if child_file_rule)].compact
96
73
  end
97
74
  end
98
75
  end
@@ -2,11 +2,11 @@
2
2
 
3
3
  class FastIgnore
4
4
  class GitignoreRuleBuilder # rubocop:disable Metrics/ClassLength
5
- def initialize(rule, file_path)
6
- @re = ::FastIgnore::GitignoreRuleRegexpBuilder.new
5
+ def initialize(rule, expand_path_with: nil)
6
+ @re = ::FastIgnore::PathRegexpBuilder.new
7
7
  @s = ::FastIgnore::GitignoreRuleScanner.new(rule)
8
8
 
9
- @file_path = file_path
9
+ @expand_path_with = expand_path_with
10
10
  @negation = false
11
11
  @anchored = false
12
12
  @dir_only = false
@@ -49,6 +49,11 @@ class FastIgnore
49
49
  @re.append_dir
50
50
  end
51
51
 
52
+ def emit_any_dir
53
+ anchored!
54
+ @re.append_any_dir
55
+ end
56
+
52
57
  def emit_end
53
58
  @re.append_end_anchor
54
59
  break!
@@ -60,11 +65,22 @@ class FastIgnore
60
65
  @re.append_escaped(@s.next_character) || unmatchable_rule!
61
66
  end
62
67
 
63
- def process_star_end_after_slash
64
- return true unless @s.star_end?
65
-
66
- @re.append_many_non_dir
67
- emit_end
68
+ def process_star_end_after_slash # rubocop:disable Metrics/MethodLength
69
+ if @s.star_end?
70
+ @re.append_many_non_dir
71
+ emit_end
72
+ elsif @s.two_star_end?
73
+ break!
74
+ elsif @s.star_slash_end?
75
+ @re.append_many_non_dir
76
+ dir_only!
77
+ emit_end
78
+ elsif @s.two_star_slash_end?
79
+ dir_only!
80
+ break!
81
+ else
82
+ true
83
+ end
68
84
  end
69
85
 
70
86
  def process_slash
@@ -76,7 +92,7 @@ class FastIgnore
76
92
  process_star_end_after_slash
77
93
  end
78
94
 
79
- def process_two_stars # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
95
+ def process_two_stars # rubocop:disable Metrics/MethodLength
80
96
  return unless @s.two_stars?
81
97
  return break! if @s.end?
82
98
 
@@ -90,8 +106,7 @@ class FastIgnore
90
106
  if nothing_emitted?
91
107
  never_anchored!
92
108
  else
93
- @re.append_any_dir
94
- anchored!
109
+ emit_any_dir
95
110
  end
96
111
  process_star_end_after_slash
97
112
  end
@@ -141,6 +156,7 @@ class FastIgnore
141
156
  end
142
157
 
143
158
  def process_rule # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
159
+ expand_rule_path! if @expand_path_with
144
160
  anchored! if @s.slash?
145
161
 
146
162
  catch :break do
@@ -159,28 +175,24 @@ class FastIgnore
159
175
  end
160
176
  end
161
177
 
162
- def prefix # rubocop:disable Metrics/MethodLength
163
- out = ::FastIgnore::GitignoreRuleRegexpBuilder.new
164
- if @file_path
165
- out.append_start_anchor.append(@file_path.escaped)
166
- out.append_any_dir unless @anchored
178
+ def prefix
179
+ out = ::FastIgnore::PathRegexpBuilder.new
180
+
181
+ if @anchored
182
+ out.append_start_anchor
167
183
  else
168
- if @anchored
169
- out.append_start_anchor
170
- else
171
- out.append_start_dir_or_anchor
172
- end
184
+ out.append_dir_or_start_anchor
173
185
  end
174
186
  out
175
187
  end
176
188
 
177
189
  def build_rule
178
190
  @re.prepend(prefix)
179
- ::FastIgnore::Rule.new(@re.to_regexp, @negation, anchored_or_file_path, @dir_only)
180
- end
181
-
182
- def anchored_or_file_path
183
- @anchored || @file_path
191
+ if @negation
192
+ ::FastIgnore::Matchers::AllowPathRegexp.new(@re.to_regexp, @anchored, @dir_only)
193
+ else
194
+ ::FastIgnore::Matchers::IgnorePathRegexp.new(@re.to_regexp, @anchored, @dir_only)
195
+ end
184
196
  end
185
197
 
186
198
  def build
@@ -194,5 +206,16 @@ class FastIgnore
194
206
  build_rule
195
207
  end
196
208
  end
209
+
210
+ def expand_rule_path!
211
+ anchored! unless @s.match?(/\*/) # rubocop:disable Performance/StringInclude # it's StringScanner#match?
212
+ return unless @s.match?(%r{(?:[~/]|\.{1,2}/|.*/\.\./)})
213
+
214
+ dir_only! if @s.match?(%r{.*/\s*\z})
215
+
216
+ @s.string.replace(PathExpander.expand_path(@s.rest, @expand_path_with))
217
+ @s.string.delete_prefix!(@expand_path_with)
218
+ @s.pos = 0
219
+ end
197
220
  end
198
221
  end
@@ -0,0 +1,31 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'set'
4
+
5
+ class FastIgnore
6
+ class GitignoreRuleGroup < ::FastIgnore::RuleGroup
7
+ def initialize(root)
8
+ @root = root
9
+ @loaded_paths = Set[root]
10
+
11
+ super([
12
+ ::FastIgnore::Patterns.new('.git', root: '/'),
13
+ ::FastIgnore::Patterns.new(from_file: ::FastIgnore::GlobalGitignore.path(root: root), root: root),
14
+ ::FastIgnore::Patterns.new(from_file: "#{root}.git/info/exclude", root: root),
15
+ ::FastIgnore::Patterns.new(from_file: "#{root}.gitignore", root: root)
16
+ ], false)
17
+ end
18
+
19
+ def add_gitignore(dir)
20
+ return if @loaded_paths.include?(dir)
21
+
22
+ @loaded_paths << dir
23
+ matcher = ::FastIgnore::Patterns.new(from_file: "#{dir}.gitignore").build_matchers(allow: false)
24
+ @matchers += matcher unless !matcher || matcher.empty?
25
+ end
26
+
27
+ def add_gitignore_to_root(path)
28
+ add_gitignore(path) until @loaded_paths.include?(path = "#{::File.dirname(path)}/")
29
+ end
30
+ end
31
+ end
@@ -42,6 +42,18 @@ class FastIgnore
42
42
  skip(/\*\s*\z/)
43
43
  end
44
44
 
45
+ def two_star_end?
46
+ skip(/\*{2,}\s*\z/)
47
+ end
48
+
49
+ def star_slash_end?
50
+ skip(%r{\*/\s*\z})
51
+ end
52
+
53
+ def two_star_slash_end?
54
+ skip(%r{\*{2,}/\s*\z})
55
+ end
56
+
45
57
  def question_mark?
46
58
  skip(/\?/)
47
59
  end
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module Matchers
5
+ module AllowAnyDir
6
+ class << self
7
+ def squash_id
8
+ :allow_any_dir
9
+ end
10
+
11
+ def dir_only?
12
+ true
13
+ end
14
+
15
+ def file_only?
16
+ false
17
+ end
18
+
19
+ def squash(_)
20
+ self
21
+ end
22
+
23
+ def weight
24
+ 0
25
+ end
26
+
27
+ # :nocov:
28
+ def inspect
29
+ '#<AllowAnyDir>'
30
+ end
31
+ # :nocov:
32
+
33
+ def match?(_)
34
+ :allow
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module Matchers
5
+ class AllowPathRegexp
6
+ attr_reader :dir_only
7
+ alias_method :dir_only?, :dir_only
8
+ undef :dir_only
9
+
10
+ attr_reader :squash_id
11
+ attr_reader :rule
12
+
13
+ def initialize(rule, squashable, dir_only)
14
+ @rule = rule
15
+ @dir_only = dir_only
16
+ @squashable = squashable
17
+ @squash_id = squashable ? :allow : object_id
18
+
19
+ freeze
20
+ end
21
+
22
+ def squash(list)
23
+ self.class.new(::Regexp.union(list.map(&:rule)), @squashable, @dir_only)
24
+ end
25
+
26
+ def file_only?
27
+ false
28
+ end
29
+
30
+ def weight
31
+ 1
32
+ end
33
+
34
+ # :nocov:
35
+ def inspect
36
+ "#<AllowPathRegexp #{'dir_only ' if @dir_only}#{@rule.inspect}>"
37
+ end
38
+ # :nocov:
39
+
40
+ def match?(candidate)
41
+ :allow if @rule.match?(candidate.relative_path)
42
+ end
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,45 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module Matchers
5
+ class IgnorePathRegexp
6
+ attr_reader :dir_only
7
+ alias_method :dir_only?, :dir_only
8
+ undef :dir_only
9
+
10
+ attr_reader :squash_id
11
+ attr_reader :rule
12
+
13
+ def initialize(rule, anchored, dir_only)
14
+ @rule = rule
15
+ @dir_only = dir_only
16
+ @anchored = anchored
17
+ @squash_id = anchored ? :ignore : object_id
18
+
19
+ freeze
20
+ end
21
+
22
+ def squash(list)
23
+ self.class.new(::Regexp.union(list.map(&:rule)), @anchored, @dir_only)
24
+ end
25
+
26
+ def file_only?
27
+ false
28
+ end
29
+
30
+ def weight
31
+ 1
32
+ end
33
+
34
+ # :nocov:
35
+ def inspect
36
+ "#<IgnorePathRegexp #{'dir_only ' if @dir_only}#{@rule.inspect}>"
37
+ end
38
+ # :nocov:
39
+
40
+ def match?(candidate)
41
+ :ignore if @rule.match?(candidate.relative_path)
42
+ end
43
+ end
44
+ end
45
+ end