lib/spoom/deadcode/plugins/base.rb in spoom-1.2.3 vs lib/spoom/deadcode/plugins/base.rb in spoom-1.2.4
- old
+ new
@@ -15,10 +15,64 @@
class << self
extend T::Sig
# Plugins DSL
+ # Mark classes matching `names` as ignored.
+ #
+ # Names can be either strings or regexps:
+ #
+ # ~~~rb
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
+ # ignore_class_names(
+ # "Foo",
+ # "Bar",
+ # /Baz.*/,
+ # )
+ # end
+ # ~~~
+ sig { params(names: T.any(String, Regexp)).void }
+ def ignore_classes_named(*names)
+ save_names_and_patterns(names, :@ignored_class_names, :@ignored_class_patterns)
+ end
+
+ # Mark classes directly subclassing a class matching `names` as ignored.
+ #
+ # Names can be either strings or regexps:
+ #
+ # ~~~rb
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
+ # ignore_classes_inheriting_from(
+ # "Foo",
+ # "Bar",
+ # /Baz.*/,
+ # )
+ # end
+ # ~~~
+ sig { params(names: T.any(String, Regexp)).void }
+ def ignore_classes_inheriting_from(*names)
+ save_names_and_patterns(names, :@ignored_subclasses_of_names, :@ignored_subclasses_of_patterns)
+ end
+
+ # Mark constants matching `names` as ignored.
+ #
+ # Names can be either strings or regexps:
+ #
+ # ~~~rb
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
+ # ignore_class_names(
+ # "FOO",
+ # "BAR",
+ # /BAZ.*/,
+ # )
+ # end
+ # ~~~
+ sig { params(names: T.any(String, Regexp)).void }
+ def ignore_constants_named(*names)
+ save_names_and_patterns(names, :@ignored_constant_names, :@ignored_constant_patterns)
+ end
+
# Mark methods matching `names` as ignored.
#
# Names can be either strings or regexps:
#
# ~~~rb
@@ -29,25 +83,43 @@
# /baz.*/,
# )
# end
# ~~~
sig { params(names: T.any(String, Regexp)).void }
- def ignore_method_names(*names)
+ def ignore_methods_named(*names)
save_names_and_patterns(names, :@ignored_method_names, :@ignored_method_patterns)
end
+ # Mark modules matching `names` as ignored.
+ #
+ # Names can be either strings or regexps:
+ #
+ # ~~~rb
+ # class MyPlugin < Spoom::Deadcode::Plugins::Base
+ # ignore_class_names(
+ # "Foo",
+ # "Bar",
+ # /Baz.*/,
+ # )
+ # end
+ # ~~~
+ sig { params(names: T.any(String, Regexp)).void }
+ def ignore_modules_named(*names)
+ save_names_and_patterns(names, :@ignored_module_names, :@ignored_module_patterns)
+ end
+
private
sig { params(names: T::Array[T.any(String, Regexp)], names_variable: Symbol, patterns_variable: Symbol).void }
def save_names_and_patterns(names, names_variable, patterns_variable)
ignored_names = instance_variable_set(names_variable, Set.new)
ignored_patterns = instance_variable_set(patterns_variable, [])
names.each do |name|
case name
when String
- ignored_names << name
+ ignored_names << name.delete_prefix("::")
when Regexp
ignored_patterns << name
end
end
end
@@ -71,10 +143,16 @@
sig { params(indexer: Indexer, definition: Definition).void }
def on_define_accessor(indexer, definition)
# no-op
end
+ # Do not override this method, use `on_define_accessor` instead.
+ sig { params(indexer: Indexer, definition: Definition).void }
+ def internal_on_define_accessor(indexer, definition)
+ on_define_accessor(indexer, definition)
+ end
+
# Called when a class is defined.
#
# Will be called when the indexer processes a `class` node.
# Note that when this method is called, the definition for the node has already been added to the index.
# It is still possible to ignore it from the plugin:
@@ -89,10 +167,22 @@
sig { params(indexer: Indexer, definition: Definition).void }
def on_define_class(indexer, definition)
# no-op
end
+ # Do not override this method, use `on_define_class` instead.
+ sig { params(indexer: Indexer, definition: Definition).void }
+ def internal_on_define_class(indexer, definition)
+ if ignored_class_name?(definition.name)
+ definition.ignored!
+ elsif ignored_subclass?(indexer.nesting_class_superclass_name)
+ definition.ignored!
+ end
+
+ on_define_class(indexer, definition)
+ end
+
# Called when a constant is defined.
#
# Will be called when the indexer processes a `CONST =` node.
# Note that when this method is called, the definition for the node has already been added to the index.
# It is still possible to ignore it from the plugin:
@@ -107,10 +197,18 @@
sig { params(indexer: Indexer, definition: Definition).void }
def on_define_constant(indexer, definition)
# no-op
end
+ # Do not override this method, use `on_define_constant` instead.
+ sig { params(indexer: Indexer, definition: Definition).void }
+ def internal_on_define_constant(indexer, definition)
+ definition.ignored! if ignored_constant_name?(definition.name)
+
+ on_define_constant(indexer, definition)
+ end
+
# Called when a method is defined.
#
# Will be called when the indexer processes a `def` or `defs` node.
# Note that when this method is called, the definition for the node has already been added to the index.
# It is still possible to ignore it from the plugin:
@@ -124,11 +222,19 @@
# end
# end
# ~~~
sig { params(indexer: Indexer, definition: Definition).void }
def on_define_method(indexer, definition)
+ # no-op
+ end
+
+ # Do not override this method, use `on_define_method` instead.
+ sig { params(indexer: Indexer, definition: Definition).void }
+ def internal_on_define_method(indexer, definition)
definition.ignored! if ignored_method_name?(definition.name)
+
+ on_define_method(indexer, definition)
end
# Called when a module is defined.
#
# Will be called when the indexer processes a `module` node.
@@ -145,10 +251,18 @@
sig { params(indexer: Indexer, definition: Definition).void }
def on_define_module(indexer, definition)
# no-op
end
+ # Do not override this method, use `on_define_module` instead.
+ sig { params(indexer: Indexer, definition: Definition).void }
+ def internal_on_define_module(indexer, definition)
+ definition.ignored! if ignored_module_name?(definition.name)
+
+ on_define_module(indexer, definition)
+ end
+
# Called when a send is being processed
#
# ~~~rb
# class MyPlugin < Spoom::Deadcode::Plugins::Base
# def on_send(indexer, send)
@@ -163,38 +277,77 @@
sig { params(indexer: Indexer, send: Send).void }
def on_send(indexer, send)
# no-op
end
+ # Do not override this method, use `on_send` instead.
+ sig { params(indexer: Indexer, send: Send).void }
+ def internal_on_send(indexer, send)
+ on_send(indexer, send)
+ end
+
private
+ # DSL support
+
+ sig { params(name: T.nilable(String)).returns(T::Boolean) }
+ def ignored_class_name?(name)
+ return false unless name
+
+ ignored_name?(name, :@ignored_class_names, :@ignored_class_patterns)
+ end
+
+ sig { params(superclass_name: T.nilable(String)).returns(T::Boolean) }
+ def ignored_subclass?(superclass_name)
+ return false unless superclass_name
+
+ ignored_name?(superclass_name, :@ignored_subclasses_of_names, :@ignored_subclasses_of_patterns)
+ end
+
sig { params(name: String).returns(T::Boolean) }
+ def ignored_constant_name?(name)
+ ignored_name?(name, :@ignored_constant_names, :@ignored_constant_patterns)
+ end
+
+ sig { params(name: String).returns(T::Boolean) }
def ignored_method_name?(name)
ignored_name?(name, :@ignored_method_names, :@ignored_method_patterns)
end
- sig { params(const: Symbol).returns(T::Set[String]) }
- def names(const)
- self.class.instance_variable_get(const) || Set.new
+ sig { params(name: String).returns(T::Boolean) }
+ def ignored_module_name?(name)
+ ignored_name?(name, :@ignored_module_names, :@ignored_module_patterns)
end
sig { params(name: String, names_variable: Symbol, patterns_variable: Symbol).returns(T::Boolean) }
def ignored_name?(name, names_variable, patterns_variable)
names(names_variable).include?(name) || patterns(patterns_variable).any? { |pattern| pattern.match?(name) }
end
+ sig { params(const: Symbol).returns(T::Set[String]) }
+ def names(const)
+ self.class.instance_variable_get(const) || Set.new
+ end
+
sig { params(const: Symbol).returns(T::Array[Regexp]) }
def patterns(const)
self.class.instance_variable_get(const) || []
end
- sig { params(indexer: Indexer, send: Send).void }
- def reference_send_first_symbol_as_method(indexer, send)
- first_arg = send.args.first
- return unless first_arg.is_a?(SyntaxTree::SymbolLiteral)
+ # Plugin utils
- name = indexer.node_string(first_arg.value)
- indexer.reference_method(name, send.node)
+ sig { params(name: String).returns(String) }
+ def camelize(name)
+ name = T.must(name.split("::").last)
+ name = T.must(name.split("/").last)
+ name = name.gsub(/[^a-zA-Z0-9_]/, "")
+ name = name.sub(/^[a-z\d]*/, &:capitalize)
+ name = name.gsub(%r{(?:_|(/))([a-z\d]*)}) do
+ s1 = Regexp.last_match(1)
+ s2 = Regexp.last_match(2)
+ "#{s1}#{s2&.capitalize}"
+ end
+ name
end
end
end
end
end