Skip to content

Commit

Permalink
feat: more heuristics
Browse files Browse the repository at this point in the history
  • Loading branch information
name committed Dec 4, 2024
1 parent 37e9332 commit 263f04b
Show file tree
Hide file tree
Showing 2 changed files with 116 additions and 4 deletions.
36 changes: 32 additions & 4 deletions lib/degem/find_unused.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,11 @@ def reject_used(rubygems)
def matchers
[
method(:based_on_top_module),
method(:based_on_top_composite_module),
method(:based_on_top_composite_module_dash),
method(:based_on_top_composite_module_underscore),
method(:based_on_top_call),
method(:based_on_top_composite_call),
method(:based_on_top_composite_call_dash),
method(:based_on_top_composite_call_underscore),
method(:based_on_require),
method(:based_on_require_prefix_path),
method(:based_on_require_path)
Expand Down Expand Up @@ -66,8 +68,21 @@ def based_on_top_module(rubygem, line)
regex.match?(line)
end

# gem foo_bar -> FooBar (but not XFooBar or X::FooBar)
def based_on_top_composite_module_underscore(rubygem, line)
return false unless rubygem.name.include?("_")

regex = %r{
(?<!\w::) # Do not match if :: before
(?<!\w) # Do not match if \w before
#{rubygem.name.split("_").map(&:capitalize).join}
::
}x
regex.match?(line)
end

# gem foo-bar -> Foo::Bar (but not XFoo::Bar or X::Foo::Bar)
def based_on_top_composite_module(rubygem, line)
def based_on_top_composite_module_dash(rubygem, line)
return false unless rubygem.name.include?("-")

regex = %r{
Expand All @@ -92,7 +107,7 @@ def based_on_top_call(rubygem, line)
end

# gem foo-bar -> FooBar. (but not X::FooBar. or XFooBar.)
def based_on_top_composite_call(rubygem, line)
def based_on_top_composite_call_dash(rubygem, line)
return false unless rubygem.name.include?("-")

regex = %r{
Expand All @@ -104,6 +119,19 @@ def based_on_top_composite_call(rubygem, line)
regex.match?(line)
end

# gem foo_bar -> FooBar. (but not X::FooBar. or XFooBar.)
def based_on_top_composite_call_underscore(rubygem, line)
return false unless rubygem.name.include?("_")

regex = %r{
(?<!\w::) # Do not match if :: before
(?<!\w) # Do not match if \w before
#{rubygem.name.split("_").map(&:capitalize).join}
\.
}x
regex.match?(line)
end

# gem foo-bar -> require 'foo-bar'
def based_on_require(rubygem, line)
regex = %r{
Expand Down
84 changes: 84 additions & 0 deletions test/test_find_unused.rb
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,48 @@ def test_it_detects_unused_gems_based_on_the_top_module_6
end
end

def test_it_detects_unused_gems_based_on_the_top_module_7
content = "FooBar::Baz".prepend(padding).concat(padding)

with_gemfile do |gemfile_path|
bundle_install(%w[foo foobar foo-bar foo_bar bar]) do |gemspec_paths|
with_file(path: File.join("app", "services", "baz.rb"), content: content) do |f|
gem_specification = TestableGemSpecification.new(gemspec_paths)
actual = Degem::FindUnused.new(gemfile_path:, gem_specification:, bundle_paths: ->(_) { [f] }).call
assert_equal %w[foo foobar foo-bar bar], actual.map(&:name)
end
end
end
end

def test_it_detects_unused_gems_based_on_the_top_module_8
content = "XFooBar::Baz".prepend(padding).concat(padding)

with_gemfile do |gemfile_path|
bundle_install(%w[foo foobar foo-bar foo_bar bar]) do |gemspec_paths|
with_file(path: File.join("app", "services", "baz.rb"), content: content) do |f|
gem_specification = TestableGemSpecification.new(gemspec_paths)
actual = Degem::FindUnused.new(gemfile_path:, gem_specification:, bundle_paths: ->(_) { [f] }).call
assert_equal %w[foo foobar foo-bar foo_bar bar], actual.map(&:name)
end
end
end
end

def test_it_detects_unused_gems_based_on_the_top_module_9
content = "X::FooBar::Baz".prepend(padding).concat(padding)

with_gemfile do |gemfile_path|
bundle_install(%w[foo foobar foo-bar foo_bar bar]) do |gemspec_paths|
with_file(path: File.join("app", "services", "baz.rb"), content: content) do |f|
gem_specification = TestableGemSpecification.new(gemspec_paths)
actual = Degem::FindUnused.new(gemfile_path:, gem_specification:, bundle_paths: ->(_) { [f] }).call
assert_equal %w[foo foobar foo-bar foo_bar bar], actual.map(&:name)
end
end
end
end

def test_it_detects_unused_gems_based_on_the_top_call_1
content = "Foobar.new.call".prepend(padding).concat(padding)

Expand Down Expand Up @@ -168,6 +210,48 @@ def test_it_detects_unused_gems_based_on_the_top_call_5
end
end

def test_it_detects_unused_gems_based_on_the_top_call_6
content = "FooBar.baz".prepend(padding).concat(padding)

with_gemfile do |gemfile_path|
bundle_install(%w[foo foobar foo-bar foo_bar bar]) do |gemspec_paths|
with_file(path: File.join("app", "services", "baz.rb"), content: content) do |f|
gem_specification = TestableGemSpecification.new(gemspec_paths)
actual = Degem::FindUnused.new(gemfile_path:, gem_specification:, bundle_paths: ->(_) { [f] }).call
assert_equal %w[foo foobar bar], actual.map(&:name)
end
end
end
end

def test_it_detects_unused_gems_based_on_the_top_call_7
content = "XFooBar.baz".prepend(padding).concat(padding)

with_gemfile do |gemfile_path|
bundle_install(%w[foo foobar foo-bar foo_bar bar]) do |gemspec_paths|
with_file(path: File.join("app", "services", "baz.rb"), content: content) do |f|
gem_specification = TestableGemSpecification.new(gemspec_paths)
actual = Degem::FindUnused.new(gemfile_path:, gem_specification:, bundle_paths: ->(_) { [f] }).call
assert_equal %w[foo foobar foo-bar foo_bar bar], actual.map(&:name)
end
end
end
end

def test_it_detects_unused_gems_based_on_the_top_call_8
content = "X::FooBar.baz".prepend(padding).concat(padding)

with_gemfile do |gemfile_path|
bundle_install(%w[foo foobar foo-bar foo_bar bar]) do |gemspec_paths|
with_file(path: File.join("app", "services", "baz.rb"), content: content) do |f|
gem_specification = TestableGemSpecification.new(gemspec_paths)
actual = Degem::FindUnused.new(gemfile_path:, gem_specification:, bundle_paths: ->(_) { [f] }).call
assert_equal %w[foo foobar foo-bar foo_bar bar], actual.map(&:name)
end
end
end
end

def test_it_detects_unused_gems_based_on_require
content = "require 'foo-bar'".prepend(padding).concat(padding)

Expand Down

0 comments on commit 263f04b

Please sign in to comment.