degem 0.1.0 → 0.3.0

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: 99c4e8766d6d3f8e6f710e2e13c0e0007190617fff3f83d198b469f0aec2ffb9
4
- data.tar.gz: 4df2c08f44fc1eb1c694a85ae55d36421f4610bb717f3789eb8b5feb93c726e3
3
+ metadata.gz: 683ca7f47acea423692062935b4ccd5285e5aa764a12883a4f34237af7be248a
4
+ data.tar.gz: 1a9a8e898b9f4afcd1668b65a0ebc2b7928a84efa6c31e263c237114fa0a2069
5
5
  SHA512:
6
- metadata.gz: 26145f7a46f9b9a3152092ba4fa7065261630b66c5edf443d7e90d1eff1c88264814edefc3048d73c39b24cb7a7e9709114baf5959133de351b841967f17fba0
7
- data.tar.gz: 5f3d721a7bf24c8541f93d5a67672ca71f8bfa7550a11822af4e214d6e338d905b9a4f8a3324457593de276c88cbb18eaf10af910faa8470a9abca9096787eca
6
+ metadata.gz: b8e874de8d90b2a2e833b1685938ce9302426c3af5acf8e60bcf26cb0dab994a1520173269a366969018e69fb1abba74f1c4900235a0f7051739073a3962f70d
7
+ data.tar.gz: 6c19cd8a7e75ef66396e4dc209a14b77765e323804952769cd30a0d9267abb15bf9388ab58ee3f22002320585bb211f80d9d0e86163c7ac0a6b50e992b046cb6
data/lib/degem/cli.rb CHANGED
@@ -9,33 +9,29 @@ module Degem
9
9
  end
10
10
 
11
11
  def initialize(stderr)
12
- @stderr = stderr
12
+ Degem.stderr = stderr
13
13
  end
14
14
 
15
15
  def call
16
16
  unless gemfile_exists?
17
- @stderr.puts "Gemfile not found in the current directory"
17
+ Degem.stderr.puts "Gemfile not found in the current directory"
18
18
  return 1
19
19
  end
20
20
 
21
21
  unused = find_unused.call
22
22
  decorated = decorate_rubygems.call(unused)
23
- Report.new(@stderr).call(decorated)
23
+ Report.new.call(decorated)
24
24
  0
25
25
  end
26
26
 
27
27
  private
28
28
 
29
29
  def find_unused
30
- FindUnused.new(
31
- gemfile_path: GEMFILE,
32
- gem_specification: Gem::Specification,
33
- grep: Grep.new(@stderr)
34
- )
30
+ FindUnused.new(gemfile_path: GEMFILE)
35
31
  end
36
32
 
37
33
  def decorate_rubygems
38
- DecorateRubygems.new(
34
+ DecorateUnusedGems.new(
39
35
  gem_specification: Gem::Specification,
40
36
  git_adapter: GitAdapter.new
41
37
  )
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Degem
4
- class DecorateRubygems
4
+ class DecorateUnusedGems
5
5
  def initialize(gem_specification:, git_adapter:)
6
6
  @gem_specification = gem_specification
7
7
  @git_adapter = git_adapter
@@ -11,7 +11,7 @@ module Degem
11
11
  rubygems.map do |rubygem|
12
12
  gemspec = @gem_specification.find_by_name(rubygem.name)
13
13
  git = @git_adapter.call(rubygem.name)
14
- Rubygem.new(rubygem, gemspec, git)
14
+ UnusedGem.new(rubygem, gemspec, git)
15
15
  end
16
16
  end
17
17
  end
@@ -2,16 +2,16 @@
2
2
 
3
3
  module Degem
4
4
  class FindUnused
5
- def initialize(gemfile_path:, gem_specification:, grep: Grep.new, bundle_paths: GitLsFiles.new)
5
+ def initialize(gemfile_path:, gem_specification: Gem::Specification, bundle_paths: GitLsFiles.new)
6
6
  @gemfile_path = gemfile_path
7
7
  @gem_specification = gem_specification
8
- @grep = grep
9
- @bundle_paths = bundle_paths.call(File.dirname(gemfile_path))
8
+ fallback = Dir.glob(File.join(File.dirname(gemfile_path), "**/*.rb"))
9
+ @bundle_paths = bundle_paths.call(fallback)
10
10
  end
11
11
 
12
12
  def call
13
13
  rubygems = gemfile.rubygems.reject { _1.name == "degem" }
14
- rubygems = reject_railties(rubygems) if rails?
14
+ rubygems = reject_railties(rubygems) if gemfile.rails?
15
15
  reject_used(rubygems)
16
16
  end
17
17
 
@@ -20,162 +20,36 @@ module Degem
20
20
  attr_reader :gemfile_path
21
21
 
22
22
  def reject_railties(rubygems)
23
- rubygems
24
- .reject { _1.name == "rails" }
25
- .reject do |rubygem|
26
- gem_path = @gem_specification.find_by_name(rubygem.name).full_gem_path
27
- @grep.match?(/(Rails::Railtie|Rails::Engine)/, gem_path)
28
- end
23
+ rubygems.reject(&:rails?).reject(&:railtie?)
29
24
  end
30
25
 
31
26
  def reject_used(rubygems)
32
- candidates = rubygems.map { Matcher.new(rubygem: _1, matchers: matchers) }
33
- @grep.inverse_many(candidates, @bundle_paths).map(&:rubygem)
34
- end
35
-
36
- def matchers
37
- [
38
- method(:based_on_top_module),
39
- method(:based_on_top_composite_module_dash),
40
- method(:based_on_top_composite_module_underscore),
41
- method(:based_on_top_call),
42
- method(:based_on_top_composite_call_dash),
43
- method(:based_on_top_composite_call_underscore),
44
- method(:based_on_require),
45
- method(:based_on_require_prefix_path),
46
- method(:based_on_require_path)
47
- ].compact
48
- end
49
-
50
- def gemfile
51
- @gemfile ||= ParseGemfile.new.call(gemfile_path)
52
- end
53
-
54
- def rails?
55
- @rails ||= gemfile.rails?
56
- end
57
-
58
- # gem foo -> Foo:: (but not XFoo:: or X::Foo)
59
- def based_on_top_module(rubygem, line)
60
- return false if rubygem.name.include?("-")
61
-
62
- regex = %r{
63
- (?<!\w::) # Do not match if :: before
64
- (?<!\w) # Do not match if \w before
65
- #{rubygem.name.capitalize}
66
- ::
67
- }x
68
- regex.match?(line)
69
- end
70
-
71
- # gem foo_bar -> FooBar (but not XFooBar or X::FooBar)
72
- def based_on_top_composite_module_underscore(rubygem, line)
73
- return false unless rubygem.name.include?("_")
74
-
75
- regex = %r{
76
- (?<!\w::) # Do not match if :: before
77
- (?<!\w) # Do not match if \w before
78
- #{rubygem.name.split("_").map(&:capitalize).join}
79
- ::
80
- }x
81
- regex.match?(line)
82
- end
83
-
84
- # gem foo-bar -> Foo::Bar (but not XFoo::Bar or X::Foo::Bar)
85
- def based_on_top_composite_module_dash(rubygem, line)
86
- return false unless rubygem.name.include?("-")
87
-
88
- regex = %r{
89
- (?<!\w::) # Do not match if :: before
90
- (?<!\w) # Do not match if \w before
91
- #{rubygem.name.split("-").map(&:capitalize).join("::")}
92
- }x
93
- regex.match?(line)
94
- end
95
-
96
- # gem foo -> Foo. (but not X::Foo. or XBar.)
97
- def based_on_top_call(rubygem, line)
98
- return false if rubygem.name.include?("-")
99
-
100
- regex = %r{
101
- (?<!\w::) # Do not match if :: before
102
- (?<!\w) # Do not match if \w before
103
- #{rubygem.name.capitalize}
104
- \.
105
- }x
106
- regex.match?(line)
107
- end
108
-
109
- # gem foo-bar -> FooBar. (but not X::FooBar. or XFooBar.)
110
- def based_on_top_composite_call_dash(rubygem, line)
111
- return false unless rubygem.name.include?("-")
112
-
113
- regex = %r{
114
- (?<!\w::) # Do not match if :: before
115
- (?<!\w) # Do not match if \w before
116
- #{rubygem.name.split("-").map(&:capitalize).join}
117
- \.
118
- }x
119
- regex.match?(line)
27
+ bundle = ParseRuby.new.call(@bundle_paths)
28
+ rubygems = reject_required(rubygems, bundle.requires)
29
+ reject_consts(rubygems, bundle.consts)
120
30
  end
121
31
 
122
- # gem foo_bar -> FooBar. (but not X::FooBar. or XFooBar.)
123
- def based_on_top_composite_call_underscore(rubygem, line)
124
- return false unless rubygem.name.include?("_")
125
-
126
- regex = %r{
127
- (?<!\w::) # Do not match if :: before
128
- (?<!\w) # Do not match if \w before
129
- #{rubygem.name.split("_").map(&:capitalize).join}
130
- \.
131
- }x
132
- regex.match?(line)
133
- end
134
-
135
- # gem foo-bar -> require 'foo-bar'
136
- def based_on_require(rubygem, line)
137
- regex = %r{
138
- ^
139
- \s*
140
- require
141
- \s+
142
- ['"]
143
- #{rubygem.name}
144
- ['"]
145
- }x
146
- regex.match?(line)
32
+ def reject_consts(rubygems, bundle_consts)
33
+ rubygems.reject do |rubygem|
34
+ rubygem.own_consts.any? do |own_const|
35
+ bundle_consts.include?(own_const)
36
+ end
37
+ end
147
38
  end
148
39
 
149
- # gem foo-bar -> require 'foo/bar'
150
- def based_on_require_path(rubygem, line)
151
- return false unless rubygem.name.include?("-")
40
+ def reject_required(rubygems, bundle_requires)
41
+ rubygems.reject do |rubygem|
42
+ bundle_requires.any? do |bundle_require|
43
+ next true if bundle_require == rubygem.name
44
+ next true if bundle_require == rubygem.name.tr("-", "/")
152
45
 
153
- regex = %r{
154
- ^
155
- \s*
156
- require
157
- \s+
158
- ['"]
159
- #{rubygem.name.tr("-", "/")} # match foo/bar when rubygem is foo-bar
160
- ['"]
161
- }x
162
- regex.match?(line)
46
+ bundle_require.start_with?("#{rubygem.name}/")
47
+ end
48
+ end
163
49
  end
164
50
 
165
- # gem foo -> require 'foo/'
166
- def based_on_require_prefix_path(rubygem, line)
167
- return false if rubygem.name.include?("-")
168
-
169
- regex = %r{
170
- ^
171
- \s*
172
- require
173
- \s+
174
- ['"]
175
- #{rubygem.name}
176
- /
177
- }x
178
- regex.match?(line)
51
+ def gemfile
52
+ @gemfile ||= ParseGemfile.new(@gem_specification).call(gemfile_path)
179
53
  end
180
54
  end
181
55
  end
data/lib/degem/gemfile.rb CHANGED
@@ -2,22 +2,28 @@
2
2
 
3
3
  module Degem
4
4
  class Gemfile
5
- def initialize(dsl)
5
+ def initialize(dsl:, gem_specification:)
6
6
  @dsl = dsl
7
+ @gem_specification = gem_specification
7
8
  end
8
9
 
9
10
  def rubygems
10
- @rubygems ||= (gemfile_dependencies + gemspec_dependencies).uniq
11
+ @rubygems ||=
12
+ (gemfile_dependencies + gemspec_dependencies)
13
+ .map { Rubygem.new(rubygem: _1, gem_specification: @gem_specification) }
14
+ .uniq
11
15
  end
12
16
 
13
17
  def rails?
14
- @rails ||= rubygems.map(&:name).include?("rails")
18
+ !!rubygems.find(&:rails?)
15
19
  end
16
20
 
17
21
  private
18
22
 
19
23
  def gemfile_dependencies
20
- @dsl.dependencies.select(&:should_include?)
24
+ @dsl.dependencies.select(&:should_include?).reject do |dependency|
25
+ @dsl.gemspecs.flat_map(&:name).include?(dependency.name)
26
+ end
21
27
  end
22
28
 
23
29
  def gemspec_dependencies
@@ -2,10 +2,14 @@
2
2
 
3
3
  module Degem
4
4
  class ParseGemfile
5
+ def initialize(gem_specification = Gem::Specification)
6
+ @gem_specification = gem_specification
7
+ end
8
+
5
9
  def call(gemfile_path)
6
10
  dsl = Bundler::Dsl.new
7
11
  dsl.eval_gemfile(gemfile_path)
8
- Gemfile.new(dsl)
12
+ Gemfile.new(dsl: dsl, gem_specification: @gem_specification)
9
13
  end
10
14
 
11
15
  private
@@ -0,0 +1,117 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Degem
4
+ class ParseRuby
5
+ def initialize(visitor = Visitor)
6
+ @visitor = visitor
7
+ end
8
+
9
+ def call(path)
10
+ visitor = @visitor.new
11
+ Array(path).each do |path|
12
+ visitor.path = path
13
+ Prism.parse_file(path).value.accept(visitor)
14
+ Degem.stderr.putc "."
15
+ end
16
+ visitor
17
+ end
18
+ end
19
+
20
+ require "prism"
21
+
22
+ class Visitor < Prism::Visitor
23
+ def initialize
24
+ @requires = Set.new
25
+ @paths = Set.new
26
+ @classes = Set.new
27
+ @modules = Set.new
28
+ @path = nil
29
+ @stack = []
30
+ super
31
+ end
32
+
33
+ def requires = @requires.to_a
34
+ def consts = (@paths.union(@classes).union(@modules)).to_a
35
+ def paths = @paths.to_a
36
+ def classes = @classes.to_a
37
+ def modules = @modules.to_a
38
+ attr_writer :path
39
+
40
+ def visit_call_node(node)
41
+ visit_require_call_node(node)
42
+ super
43
+ end
44
+
45
+ def visit_module_node(node)
46
+ @stack.push(node)
47
+ super
48
+ @modules.add(@stack.map(&:name).join("::"))
49
+ @stack.pop
50
+ end
51
+
52
+ def visit_class_node(node)
53
+ @stack.push(node)
54
+ super
55
+ @stack.pop
56
+ *modules, klass = node.constant_path.full_name_parts rescue [[], node.name]
57
+ @modules.add((@stack.map(&:name) + modules).join("::")) if modules.any?
58
+ @classes.add((@stack.map(&:name) + modules + [klass]).join("::"))
59
+ end
60
+
61
+ def visit_constant_path_node(node)
62
+ paths_from(node).each { @paths.add(_1) }
63
+ super
64
+ end
65
+
66
+ def visit_constant_read_node(node)
67
+ @paths.add(node.name.to_s) unless @stack.find { _1.constant_path == node }
68
+ super
69
+ end
70
+
71
+ private
72
+
73
+ def visit_require_call_node(node)
74
+ return if node.name.to_s != "require"
75
+ return if node.receiver
76
+ return unless node.arguments
77
+ return unless node.arguments.arguments[0].is_a?(Prism::StringNode)
78
+
79
+ required = node.arguments.arguments[0].unescaped
80
+ @requires.add(required)
81
+ end
82
+
83
+ def from_ancestor_to(node)
84
+ acc = [node]
85
+ node = node.respond_to?(:parent) && node.parent
86
+ while node
87
+ acc.prepend(node)
88
+ node = node.respond_to?(:parent) && node.parent
89
+ end
90
+ acc
91
+ end
92
+
93
+ def paths_from(node)
94
+ from_ancestor_to(node)
95
+ .filter_map { _1.respond_to?(:name) ? _1.name.to_s : nil }
96
+ .tap { _1.singleton_class.include(Scan) }
97
+ .scan { |a, b| [a, b].join("::") }
98
+ end
99
+ end
100
+
101
+ module Scan
102
+ def scan(init = nil)
103
+ if init.nil?
104
+ init = self[0]
105
+ xs = self[1..] || []
106
+ else
107
+ xs = self
108
+ end
109
+
110
+ return self if xs.empty?
111
+
112
+ xs.reduce([init]) do |acc, x|
113
+ acc + [yield(acc.last, x)]
114
+ end
115
+ end
116
+ end
117
+ end
data/lib/degem/report.rb CHANGED
@@ -2,21 +2,17 @@
2
2
 
3
3
  module Degem
4
4
  class Report
5
- def initialize(stderr)
6
- @stderr = stderr
7
- end
8
-
9
5
  def call(rubygems)
10
- @stderr.puts
11
- @stderr.puts
12
- @stderr.puts "The following gems may be unused:"
13
- @stderr.puts
6
+ Degem.stderr.puts
7
+ Degem.stderr.puts
8
+ Degem.stderr.puts "The following gems may be unused (#{rubygems.size}):"
9
+ Degem.stderr.puts
14
10
 
15
11
  rubygems.each do |rubygem|
16
12
  gem_name(rubygem)
17
- @stderr.puts
13
+ Degem.stderr.puts
18
14
  commits(rubygem)
19
- @stderr.puts
15
+ Degem.stderr.puts
20
16
  end
21
17
  end
22
18
 
@@ -30,15 +26,15 @@ module Degem
30
26
  "#{rubygem.name}: #{rubygem.source_code_uri}"
31
27
  end
32
28
 
33
- @stderr.puts(heading)
34
- @stderr.puts("=" * heading.size)
29
+ Degem.stderr.puts(heading)
30
+ Degem.stderr.puts("=" * heading.size)
35
31
  end
36
32
 
37
33
  def commits(rubygem)
38
34
  rubygem.commits.each.with_index do |commit, i|
39
- @stderr.puts("#{commit.hash[0..6]} (#{commit.date}) #{commit.title}")
40
- @stderr.puts(commit.url)
41
- @stderr.puts if i + 1 == rubygem.commits.size
35
+ Degem.stderr.puts("#{commit.hash[0..6]} (#{commit.date}) #{commit.title}")
36
+ Degem.stderr.puts(commit.url)
37
+ Degem.stderr.puts if i + 1 == rubygem.commits.size
42
38
  end
43
39
  end
44
40
  end
data/lib/degem/rubygem.rb CHANGED
@@ -1,16 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "delegate"
4
+
3
5
  module Degem
4
- class Rubygem < MultiDelegator
5
- attr_reader :commits
6
+ class Rubygem < SimpleDelegator
7
+ def initialize(rubygem:, gem_specification:)
8
+ @gem_specification = gem_specification
9
+ super(rubygem)
10
+ end
11
+
12
+ def rails?
13
+ name == "rails"
14
+ end
6
15
 
7
- def initialize(_, _, commits)
8
- super
9
- @commits = commits
16
+ def railtie?
17
+ parsed.consts.grep(/Rails::Railtie|Rails::Engine/).any?
10
18
  end
11
19
 
12
- def source_code_uri
13
- metadata["source_code_uri"] || homepage
20
+ def own_consts
21
+ variations = [
22
+ name,
23
+ name.delete("_-"),
24
+ name.gsub("_", "::"),
25
+ name.gsub("-", "::"),
26
+ *name.split("_").each_cons(2).to_a.map { _1.join("::") },
27
+ *name.split("_").each_cons(2).to_a.map(&:join),
28
+ *name.split("-").each_cons(2).to_a.map { _1.join("::") },
29
+ *name.split("-").each_cons(2).to_a.map(&:join)
30
+ ]
31
+
32
+ parsed.classes + (parsed.modules + parsed.paths).filter do |const|
33
+ variations.any? { |variation| const.downcase == variation.downcase }
34
+ end
35
+ end
36
+
37
+ private
38
+
39
+ def parsed
40
+ @parsed ||=
41
+ begin
42
+ gem_path = @gem_specification.find_by_name(name).full_gem_path
43
+ paths = Dir.glob(File.join(gem_path, "**", "lib", "**/*.rb"))
44
+ ParseRuby.new.call(paths)
45
+ end
14
46
  end
15
47
  end
16
48
  end
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Degem
4
- class Rubygem < MultiDelegator
4
+ class UnusedGem < MultiDelegator
5
5
  attr_reader :commits
6
6
 
7
7
  def initialize(_, _, commits)
data/lib/degem/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Degem
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/degem.rb CHANGED
@@ -2,18 +2,25 @@
2
2
 
3
3
  require_relative "degem/version"
4
4
  require_relative "degem/gemfile"
5
+ require_relative "degem/rubygem"
5
6
  require_relative "degem/parse_gemfile"
6
- require_relative "degem/grep"
7
7
  require_relative "degem/git_ls_files"
8
- require_relative "degem/matcher"
8
+ require_relative "degem/parse_ruby"
9
9
  require_relative "degem/find_unused"
10
10
  require_relative "degem/multi_delegator"
11
- require_relative "degem/rubygem"
12
- require_relative "degem/decorate_rubygems"
11
+ require_relative "degem/unused_gem"
12
+ require_relative "degem/decorate_unused_gems"
13
13
  require_relative "degem/commit"
14
14
  require_relative "degem/git_adapter"
15
15
  require_relative "degem/report"
16
16
  require_relative "degem/cli"
17
17
 
18
18
  module Degem
19
+ class << self
20
+ attr_writer :stderr
21
+
22
+ def stderr
23
+ @stderr ||= $stderr
24
+ end
25
+ end
19
26
  end
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: degem
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - 3v0k4
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2024-12-05 00:00:00.000000000 Z
12
- dependencies: []
11
+ date: 2024-12-20 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: prism
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.2'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.2'
13
27
  description: Degem finds unused gems in the Ruby bundle (ie, an app with a `Gemfile`
14
28
  or a gem with both a `Gemfile` and a gemspec).
15
29
  email:
@@ -23,18 +37,17 @@ files:
23
37
  - lib/degem.rb
24
38
  - lib/degem/cli.rb
25
39
  - lib/degem/commit.rb
26
- - lib/degem/decorate_rubygems.rb
27
- - lib/degem/decorated.rb
40
+ - lib/degem/decorate_unused_gems.rb
28
41
  - lib/degem/find_unused.rb
29
42
  - lib/degem/gemfile.rb
30
43
  - lib/degem/git_adapter.rb
31
44
  - lib/degem/git_ls_files.rb
32
- - lib/degem/grep.rb
33
- - lib/degem/matcher.rb
34
45
  - lib/degem/multi_delegator.rb
35
46
  - lib/degem/parse_gemfile.rb
47
+ - lib/degem/parse_ruby.rb
36
48
  - lib/degem/report.rb
37
49
  - lib/degem/rubygem.rb
50
+ - lib/degem/unused_gem.rb
38
51
  - lib/degem/version.rb
39
52
  homepage: https://github.com/3v0k4/degem
40
53
  licenses:
data/lib/degem/grep.rb DELETED
@@ -1,42 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "find"
4
-
5
- module Degem
6
- class Grep
7
- def initialize(stderr = StringIO.new)
8
- @stderr = stderr
9
- end
10
-
11
- def match?(matcher, dir)
12
- Find.find(File.expand_path(dir)) do |path|
13
- next unless File.file?(path)
14
- next if File.extname(path) != ".rb"
15
-
16
- @stderr.putc "."
17
- File.foreach(path) do |line|
18
- next unless matcher.match?(line)
19
-
20
- return true
21
- end
22
- end
23
-
24
- false
25
- end
26
-
27
- def inverse_many(matchers, paths)
28
- Find.find(*paths) do |path|
29
- next unless File.file?(path)
30
-
31
- @stderr.putc "."
32
- File.foreach(path) do |line|
33
- matchers = matchers.reject do |matcher|
34
- matcher.match?(line)
35
- end
36
- end
37
- end
38
-
39
- matchers
40
- end
41
- end
42
- end
data/lib/degem/matcher.rb DELETED
@@ -1,16 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Degem
4
- class Matcher
5
- attr_reader :rubygem
6
-
7
- def initialize(rubygem:, matchers:)
8
- @rubygem = rubygem
9
- @matchers = matchers
10
- end
11
-
12
- def match?(string)
13
- @matchers.any? { _1.call(@rubygem, string) }
14
- end
15
- end
16
- end