fast_ignore 0.10.0 → 0.10.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 69021259195d30c9d3eb2e4461a779ef70b67d664370c5dff06d79f16ff009cb
4
- data.tar.gz: f3e60391822c26b461316389277f3901801c89e1dfcea59e819976d2b4c4b761
3
+ metadata.gz: f3d94c089fb5c75d6c9d0650d2391d03425c487c81296495f44f35ed1f6d80ac
4
+ data.tar.gz: a9bba05df8121aa49d38b39c7aaaa0e3c7d2b30e4b874d083fe517fa36846b97
5
5
  SHA512:
6
- metadata.gz: c99e8a9d3be9addeca4d18d327e450b9d6c345b6db354beb612e7f7e999af743d4ee4f62df9b1be0dec4a03820f948c52f8cb53d202ff8d3242499bbc453da87
7
- data.tar.gz: 2d17fe903303a913df5d763789517897e7c444c89069b3f81ce28df0136c1c5c6a94fd1c6f8080e17291713a75da4246da67c1c86a90c89a9084137276ba0b4d
6
+ metadata.gz: e8954fbef86b13d7948744b2c803319b261d67b6afe83412f1e099a377b17adae2aa1106a3445e6f5604449130c8dfc815331fe104f205ca09b87f5ff8caa69e
7
+ data.tar.gz: e53891e9d8b056a62ede7399695deb2911d5836ad5b8442b2ef90d7876fb4d794f1665697df6e7eeecf616f828217fce841f96c9bdfd39e73ae6c89594a65d5c
data/CHANGELOG.md CHANGED
@@ -1,3 +1,7 @@
1
+ # v0.10.1
2
+ - Add option to follow symlinks (turns out i needed it)
3
+ - performance improvements
4
+
1
5
  # v0.10.0
2
6
  - patterns with middle slashes are anchored to the root (like the gitignore documentation, now that it more clearly explains)
3
7
  - new shebang pattern (#!:), the previous version was extremely janky.
@@ -6,7 +10,6 @@
6
10
  - documentation improvements
7
11
  - root can be given as a path relative to PWD
8
12
  - includes with 'a/**/d' now matches a/b/c/d properly
9
- -
10
13
 
11
14
  # v0.9.0
12
15
  - speed improvements, which may break things (Specifically, only using relative paths internally, is about 30% faster (depending on root depth))
data/README.md CHANGED
@@ -50,12 +50,20 @@ FastIgnore.new.each.with_index { |file, index| puts "#{file}#{index}" }
50
50
  ```
51
51
 
52
52
  ### `relative: true`
53
- By default, FastIgnore will return full paths. To return paths relative to the current working directory, use:
53
+ By default, FastIgnore will return full paths. To return paths relative to the current working directory, or the supplied [`root:`](#root), use:
54
54
 
55
55
  ```ruby
56
56
  FastIgnore.new(relative: true).to_a
57
57
  ```
58
58
 
59
+ ### `follow_symlinks: true`
60
+ By default, FastIgnore will match git's behaviour and not follow symbolic links.
61
+ To make it follow symlinks, use:
62
+
63
+ ```ruby
64
+ FastIgnore.new(follow_symlinks: true).to_a
65
+ ```
66
+
59
67
  ### `root:`
60
68
 
61
69
  By default, root is PWD (the current working directory)
@@ -200,11 +208,10 @@ This does unfortunately lose the file path as the root for `/` and `/**` rules.
200
208
  ## Known issues
201
209
  - Doesn't take into account project excludes in `.git/info/exclude`
202
210
  - Doesn't take into account globally ignored files in `git config core.excludesFile`.
203
- - Doesn't follow this rule in the gitignore documentation because I don't understand what it means that isn't covered by other rules:
204
-
205
- > [If the pattern does not contain a slash /, Git treats it as a shell glob pattern and checks for a match against the pathname relative to the location of the `.gitignore` file (relative to the toplevel of the work tree if not from a `.gitignore` file)](https://www.git-scm.com/docs/gitignore#_pattern_format)
211
+ - Doesn't know what to do if you change the current working directory inside the `FastIgnore#each` block.
212
+ So don't do that.
206
213
 
207
- if someone can explain it with examples [make an issue please](https://github.com/robotdana/fast_ignore/issues/new)
214
+ (It does handle changing the current working directory between `FastIgnore#allowed?` calls.)
208
215
 
209
216
  ## Development
210
217
 
data/bin/ls CHANGED
@@ -1,4 +1,4 @@
1
- #!/usr/bin/env ruby
1
+ #!/usr/bin/env ruby --disable-all
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require_relative '../lib/fast_ignore'
data/bin/time ADDED
@@ -0,0 +1,18 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'open3'
5
+ RUNS = 30
6
+ SCRIPT = "time #{__dir__}/ls"
7
+ Dir.chdir ARGV[0] do
8
+ times = Array.new(RUNS).map do
9
+ run_times = Open3.capture3(SCRIPT)[1]
10
+ puts run_times.lstrip
11
+ run_times.scan(/(?:\d+(?:.\d+)?)/)
12
+ end
13
+
14
+ puts format(
15
+ "\e[1mAverage:\n\e[32m%0.2f real %0.2f user %0.2f sys\e[0m", # rubocop:disable Style/FormatStringToken
16
+ *times.transpose.map { |n| (n.map(&:to_f).sum / RUNS) }
17
+ )
18
+ end
data/fast_ignore.gemspec CHANGED
@@ -30,7 +30,7 @@ Gem::Specification.new do |spec|
30
30
  spec.require_paths = ['lib']
31
31
 
32
32
  spec.add_development_dependency 'bundler', '>= 1.17'
33
- spec.add_development_dependency 'leftovers', '>= 0.2.1'
33
+ spec.add_development_dependency 'leftovers', '>= 0.2.2'
34
34
  spec.add_development_dependency 'pry', '> 0'
35
35
  spec.add_development_dependency 'rake', '>= 12.3.3'
36
36
  spec.add_development_dependency 'rspec', '~> 3.0'
data/lib/fast_ignore.rb CHANGED
@@ -2,8 +2,8 @@
2
2
 
3
3
  require_relative './fast_ignore/backports'
4
4
 
5
- require_relative './fast_ignore/rule_parser'
6
5
  require_relative './fast_ignore/rule_set_builder'
6
+ require_relative './fast_ignore/rule_builder'
7
7
  require_relative './fast_ignore/rule_set'
8
8
  require_relative './fast_ignore/rule'
9
9
 
@@ -22,70 +22,61 @@ class FastIgnore
22
22
  end
23
23
  # :nocov:
24
24
 
25
- def initialize( # rubocop:disable Metrics/MethodLength
26
- relative: false,
27
- root: nil,
28
- include_shebangs: nil,
29
- **rule_set_builder_args
30
- )
31
- # :nocov:
32
- if include_shebangs && !Array(include_shebangs).empty?
33
-
34
- warn <<~WARNING
35
- Removed FastIgnore `include_shebangs:` argument.
36
- It will be ignored. Please replace with the include_rules: in the shebang format
37
- https://github.com/robotdana/fast_ignore#shebang-rules
38
- WARNING
39
- end
40
- # :nocov:
41
-
42
- root = root ? File.expand_path(root, ::Dir.pwd) : ::Dir.pwd
43
- @root = "#{root}/"
44
-
45
- @rule_sets = ::FastIgnore::RuleSetBuilder.from_args(root: @root, **rule_set_builder_args)
25
+ def initialize(relative: false, root: nil, follow_symlinks: false, **rule_set_builder_args)
46
26
  @relative = relative
27
+ @follow_symlinks = follow_symlinks
28
+ dir_pwd = Dir.pwd
29
+ @root = "#{::File.expand_path(root.to_s, dir_pwd)}/"
30
+ @rule_sets = ::FastIgnore::RuleSetBuilder.build(root: @root, **rule_set_builder_args)
47
31
 
48
32
  freeze
49
33
  end
50
34
 
51
35
  def each(&block)
52
- if block_given?
53
- each_allowed(&block)
36
+ return enum_for(:each) unless block_given?
37
+
38
+ dir_pwd = Dir.pwd
39
+ root_from_pwd = @root.start_with?(dir_pwd) ? ".#{@root.delete_prefix(dir_pwd)}" : @root
40
+
41
+ each_recursive(root_from_pwd, '', &block)
42
+ end
43
+
44
+ def directory?(path)
45
+ if @follow_symlinks
46
+ ::File.stat(path).directory?
54
47
  else
55
- enum_for(:each_allowed)
48
+ ::File.lstat(path).directory?
56
49
  end
57
50
  end
58
51
 
59
52
  def allowed?(path)
60
53
  full_path = ::File.expand_path(path, @root)
61
54
  return false unless full_path.start_with?(@root)
62
-
63
- dir = ::File.lstat(full_path).directory?
64
- return false if dir
55
+ return false if directory?(full_path)
65
56
 
66
57
  relative_path = full_path.delete_prefix(@root)
67
58
  filename = ::File.basename(relative_path)
68
59
 
69
- @rule_sets.all? { |r| r.allowed_recursive?(relative_path, dir, filename) }
60
+ @rule_sets.all? { |r| r.allowed_recursive?(relative_path, false, filename) }
70
61
  rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENOTDIR, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
71
62
  false
72
63
  end
73
64
 
74
65
  private
75
66
 
76
- def each_allowed(full_path = @root, relative_path = '', &block) # rubocop:disable Metrics/MethodLength
77
- ::Dir.each_child(full_path) do |filename|
67
+ def each_recursive(parent_full_path, parent_relative_path, &block) # rubocop:disable Metrics/MethodLength
68
+ ::Dir.each_child(parent_full_path) do |filename|
78
69
  begin
79
- full_child = full_path + filename
80
- relative_child = relative_path + filename
81
- dir = ::File.lstat(full_child).directory?
70
+ full_path = parent_full_path + filename
71
+ relative_path = parent_relative_path + filename
72
+ dir = directory?(full_path)
82
73
 
83
- next unless @rule_sets.all? { |r| r.allowed_unrecursive?(relative_child, dir, filename) }
74
+ next unless @rule_sets.all? { |r| r.allowed_unrecursive?(relative_path, dir, filename) }
84
75
 
85
76
  if dir
86
- each_allowed("#{full_child}/", "#{relative_child}/", &block)
77
+ each_recursive(full_path + '/', relative_path + '/', &block)
87
78
  else
88
- yield(@relative ? relative_child : full_child)
79
+ yield(@relative ? relative_path : @root + relative_path)
89
80
  end
90
81
  rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENOTDIR, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
91
82
  nil
@@ -10,18 +10,20 @@ class FastIgnore
10
10
 
11
11
  attr_reader :negation
12
12
  alias_method :negation?, :negation
13
+
13
14
  attr_reader :dir_only
14
15
  alias_method :dir_only?, :dir_only
15
- attr_reader :file_only
16
- alias_method :file_only?, :file_only
17
16
 
18
17
  attr_reader :shebang
19
- attr_reader :rule
18
+ alias_method :file_only?, :shebang
19
+
20
+ attr_reader :unanchored
21
+ alias_method :unanchored?, :unanchored
20
22
 
21
- def initialize(rule, dir_only, file_only, negation, shebang = nil)
23
+ def initialize(rule, unanchored, dir_only, negation, shebang = nil)
22
24
  @rule = rule
25
+ @unanchored = unanchored
23
26
  @dir_only = dir_only
24
- @file_only = file_only
25
27
  @negation = negation
26
28
  @shebang = shebang
27
29
 
@@ -31,9 +33,9 @@ class FastIgnore
31
33
  # :nocov:
32
34
  def inspect
33
35
  if shebang
34
- "#<Rule #{'allow ' if negation?}#!:#{shebang.to_s[15..-4]}>"
36
+ "#<Rule #{'allow ' if @negation}#!:#{@shebang.to_s[15..-4]}>"
35
37
  else
36
- "#<Rule #{'!' if negation?}#{rule}#{'/' if dir_only?}>"
38
+ "#<Rule #{'!' if @negation}#{@rule}#{'/' if @dir_only}>"
37
39
  end
38
40
  end
39
41
  # :nocov:
@@ -42,6 +44,7 @@ class FastIgnore
42
44
  if @shebang
43
45
  match_shebang?(path, filename)
44
46
  else
47
+ # 14 = FNMATCH_OPTIONS
45
48
  ::File.fnmatch?(@rule, path, 14)
46
49
  end
47
50
  end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module RuleBuilder
5
+ # rule or nil
6
+ class << self
7
+ # :nocov:
8
+ if ::FastIgnore::Backports.ruby_version_less_than?(2, 5)
9
+ require_relative 'backports/delete_prefix_suffix'
10
+ using ::FastIgnore::Backports::DeletePrefixSuffix
11
+ end
12
+ # :nocov:
13
+
14
+ def build(rule, allow, expand_path, file_root)
15
+ strip(rule)
16
+
17
+ return shebang_rules(rule, allow) if remove_shebang(rule)
18
+ return [] if skip?(rule)
19
+
20
+ gitignore_rules(rule, allow, expand_path, file_root)
21
+ end
22
+
23
+ private
24
+
25
+ def strip(rule)
26
+ rule.chomp!
27
+ rule.rstrip! unless rule.end_with?('\\ ')
28
+ end
29
+
30
+ def remove_shebang(rule)
31
+ return unless rule.delete_prefix!('#!:')
32
+
33
+ rule.strip!
34
+
35
+ true
36
+ end
37
+
38
+ def shebang_rules(rule, allow)
39
+ rules = [::FastIgnore::Rule.new(nil, true, false, allow, /\A#!.*\b#{Regexp.escape(rule)}\b/.freeze)]
40
+ return rules unless allow
41
+
42
+ rules << ::FastIgnore::Rule.new('**/*', true, true, true)
43
+ rules
44
+ end
45
+
46
+ def skip?(rule)
47
+ rule.empty? || rule.start_with?('#')
48
+ end
49
+
50
+ def gitignore_rules(rule, allow, expand_path, file_root)
51
+ dir_only = extract_dir_only(rule)
52
+ negation = extract_negation(rule, allow)
53
+
54
+ expand_rule_path(rule, expand_path) if expand_path
55
+ unanchored = unanchored?(rule)
56
+ rule.delete_prefix!('/')
57
+
58
+ rule.prepend("#{file_root}#{'**/' if unanchored}") if file_root || unanchored
59
+
60
+ build_gitignore_rules(rule, unanchored, allow, dir_only, negation)
61
+ end
62
+
63
+ def extract_dir_only(rule)
64
+ rule.delete_suffix!('/')
65
+ end
66
+
67
+ def extract_negation(rule, allow)
68
+ return allow unless rule.delete_prefix!('!')
69
+
70
+ not allow
71
+ end
72
+
73
+ EXPAND_PATH_RE = %r{^(?:[~/]|\.{1,2}/)}.freeze
74
+ def expand_rule_path(rule, root)
75
+ rule.replace(::File.expand_path(rule)) if rule.match?(EXPAND_PATH_RE)
76
+ rule.delete_prefix!(root)
77
+ rule.prepend('/') unless rule.start_with?('*') || rule.start_with?('/')
78
+ end
79
+
80
+ def unanchored?(rule)
81
+ not rule.include?('/') # we've already removed the trailing '/' with extract_dir_only
82
+ end
83
+
84
+ def build_gitignore_rules(rule, unanchored, allow, dir_only, negation)
85
+ rules = [::FastIgnore::Rule.new(rule.freeze, unanchored, dir_only, negation)]
86
+ return rules unless allow
87
+
88
+ rules << ::FastIgnore::Rule.new("#{rule}/**/*", unanchored, false, negation)
89
+ rules + ancestor_rules(rule, unanchored)
90
+ end
91
+
92
+ def ancestor_rules(parent, unanchored)
93
+ ancestor_rules = []
94
+
95
+ while (parent = ::File.dirname(parent)) != '.'
96
+ rule = ::File.basename(parent) == '**' ? "#{parent}/*" : parent.freeze
97
+ ancestor_rules << ::FastIgnore::Rule.new(rule, unanchored, true, true)
98
+ end
99
+
100
+ ancestor_rules
101
+ end
102
+ end
103
+ end
104
+ end
@@ -2,12 +2,15 @@
2
2
 
3
3
  class FastIgnore
4
4
  class RuleSet
5
- def initialize(allow: false)
6
- @dir_rules = []
7
- @file_rules = []
5
+ def initialize(rules, allow)
6
+ @dir_rules = rules.reject(&:file_only?).freeze
7
+ @file_rules = rules.reject(&:dir_only?).freeze
8
+ @any_not_anchored = rules.any?(&:unanchored?)
9
+ @has_shebang_rules = rules.any?(&:shebang)
8
10
  @allowed_recursive = { '.' => true }
9
- @any_not_anchored = false
10
11
  @allow = allow
12
+
13
+ freeze
11
14
  end
12
15
 
13
16
  def freeze
@@ -26,21 +29,10 @@ class FastIgnore
26
29
 
27
30
  def allowed_unrecursive?(path, dir, filename)
28
31
  (dir ? @dir_rules : @file_rules).reverse_each do |rule|
29
- # 14 = Rule::FNMATCH_OPTIONS
30
-
31
32
  return rule.negation? if rule.match?(path, filename)
32
33
  end
33
34
 
34
- (not @allow) || (@any_not_anchored if dir)
35
- end
36
-
37
- def append_rules(anchored, rules)
38
- rules.each do |rule|
39
- (@dir_rules << rule) unless rule.file_only?
40
- (@file_rules << rule) unless rule.dir_only?
41
- @any_not_anchored ||= !anchored
42
- @has_shebang_rules ||= rule.shebang
43
- end
35
+ (not @allow) || (dir && @any_not_anchored)
44
36
  end
45
37
 
46
38
  def weight
@@ -1,92 +1,87 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class FastIgnore
4
- class RuleSetBuilder
5
- # :nocov:
6
- if ::FastIgnore::Backports.ruby_version_less_than?(2, 5)
7
- require_relative 'backports/delete_prefix_suffix'
8
- using ::FastIgnore::Backports::DeletePrefixSuffix
9
- end
10
- # :nocov:
4
+ module RuleSetBuilder
5
+ class << self
6
+ # :nocov:
7
+ if ::FastIgnore::Backports.ruby_version_less_than?(2, 5)
8
+ require_relative 'backports/delete_prefix_suffix'
9
+ using ::FastIgnore::Backports::DeletePrefixSuffix
10
+ end
11
+ # :nocov:
11
12
 
12
- def self.from_args( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
13
- root:,
14
- ignore_rules: nil,
15
- ignore_files: nil,
16
- gitignore: :auto,
17
- include_rules: nil,
18
- include_files: nil,
19
- argv_rules: nil
20
- )
21
- rule_sets = [
22
- from_array(ignore_rules),
23
- *from_files(ignore_files, project_root: root),
24
- from_array('.git'),
25
- from_gitignore_arg(gitignore, project_root: root),
26
- from_array(include_rules, allow: true),
27
- *from_files(include_files, allow: true, project_root: root),
28
- from_array(argv_rules, allow: true, expand_path: root)
29
- ]
13
+ def build( # rubocop:disable Metrics/ParameterLists
14
+ root:,
15
+ ignore_rules: nil,
16
+ ignore_files: nil,
17
+ gitignore: :auto,
18
+ include_rules: nil,
19
+ include_files: nil,
20
+ argv_rules: nil
21
+ )
22
+ prepare [
23
+ from_array(ignore_rules),
24
+ *from_files(ignore_files, project_root: root),
25
+ from_array('.git'),
26
+ from_gitignore_arg(gitignore, project_root: root),
27
+ from_array(include_rules, allow: true),
28
+ *from_files(include_files, allow: true, project_root: root),
29
+ from_array(argv_rules, allow: true, expand_path: root)
30
+ ]
31
+ end
30
32
 
31
- rule_sets.compact!
32
- rule_sets.reject!(&:empty?)
33
- rule_sets.sort_by!(&:weight)
34
- rule_sets
35
- end
33
+ private
36
34
 
37
- def self.from_file(filename, project_root:, allow: false)
38
- filename = ::File.expand_path(filename, project_root)
39
- raise FastIgnore::Error, "#{filename} is not within #{project_root}" unless filename.start_with?(project_root)
35
+ def prepare(rule_sets)
36
+ rule_sets.compact!
37
+ rule_sets.reject!(&:empty?)
38
+ rule_sets.sort_by!(&:weight)
39
+ rule_sets
40
+ end
40
41
 
41
- file_root = "#{::File.dirname(filename)}/".delete_prefix(project_root)
42
- rule_set = ::FastIgnore::RuleSet.new(allow: allow)
42
+ def from_file(filename, project_root:, allow: false)
43
+ filename = ::File.expand_path(filename, project_root)
44
+ raise FastIgnore::Error, "#{filename} is not within #{project_root}" unless filename.start_with?(project_root)
43
45
 
44
- ::IO.foreach(filename) do |rule_string|
45
- parse_rules(rule_string, allow: allow, rule_set: rule_set, file_root: file_root)
46
+ file_root = "#{::File.dirname(filename)}/".delete_prefix(project_root)
47
+ build_rule_set(::File.readlines(filename), allow, file_root: file_root)
46
48
  end
47
49
 
48
- rule_set.freeze
49
- end
50
-
51
- def self.from_files(files, project_root:, allow: false)
52
- Array(files).map do |file|
53
- from_file(file, allow: allow, project_root: project_root)
50
+ def from_files(files, project_root:, allow: false)
51
+ Array(files).map do |file|
52
+ from_file(file, project_root: project_root, allow: allow)
53
+ end
54
54
  end
55
- end
56
55
 
57
- def self.from_gitignore_arg(gitignore, project_root:)
58
- default_path = ::File.join(project_root, '.gitignore')
59
- case gitignore
60
- when :auto
61
- from_file(default_path, project_root: project_root) if ::File.exist?(default_path)
62
- when true
63
- from_file(default_path, project_root: project_root)
56
+ def from_gitignore_arg(gitignore, project_root:)
57
+ default_path = ::File.join(project_root, '.gitignore')
58
+ case gitignore
59
+ when :auto
60
+ from_file(default_path, project_root: project_root) if ::File.exist?(default_path)
61
+ when true
62
+ from_file(default_path, project_root: project_root)
63
+ end
64
64
  end
65
- end
66
65
 
67
- def self.from_array(rules, allow: false, expand_path: false)
68
- rules = Array(rules)
69
- return if rules.empty?
66
+ def from_array(rules, allow: false, expand_path: false)
67
+ return unless rules
70
68
 
71
- rule_set = ::FastIgnore::RuleSet.new(allow: allow)
69
+ rules = Array(rules)
72
70
 
73
- rules.each do |rule_string|
74
- rule_string.to_s.each_line do |rule_line|
75
- parse_rules(rule_line, rule_set: rule_set, allow: allow, expand_path: expand_path)
76
- end
71
+ return if rules.empty?
72
+
73
+ rules = rules.flat_map { |string| string.to_s.lines }
74
+
75
+ build_rule_set(rules, allow, expand_path: expand_path)
77
76
  end
78
77
 
79
- rule_set.freeze
80
- end
78
+ def build_rule_set(rules, allow, expand_path: false, file_root: nil)
79
+ rules = rules.flat_map do |rule|
80
+ ::FastIgnore::RuleBuilder.build(rule, allow, expand_path, file_root)
81
+ end
81
82
 
82
- def self.parse_rules(rule_line, rule_set:, allow: false, expand_path: false, file_root: nil)
83
- ::FastIgnore::RuleParser.new_rule(
84
- rule_line,
85
- rule_set: rule_set,
86
- allow: allow,
87
- expand_path: expand_path,
88
- file_root: file_root
89
- )
83
+ ::FastIgnore::RuleSet.new(rules, allow).freeze
84
+ end
90
85
  end
91
86
  end
92
87
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class FastIgnore
4
- VERSION = '0.10.0'
4
+ VERSION = '0.10.1'
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_ignore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.10.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dana Sherson
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-04-21 00:00:00.000000000 Z
11
+ date: 2020-04-22 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -30,14 +30,14 @@ dependencies:
30
30
  requirements:
31
31
  - - ">="
32
32
  - !ruby/object:Gem::Version
33
- version: 0.2.1
33
+ version: 0.2.2
34
34
  type: :development
35
35
  prerelease: false
36
36
  version_requirements: !ruby/object:Gem::Requirement
37
37
  requirements:
38
38
  - - ">="
39
39
  - !ruby/object:Gem::Version
40
- version: 0.2.1
40
+ version: 0.2.2
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: pry
43
43
  requirement: !ruby/object:Gem::Requirement
@@ -160,15 +160,15 @@ files:
160
160
  - Rakefile
161
161
  - bin/console
162
162
  - bin/ls
163
- - bin/ls-disable-gems
164
163
  - bin/setup
164
+ - bin/time
165
165
  - fast_ignore.gemspec
166
166
  - lib/fast_ignore.rb
167
167
  - lib/fast_ignore/backports.rb
168
168
  - lib/fast_ignore/backports/delete_prefix_suffix.rb
169
169
  - lib/fast_ignore/backports/dir_each_child.rb
170
170
  - lib/fast_ignore/rule.rb
171
- - lib/fast_ignore/rule_parser.rb
171
+ - lib/fast_ignore/rule_builder.rb
172
172
  - lib/fast_ignore/rule_set.rb
173
173
  - lib/fast_ignore/rule_set_builder.rb
174
174
  - lib/fast_ignore/version.rb
data/bin/ls-disable-gems DELETED
@@ -1,6 +0,0 @@
1
- #!/usr/bin/env ruby --disable-gems
2
- # frozen_string_literal: true
3
-
4
- require_relative '../lib/fast_ignore'
5
-
6
- puts FastIgnore.new(relative: true, argv_rules: ARGV).to_a
@@ -1,103 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- class FastIgnore
4
- class RuleParser
5
- # :nocov:
6
- if ::FastIgnore::Backports.ruby_version_less_than?(2, 5)
7
- require_relative 'backports/delete_prefix_suffix'
8
- using ::FastIgnore::Backports::DeletePrefixSuffix
9
- end
10
- # :nocov:
11
-
12
- # rule or nil
13
- class << self
14
- def new_rule(rule, rule_set:, allow: false, expand_path: false, file_root: nil) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
15
- rule = rule.dup
16
- strip(rule)
17
-
18
- return rule_set.append_rules(false, shebang_rules(rule, allow)) if extract_shebang(rule)
19
-
20
- return if skip?(rule)
21
-
22
- dir_only = extract_dir_only(rule)
23
- negation = extract_negation(rule, allow)
24
-
25
- expand_rule_path(rule, expand_path) if expand_path
26
- anchored = anchored?(rule)
27
- rule.delete_prefix!('/')
28
-
29
- rule.prepend("#{file_root}#{'**/' unless anchored}") if file_root || (not anchored)
30
-
31
- rule.freeze
32
-
33
- rule_set.append_rules(
34
- anchored,
35
- rules(rule, allow, dir_only, negation)
36
- )
37
- end
38
-
39
- private
40
-
41
- def shebang_rules(rule, allow)
42
- rules = [::FastIgnore::Rule.new(nil, false, true, allow, /\A#!.*\b#{Regexp.escape(rule)}\b/)]
43
- return rules unless allow
44
-
45
- rules << ::FastIgnore::Rule.new('**/*', true, false, true)
46
- rules
47
- end
48
-
49
- def rules(rule, allow, dir_only, negation)
50
- rules = [::FastIgnore::Rule.new(rule, dir_only, false, negation)]
51
- return rules unless allow
52
-
53
- rules << ::FastIgnore::Rule.new("#{rule}/**/*", false, false, negation)
54
- rules + ancestor_rules(rule)
55
- end
56
-
57
- def ancestor_rules(parent)
58
- ancestor_rules = []
59
-
60
- while (parent = ::File.dirname(parent)) != '.'
61
- rule = ::File.basename(parent) == '**' ? "#{parent}/*" : parent.freeze
62
- ancestor_rules << ::FastIgnore::Rule.new(rule, true, false, true)
63
- end
64
-
65
- ancestor_rules
66
- end
67
-
68
- def extract_negation(rule, allow)
69
- return allow unless rule.delete_prefix!('!')
70
-
71
- not allow
72
- end
73
-
74
- def extract_dir_only(rule)
75
- rule.delete_suffix!('/')
76
- end
77
-
78
- def strip(rule)
79
- rule.chomp!
80
- rule.rstrip! unless rule.end_with?('\\ ')
81
- end
82
-
83
- def anchored?(rule)
84
- rule.include?('/') # we've already removed the trailing '/' with extract_dir_only
85
- end
86
-
87
- EXPAND_PATH_RE = %r{^(?:[~/]|\.{1,2}/)}.freeze
88
- def expand_rule_path(rule, root)
89
- rule.replace(::File.expand_path(rule)) if rule.match?(EXPAND_PATH_RE)
90
- rule.delete_prefix!(root)
91
- rule.prepend('/') unless rule.start_with?('*') || rule.start_with?('/')
92
- end
93
-
94
- def extract_shebang(rule)
95
- rule.delete_prefix!('#!:') && (rule.strip! || true)
96
- end
97
-
98
- def skip?(rule)
99
- rule.empty? || rule.start_with?('#')
100
- end
101
- end
102
- end
103
- end