fast_ignore 0.10.2 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2dd945c76bf226766ac86086faf839eac44c4c0cce452e2a3a44e7c47964b7f5
4
- data.tar.gz: a72de31878713db71c94aa8067c87b807f19833eb008a1a6d6e673fcdeff5a7a
3
+ metadata.gz: f467113b0ee03faf028758ac176c59b3e51465684f8ffe144d432ba75133c10f
4
+ data.tar.gz: 2f6f0ce0babec00977a55595baa7ec806d7a9a3f1fec86df46f29475b41238cc
5
5
  SHA512:
6
- metadata.gz: cff75a6418ecc958f2a839b9617554e3857763611248063aef27ec244dd0d1b433d61b81bfdb85a74dd8497fea8599f146ae723fd76023aef72285f53a620ecd
7
- data.tar.gz: 39aeceb2cd078c8b873019b9763eccb01450e408a24c3fb04005f9451879e1a125bcd73f26a1c4e67e6c999e7d6d0f78b4a1b41abbc0a2650ec36bb1ac7adde6
6
+ metadata.gz: 3a7698e54ab0897b6b50c8638d41f3243bd3ba4ced559a5c7e01f6d365b6fb875b906a1924e96641572815748479eb793dfabc91da6f3bec62115f98ff39a392
7
+ data.tar.gz: 7e8b85ff838d04d1c16cd3eca5a480d6948342a07667760782840b0e36a706c02db2bb4e09e3370b3ccc1cdc2f38f9e893707c9f2128652a8a4aae4cdb8dd3d0
@@ -10,8 +10,11 @@ enoent
10
10
  enumerables
11
11
  env
12
12
  errno
13
+ esque
13
14
  extensionless
14
15
  fancyignore
16
+ filesystem
17
+ fnmatch
15
18
  frotz
16
19
  gemfile
17
20
  github
@@ -34,6 +37,7 @@ rspec
34
37
  rubo
35
38
  rubocop
36
39
  rubygems
40
+ rubyish
37
41
  rulesets
38
42
  rvm
39
43
  sherson
@@ -2,6 +2,7 @@
2
2
  sudo: false
3
3
  language: ruby
4
4
  cache: bundler
5
+ before_install: gem install bundler
5
6
  rvm:
6
7
  - 2.4
7
8
  - 2.5
@@ -1,3 +1,7 @@
1
+ # v0.11.0
2
+ - major performance improvement (use regexp rather than fnmatch)
3
+ - optionally pass directory: and content: into allowed? if these are already loaded.
4
+
1
5
  # v0.10.2
2
6
  - add FastIgnore#=== as an alias for FastIgnore#allowed? so that FastIgnore objects can be used for case statements.
3
7
  - Fix shebangs in non-pwd-root situations
data/README.md CHANGED
@@ -11,6 +11,16 @@ Filter a directory tree using a .gitignore file. Recognises all of the [gitignor
11
11
  FastIgnore.new(relative: true).sort == `git ls-files`.split("\n").sort
12
12
  ```
13
13
 
14
+ ## Features
15
+
16
+ - Fast (faster than using `` `git ls-files`.split("\n") `` for small repos (because it avoids the overhead of ``` `` ```))
17
+ - Supports ruby 2.4 - 2.7
18
+ - supports all gitignore rule patterns
19
+ - doesn't require git to be installed
20
+ - supports a gitignore-esque "include" patterns. (`include_rules:`/`include_files:`)
21
+ - supports an expansion of include patterns, matching expanded paths (`argv_rules:`)
22
+ - supports matching by shebang rather than filename for extensionless files: `#!:`
23
+
14
24
  ## Installation
15
25
 
16
26
  Add this line to your application's Gemfile:
@@ -62,7 +72,8 @@ FastIgnore.new.allowed?('~/home/path')
62
72
  This is aliased as `===` so you can use the FastIgnore object in case statements.
63
73
  ```ruby
64
74
  case my_path
65
- when FastIgnore.new then puts my_path
75
+ when FastIgnore.new
76
+ puts(my_path)
66
77
  end
67
78
  ```
68
79
 
@@ -214,6 +225,15 @@ FastIgnore.new(argv_rules: ["my/rule", File.read('/my/path')]).to_a
214
225
 
215
226
  This does unfortunately lose the file path as the root for `/` and `/**` rules.
216
227
 
228
+ ### optimising #allowed?
229
+
230
+ To avoid unnecessary calls to the filesystem, if your code already knows whether or not it's a directory, or if you're checking shebangs and you have already read the content of the file: use
231
+ ```ruby
232
+ FastIgnore.new.allowed?('relative/path', directory: false, content: "#!/usr/bin/ruby\n\nputs 'ok'\n")
233
+ ```
234
+ This is not required, and if FastIgnore does have to go to the filesystem for this information it's well optimised to only read what is necessary.
235
+
236
+
217
237
  ## Known issues
218
238
  - Doesn't take into account project excludes in `.git/info/exclude`
219
239
  - Doesn't take into account globally ignored files in `git config core.excludesFile`.
@@ -224,9 +244,13 @@ This does unfortunately lose the file path as the root for `/` and `/**` rules.
224
244
 
225
245
  ## Development
226
246
 
227
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
247
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake` to run the tests and linters.
248
+
249
+ You can run `bin/console` for an interactive prompt that will allow you to experiment.
250
+ `bin/ls [argv_rules]` will return something equivalent to `git ls-files` and `bin/time [argv_rules]` will give you the average time for 30 runs.
251
+ This repo is too small to stress bin/time more than 0.01s, switch to a large repo and find the average time before and after changes.
228
252
 
229
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
253
+ To install this gem onto your local machine, run `bundle exec rake install`.
230
254
 
231
255
  ## Contributing
232
256
 
data/bin/time CHANGED
@@ -5,17 +5,17 @@
5
5
  # ensure nothing else is watching that dir in the filesystem e.g. webpack
6
6
 
7
7
  require 'open3'
8
+ require 'shellwords'
8
9
  RUNS = 30
9
- SCRIPT = "time #{__dir__}/ls"
10
- Dir.chdir ARGV[0] do
11
- times = Array.new(RUNS).map do
12
- run_times = Open3.capture3(SCRIPT)[1]
13
- puts run_times.lstrip
14
- run_times.scan(/(?:\d+(?:.\d+)?)/)
15
- end
10
+ SCRIPT = "time #{__dir__}/ls #{Shellwords.join(ARGV)}"
16
11
 
17
- puts format(
18
- "\e[1mAverage:\n\e[32m%0.2f real %0.2f user %0.2f sys\e[0m", # rubocop:disable Style/FormatStringToken
19
- *times.transpose.map { |n| (n.map(&:to_f).sum / RUNS) }
20
- )
12
+ times = Array.new(RUNS).map do
13
+ run_times = Open3.capture3(SCRIPT)[1]
14
+ puts run_times.lstrip
15
+ run_times.scan(/(?:\d+(?:.\d+)?)/)
21
16
  end
17
+
18
+ puts format(
19
+ "\e[1mAverage:\n\e[32m%0.2f real %0.2f user %0.2f sys\e[0m", # rubocop:disable Style/FormatStringToken
20
+ *times.transpose.map { |n| (n.map(&:to_f).sum / RUNS) }
21
+ )
@@ -7,6 +7,7 @@ require_relative './fast_ignore/rule_builder'
7
7
  require_relative './fast_ignore/rule_set'
8
8
  require_relative './fast_ignore/rule'
9
9
  require_relative './fast_ignore/shebang_rule'
10
+ require_relative './fast_ignore/fn_match_to_re'
10
11
 
11
12
  class FastIgnore
12
13
  class Error < StandardError; end
@@ -14,13 +15,8 @@ class FastIgnore
14
15
  include ::Enumerable
15
16
 
16
17
  # :nocov:
17
- if ::FastIgnore::Backports.ruby_version_less_than?(2, 5)
18
- require_relative 'fast_ignore/backports/delete_prefix_suffix'
19
- using ::FastIgnore::Backports::DeletePrefixSuffix
20
-
21
- require_relative 'fast_ignore/backports/dir_each_child'
22
- using ::FastIgnore::Backports::DirEachChild
23
- end
18
+ using ::FastIgnore::Backports::DeletePrefixSuffix if defined?(::FastIgnore::Backports::DeletePrefixSuffix)
19
+ using ::FastIgnore::Backports::DirEachChild if defined?(::FastIgnore::Backports::DirEachChild)
24
20
  # :nocov:
25
21
 
26
22
  def initialize(relative: false, root: nil, follow_symlinks: false, **rule_set_builder_args)
@@ -41,23 +37,15 @@ class FastIgnore
41
37
  each_recursive(root_from_pwd, '', &block)
42
38
  end
43
39
 
44
- def directory?(path)
45
- if @follow_symlinks
46
- ::File.stat(path).directory?
47
- else
48
- ::File.lstat(path).directory?
49
- end
50
- end
51
-
52
- def allowed?(path)
40
+ def allowed?(path, directory: nil, content: nil)
53
41
  full_path = ::File.expand_path(path, @root)
54
42
  return false unless full_path.start_with?(@root)
55
- return false if directory?(full_path)
43
+ return false if directory.nil? ? directory?(full_path) : directory
56
44
 
57
45
  relative_path = full_path.delete_prefix(@root)
58
46
  filename = ::File.basename(relative_path)
59
47
 
60
- @rule_sets.all? { |r| r.allowed_recursive?(relative_path, false, full_path, filename) }
48
+ @rule_sets.all? { |r| r.allowed_recursive?(relative_path, false, full_path, filename, content) }
61
49
  rescue ::Errno::ENOENT, ::Errno::EACCES, ::Errno::ENOTDIR, ::Errno::ELOOP, ::Errno::ENAMETOOLONG
62
50
  false
63
51
  end
@@ -65,6 +53,14 @@ class FastIgnore
65
53
 
66
54
  private
67
55
 
56
+ def directory?(path)
57
+ if @follow_symlinks
58
+ ::File.stat(path).directory?
59
+ else
60
+ ::File.lstat(path).directory?
61
+ end
62
+ end
63
+
68
64
  def each_recursive(parent_full_path, parent_relative_path, &block) # rubocop:disable Metrics/MethodLength
69
65
  ::Dir.each_child(parent_full_path) do |filename|
70
66
  begin
@@ -72,7 +68,7 @@ class FastIgnore
72
68
  relative_path = parent_relative_path + filename
73
69
  dir = directory?(full_path)
74
70
 
75
- next unless @rule_sets.all? { |r| r.allowed_unrecursive?(relative_path, dir, full_path, filename) }
71
+ next unless @rule_sets.all? { |r| r.allowed_unrecursive?(relative_path, dir, full_path, filename, nil) }
76
72
 
77
73
  if dir
78
74
  each_recursive(full_path + '/', relative_path + '/', &block)
@@ -2,15 +2,69 @@
2
2
 
3
3
  class FastIgnore
4
4
  module Backports
5
- module_function
5
+ ruby_major, ruby_minor = RUBY_VERSION.split('.', 2)
6
+ unless ruby_major.to_i > 2 || ruby_major.to_i == 2 && ruby_minor.to_i > 5
7
+ module DirEachChild
8
+ refine ::Dir.singleton_class do
9
+ def each_child(path, &block)
10
+ Dir.entries(path).each do |entry|
11
+ next if entry == '.' || entry == '..'
6
12
 
7
- def ruby_version_less_than?(major, minor)
8
- ruby_major, ruby_minor = RUBY_VERSION.split('.', 2)
13
+ block.call entry
14
+ end
15
+ end
16
+ end
17
+ end
9
18
 
10
- return true if major > ruby_major.to_i
11
- return true if minor > ruby_minor.to_i
19
+ module DeletePrefixSuffix
20
+ refine ::String do
21
+ # delete_prefix!(prefix) -> self or nil
22
+ # Deletes leading prefix from str, returning nil if no change was made.
23
+ #
24
+ # "hello".delete_prefix!("hel") #=> "lo"
25
+ # "hello".delete_prefix!("llo") #=> nil
26
+ def delete_prefix!(str)
27
+ return unless start_with?(str)
12
28
 
13
- false
29
+ slice!(0..(str.length - 1))
30
+ self
31
+ end
32
+
33
+ # delete_suffix!(suffix) -> self or nil
34
+ # Deletes trailing suffix from str, returning nil if no change was made.
35
+ #
36
+ # "hello".delete_suffix!("llo") #=> "he"
37
+ # "hello".delete_suffix!("hel") #=> nil
38
+ def delete_suffix!(str)
39
+ return unless end_with?(str)
40
+
41
+ slice!(-str.length..-1)
42
+ self
43
+ end
44
+
45
+ # delete_prefix(prefix) -> new_str click to toggle source
46
+ # Returns a copy of str with leading prefix deleted.
47
+ #
48
+ # "hello".delete_prefix("hel") #=> "lo"
49
+ # "hello".delete_prefix("llo") #=> "hello"
50
+ def delete_prefix(str)
51
+ s = dup
52
+ s.delete_prefix!(str)
53
+ s
54
+ end
55
+
56
+ # delete_suffix(suffix) -> new_str
57
+ # Returns a copy of str with trailing suffix deleted.
58
+ #
59
+ # "hello".delete_suffix("llo") #=> "he"
60
+ # "hello".delete_suffix("hel") #=> "hello"
61
+ def delete_suffix(str) # leftovers:allowed
62
+ s = dup
63
+ s.delete_suffix!(str)
64
+ s
65
+ end
66
+ end
67
+ end
14
68
  end
15
69
  end
16
70
  end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ class FastIgnore
4
+ module FNMatchToRegex
5
+ # This doesn't look rubyish because i ported it from rust (the only rust i ever wrote that worked)
6
+ class << self
7
+ def call(pattern) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
8
+ re = '\\A'.dup
9
+
10
+ in_character_group = false
11
+ has_characters_in_group = false
12
+ escape_next_character = false
13
+ last_char_opened_character_group = false
14
+ negated_character_group = false
15
+ stars = 0
16
+
17
+ pattern.each_char do |char| # rubocop:disable Metrics/BlockLength
18
+ if escape_next_character
19
+ re << Regexp.escape(char)
20
+ escape_next_character = false
21
+ elsif char == '\\' # single char, just needs to be escaped
22
+ escape_next_character = true
23
+ elsif in_character_group
24
+ if char == '/'
25
+ if negated_character_group
26
+ has_characters_in_group = true
27
+ re << char
28
+ end
29
+ elsif char == '^'
30
+ if last_char_opened_character_group
31
+ re << char
32
+ negated_character_group = true
33
+ else
34
+ re << '\\^'
35
+ has_characters_in_group = true
36
+ end
37
+ # not characters in group
38
+ elsif char == ']'
39
+ break unless has_characters_in_group
40
+
41
+ re << ']'
42
+ in_character_group = false
43
+ has_characters_in_group = false
44
+ negated_character_group = false
45
+ last_char_opened_character_group = false
46
+ elsif char == '-'
47
+ has_characters_in_group = true
48
+ re << char
49
+ else
50
+ has_characters_in_group = true
51
+ re << Regexp.escape(char)
52
+ end
53
+ last_char_opened_character_group = false
54
+ elsif char == '*'
55
+ stars += 1
56
+ elsif char == '/'
57
+ re << if stars >= 2
58
+ '(?:.*/)?'
59
+ elsif stars.positive?
60
+ '[^/]*/'
61
+ else
62
+ char
63
+ end
64
+ stars = 0
65
+ else
66
+ if stars.positive?
67
+ re << '[^/]*'
68
+ stars = 0
69
+ end
70
+ if char == '?'
71
+ re << '[^/]'
72
+ elsif char == '['
73
+ re << '['
74
+ in_character_group = true
75
+ last_char_opened_character_group = true
76
+ else
77
+ re << Regexp.escape(char)
78
+ end
79
+ end
80
+ end
81
+
82
+ if in_character_group
83
+ return /(?!)/ # impossible to match anything
84
+ end
85
+
86
+ if stars >= 2
87
+ re << '.*'
88
+ elsif stars.positive?
89
+ re << '[^/]*'
90
+ end
91
+ re << '\\z'
92
+ Regexp.new(re, Regexp::IGNORECASE)
93
+ end
94
+ end
95
+ end
96
+ end
@@ -2,12 +2,6 @@
2
2
 
3
3
  class FastIgnore
4
4
  class Rule
5
- # FNMATCH_OPTIONS = (
6
- # ::File::FNM_DOTMATCH |
7
- # ::File::FNM_PATHNAME |
8
- # ::File::FNM_CASEFOLD
9
- # ).freeze # = 14
10
-
11
5
  attr_reader :negation
12
6
  alias_method :negation?, :negation
13
7
  undef :negation
@@ -20,12 +14,16 @@ class FastIgnore
20
14
  alias_method :unanchored?, :unanchored
21
15
  undef :unanchored
22
16
 
23
- def initialize(rule, unanchored, dir_only, negation)
24
- @rule = rule
17
+ attr_reader :type
18
+ attr_reader :rule
19
+
20
+ def initialize(rule, negation, unanchored = nil, dir_only = nil)
21
+ @rule = rule.is_a?(Regexp) ? rule : ::FastIgnore::FNMatchToRegex.call(rule)
25
22
  @unanchored = unanchored
26
23
  @dir_only = dir_only
27
24
  @negation = negation
28
- @shebang = shebang
25
+
26
+ @type = negation ? 1 : 0
29
27
 
30
28
  freeze
31
29
  end
@@ -44,8 +42,8 @@ class FastIgnore
44
42
  end
45
43
  # :nocov:
46
44
 
47
- def match?(relative_path, _, _)
48
- ::File.fnmatch?(@rule, relative_path, 14)
45
+ def match?(relative_path, _, _, _)
46
+ @rule.match?(relative_path)
49
47
  end
50
48
  end
51
49
  end
@@ -4,10 +4,7 @@ class FastIgnore
4
4
  module RuleBuilder
5
5
  class << self
6
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
7
+ using ::FastIgnore::Backports::DeletePrefixSuffix if defined?(::FastIgnore::Backports::DeletePrefixSuffix)
11
8
  # :nocov:
12
9
 
13
10
  def build(rule, allow, expand_path, file_root)
@@ -50,8 +47,11 @@ class FastIgnore
50
47
  dir_only = extract_dir_only(rule)
51
48
  negation = extract_negation(rule, allow)
52
49
 
53
- expand_rule_path(rule, expand_path) if expand_path
54
- unanchored = unanchored?(rule)
50
+ unanchored = if expand_path
51
+ expand_rule_path(rule, expand_path)
52
+ else
53
+ unanchored?(rule)
54
+ end
55
55
  rule.delete_prefix!('/')
56
56
 
57
57
  rule.prepend("#{file_root}#{'**/' if unanchored}") if file_root || unanchored
@@ -73,7 +73,7 @@ class FastIgnore
73
73
  def expand_rule_path(rule, root)
74
74
  rule.replace(::File.expand_path(rule)) if rule.match?(EXPAND_PATH_RE)
75
75
  rule.delete_prefix!(root)
76
- rule.prepend('/') unless rule.start_with?('*') || rule.start_with?('/')
76
+ rule.start_with?('*')
77
77
  end
78
78
 
79
79
  def unanchored?(rule)
@@ -81,10 +81,10 @@ class FastIgnore
81
81
  end
82
82
 
83
83
  def build_gitignore_rules(rule, unanchored, allow, dir_only, negation)
84
- rules = [::FastIgnore::Rule.new(rule.freeze, unanchored, dir_only, negation)]
84
+ rules = [::FastIgnore::Rule.new(rule, negation, unanchored, dir_only)]
85
85
  return rules unless allow
86
86
 
87
- rules << ::FastIgnore::Rule.new("#{rule}/**/*", unanchored, false, negation)
87
+ rules << ::FastIgnore::Rule.new("#{rule}/**/*", negation, unanchored, false)
88
88
  rules + ancestor_rules(rule, unanchored)
89
89
  end
90
90
 
@@ -93,7 +93,7 @@ class FastIgnore
93
93
 
94
94
  while (parent = ::File.dirname(parent)) != '.'
95
95
  rule = ::File.basename(parent) == '**' ? "#{parent}/*" : parent.freeze
96
- ancestor_rules << ::FastIgnore::Rule.new(rule, unanchored, true, true)
96
+ ancestor_rules << ::FastIgnore::Rule.new(rule, true, unanchored, true)
97
97
  end
98
98
 
99
99
  ancestor_rules
@@ -3,39 +3,43 @@
3
3
  class FastIgnore
4
4
  class RuleSet
5
5
  def initialize(rules, allow)
6
- @dir_rules = rules.reject(&:file_only?).freeze
7
- @file_rules = rules.reject(&:dir_only?).freeze
6
+ @dir_rules = squash_rules(rules.reject(&:file_only?)).freeze
7
+ @file_rules = squash_rules(rules.reject(&:dir_only?)).freeze
8
8
  @any_not_anchored = rules.any?(&:unanchored?)
9
9
  @has_shebang_rules = rules.any?(&:shebang)
10
+
10
11
  @allowed_recursive = { '.' => true }
11
12
  @allow = allow
12
13
 
13
14
  freeze
14
15
  end
15
16
 
16
- def freeze
17
- @dir_rules.freeze
18
- @file_rules.freeze
19
-
20
- super
21
- end
22
-
23
- def allowed_recursive?(relative_path, dir, full_path, filename)
17
+ def allowed_recursive?(relative_path, dir, full_path, filename, content = nil)
24
18
  @allowed_recursive.fetch(relative_path) do
25
19
  @allowed_recursive[relative_path] =
26
- allowed_recursive?(::File.dirname(relative_path), true, nil, nil) &&
27
- allowed_unrecursive?(relative_path, dir, full_path, filename)
20
+ allowed_recursive?(::File.dirname(relative_path), true, nil, nil, nil) &&
21
+ allowed_unrecursive?(relative_path, dir, full_path, filename, content)
28
22
  end
29
23
  end
30
24
 
31
- def allowed_unrecursive?(relative_path, dir, full_path, filename)
25
+ def allowed_unrecursive?(relative_path, dir, full_path, filename, content)
32
26
  (dir ? @dir_rules : @file_rules).reverse_each do |rule|
33
- return rule.negation? if rule.match?(relative_path, full_path, filename)
27
+ return rule.negation? if rule.match?(relative_path, full_path, filename, content)
34
28
  end
35
29
 
36
30
  (not @allow) || (dir && @any_not_anchored)
37
31
  end
38
32
 
33
+ def squash_rules(rules)
34
+ out = rules.chunk_while { |a, b| a.type == b.type }.map do |chunk|
35
+ next chunk.first if chunk.length == 1
36
+
37
+ chunk.first.class.new(Regexp.union(chunk.map(&:rule)), chunk.first.negation?)
38
+ end
39
+
40
+ out
41
+ end
42
+
39
43
  def weight
40
44
  @dir_rules.length + (@has_shebang_rules ? 10 : 0)
41
45
  end
@@ -4,10 +4,7 @@ class FastIgnore
4
4
  module RuleSetBuilder
5
5
  class << self
6
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
7
+ using ::FastIgnore::Backports::DeletePrefixSuffix if defined?(::FastIgnore::Backports::DeletePrefixSuffix)
11
8
  # :nocov:
12
9
 
13
10
  def build( # rubocop:disable Metrics/ParameterLists
@@ -6,12 +6,18 @@ class FastIgnore
6
6
  alias_method :negation?, :negation
7
7
  undef :negation
8
8
 
9
- attr_reader :shebang
9
+ attr_reader :rule
10
+ alias_method :shebang, :rule
10
11
 
11
- def initialize(shebang, negation)
12
- @shebang = shebang
12
+ attr_reader :type
13
+
14
+ def initialize(rule, negation)
15
+ @rule = rule
13
16
  @negation = negation
14
17
 
18
+ @type = 2
19
+ @type += 1 if negation
20
+
15
21
  freeze
16
22
  end
17
23
 
@@ -29,14 +35,14 @@ class FastIgnore
29
35
 
30
36
  # :nocov:
31
37
  def inspect
32
- "#<ShebangRule #{'allow ' if @negation}#!:#{@shebang.to_s[15..-4]}>"
38
+ "#<ShebangRule #{'allow ' if @negation}#!:#{@rule.to_s[15..-4]}>"
33
39
  end
34
40
  # :nocov:
35
41
 
36
- def match?(_, full_path, filename)
42
+ def match?(_, full_path, filename, content)
37
43
  return false if filename.include?('.')
38
44
 
39
- first_line(full_path)&.match?(@shebang)
45
+ (content || first_line(full_path))&.match?(@rule)
40
46
  end
41
47
 
42
48
  private
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class FastIgnore
4
- VERSION = '0.10.2'
4
+ VERSION = '0.11.0'
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.2
4
+ version: 0.11.0
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-26 00:00:00.000000000 Z
11
+ date: 2020-05-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -165,8 +165,7 @@ files:
165
165
  - fast_ignore.gemspec
166
166
  - lib/fast_ignore.rb
167
167
  - lib/fast_ignore/backports.rb
168
- - lib/fast_ignore/backports/delete_prefix_suffix.rb
169
- - lib/fast_ignore/backports/dir_each_child.rb
168
+ - lib/fast_ignore/fn_match_to_re.rb
170
169
  - lib/fast_ignore/rule.rb
171
170
  - lib/fast_ignore/rule_builder.rb
172
171
  - lib/fast_ignore/rule_set.rb
@@ -1,56 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This is a backport of ruby 2.5's delete_prefix/delete_suffix methods
4
- class FastIgnore
5
- module Backports
6
- module DeletePrefixSuffix
7
- refine ::String do
8
- # delete_prefix!(prefix) -> self or nil
9
- # Deletes leading prefix from str, returning nil if no change was made.
10
- #
11
- # "hello".delete_prefix!("hel") #=> "lo"
12
- # "hello".delete_prefix!("llo") #=> nil
13
- def delete_prefix!(str)
14
- return unless start_with?(str)
15
-
16
- slice!(0..(str.length - 1))
17
- self
18
- end
19
-
20
- # delete_suffix!(suffix) -> self or nil
21
- # Deletes trailing suffix from str, returning nil if no change was made.
22
- #
23
- # "hello".delete_suffix!("llo") #=> "he"
24
- # "hello".delete_suffix!("hel") #=> nil
25
- def delete_suffix!(str)
26
- return unless end_with?(str)
27
-
28
- slice!(-str.length..-1)
29
- self
30
- end
31
-
32
- # delete_prefix(prefix) -> new_str click to toggle source
33
- # Returns a copy of str with leading prefix deleted.
34
- #
35
- # "hello".delete_prefix("hel") #=> "lo"
36
- # "hello".delete_prefix("llo") #=> "hello"
37
- def delete_prefix(str)
38
- s = dup
39
- s.delete_prefix!(str)
40
- s
41
- end
42
-
43
- # delete_suffix(suffix) -> new_str
44
- # Returns a copy of str with trailing suffix deleted.
45
- #
46
- # "hello".delete_suffix("llo") #=> "he"
47
- # "hello".delete_suffix("hel") #=> "hello"
48
- def delete_suffix(str) # leftovers:allowed
49
- s = dup
50
- s.delete_suffix!(str)
51
- s
52
- end
53
- end
54
- end
55
- end
56
- end
@@ -1,18 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- # This is a backport of ruby 2.5's each_child method
4
- class FastIgnore
5
- module Backports
6
- module DirEachChild
7
- refine ::Dir.singleton_class do
8
- def each_child(path, &block)
9
- Dir.entries(path).each do |entry|
10
- next if entry == '.' || entry == '..'
11
-
12
- block.call entry
13
- end
14
- end
15
- end
16
- end
17
- end
18
- end