Class: RuboCop::Cop::Registry
| Relationships & Source Files | |
| Super Chains via Extension / Inclusion / Inheritance | |
|
Instance Chain:
self,
Enumerable
|
|
| Inherits: | Object |
| Defined in: | lib/rubocop/cop/registry.rb |
Overview
Registry that tracks all cops by their badge and department.
Class Attribute Summary
- .global readonly
Class Method Summary
- .all
- .new(cops = [], options = {}) ⇒ Registry constructor
- .qualified_cop?(name) ⇒ Boolean
- .qualified_cop_name(name, origin, warn: true)
- .reset!
-
.with_temporary_global(temp_global = global.dup)
Changes momentarily the global registry Intended for testing purposes.
Instance Attribute Summary
- #options readonly
- #warnings?(path) ⇒ Boolean readonly
Instance Method Summary
- #==(other)
- #contains_cop_matching?(names) ⇒ Boolean
- #cops
- #cops_for_department(department)
- #department?(name) ⇒ Boolean
- #department_missing?(badge, name) ⇒ Boolean
- #departments ⇒ Array<Symbol>
- #disabled(config)
-
#disabled_names(config) ⇒ Array<String>
Internal use only
Returns the names of the disabled cops without loading any of them.
- #dismiss(cop)
- #each(&block)
-
#enabled(config) ⇒ Array<Class>
Returns the enabled cop classes, loading lazy-loaded cops only when they are enabled.
- #enabled?(cop, config) ⇒ Boolean
- #enabled_pending_cop?(cop_cfg, config, cop = nil) ⇒ Boolean
- #enlist(cop)
-
#filter_by_badge(options = {}) ⇒ Registry
Internal use only
Returns a new registry containing the cops whose badge satisfies the given block, keeping lazy-loaded cops unloaded.
- #find_by_cop_name(cop_name) ⇒ Class?
-
#find_cops_by_directive(directive)
When a cop name is given returns a single-element array with the cop class.
- #freeze
-
#lazy_load(badge, constant_name)
Registers a cop by its badge and constant name without loading the class.
- #length
- #names
- #names_for_department(department)
- #print_department_missing_warning(name, path)
-
#qualified_cop_name(name, path, warn: true) ⇒ String
Convert a user provided cop name into a properly namespaced name.
- #qualify_badge(badge)
- #select(&block)
- #sort!
- #to_h ⇒ Hash{String => Array<Class>}
- #unqualified_cop_names
- #warnings readonly
- #with_department(department) ⇒ Registry
- #without_department(department) ⇒ Registry
- #clear_enrollment_queue private
- #emit_warning(path, message) private
- #enabled_cop_name?(cop_name, config) ⇒ Boolean private
- #initialize_copy(reg) private
- #load_all_lazy_cops private
- #load_lazy_cop(badge) ⇒ Class? private
- #registered?(badge) ⇒ Boolean private
- #registered_badges private
- #resolve_badge(given_badge, real_badge, source_path, warn: true) private
Constructor Details
.new(cops = [], options = {}) ⇒ Registry
# File 'lib/rubocop/cop/registry.rb', line 51
def initialize(cops = [], = {}) @departments = Set.new # Maps each badge to its cop class, or to the fully qualified constant name (a `String`) # when the cop is registered for lazy loading and its file is not loaded yet. # A single insertion-ordered map keeps the registration order stable no matter when # a lazy-loaded cop's file gets loaded, because reassigning an existing key preserves # its position; the cop execution order depends on this order. @cops_by_badge = {} @enrollment_queue = cops @options = @enabled_cache = {}.compare_by_identity @disabled_cache = {}.compare_by_identity @disabled_names_cache = {}.compare_by_identity @warnings = {} end
Class Attribute Details
.global (readonly)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 338
attr_reader :global
Class Method Details
.all
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 22
def self.all global.without_department(:Test).cops end
.qualified_cop?(name) ⇒ Boolean
# File 'lib/rubocop/cop/registry.rb', line 44
def self.qualified_cop?(name) badge = Badge.parse(name) global.qualify_badge(badge).first == badge end
.qualified_cop_name(name, origin, warn: true)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 26
def self.qualified_cop_name(name, origin, warn: true) global.qualified_cop_name(name, origin, warn: warn) end
.reset!
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 40
def self.reset! @global = new end
.with_temporary_global(temp_global = global.dup)
Changes momentarily the global registry Intended for testing purposes
# File 'lib/rubocop/cop/registry.rb', line 32
def self.with_temporary_global(temp_global = global.dup) previous = @global @global = temp_global yield ensure @global = previous end
Instance Attribute Details
#options (readonly)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 49
attr_reader :, :warnings
#warnings?(path) ⇒ Boolean (readonly)
[ GitHub ]
# File 'lib/rubocop/cop/registry.rb', line 341
def warnings?(path) @warnings[path] end
Instance Method Details
#==(other)
[ GitHub ]#clear_enrollment_queue (private)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 368
def clear_enrollment_queue return if @enrollment_queue.empty? @enrollment_queue.each do |cop| # Reassigning a badge that was registered for lazy loading keeps # its original position in the insertion-ordered map. @cops_by_badge[cop.badge] = cop @departments << cop.department end @enrollment_queue = [] end
#contains_cop_matching?(names) ⇒ Boolean
# File 'lib/rubocop/cop/registry.rb', line 138
def contains_cop_matching?(names) registered_badges.any? { |badge| badge.match_name?(names) } end
#cops
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 222
def cops clear_enrollment_queue load_all_lazy_cops @cops_by_badge.values end
#cops_for_department(department)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 280
def cops_for_department(department) with_department(department.to_sym).cops end
#department?(name) ⇒ Boolean
# File 'lib/rubocop/cop/registry.rb', line 134
def department?(name) departments.include?(name.to_sym) end
#department_missing?(badge, name) ⇒ Boolean
# File 'lib/rubocop/cop/registry.rb', line 188
def department_missing?(badge, name) !badge.qualified? && unqualified_cop_names.include?(name) end
#departments ⇒ Array<Symbol>
# File 'lib/rubocop/cop/registry.rb', line 104
def departments clear_enrollment_queue @departments.to_a end
#disabled(config)
[ GitHub ]
#disabled_names(config) ⇒ Array<String>
Returns the names of the disabled cops without loading any of them.
# File 'lib/rubocop/cop/registry.rb', line 253
def disabled_names(config) @disabled_names_cache[config] ||= registered_badges.filter_map do |badge| name = badge.to_s name unless enabled_cop_name?(name, config) end end
#dismiss(cop)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 90
def dismiss(cop) dismissed = !@enrollment_queue.delete(cop).nil? # A lazy-loaded cop that was not enlisted yet is dismissed by removing its registration. # Anonymous cop classes cannot have a badge. if !cop.name.nil? && @cops_by_badge[cop.badge].is_a?(String) @cops_by_badge.delete(cop.badge) dismissed = true end raise "Cop #{cop} could not be dismissed" unless dismissed end
#each(&block)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 306
def each(&block) cops.each(&block) end
#emit_warning(path, message) (private)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 441
def emit_warning(path, ) Registry.global.warnings[path] = true warn "#{PathUtil.smart_path(path)}: Warning: #{}" end
#enabled(config) ⇒ Array<Class>
Returns the enabled cop classes, loading lazy-loaded cops only when they are enabled.
# File 'lib/rubocop/cop/registry.rb', line 236
def enabled(config) @enabled_cache[config] ||= registered_badges.filter_map do |badge| next unless enabled_cop_name?(badge.to_s, config) cop_or_name = @cops_by_badge[badge] cop_or_name.is_a?(String) ? load_lazy_cop(badge) : cop_or_name end end
#enabled?(cop, config) ⇒ Boolean
# File 'lib/rubocop/cop/registry.rb', line 260
def enabled?(cop, config) enabled_cop_name?(cop.cop_name, config) end
#enabled_cop_name?(cop_name, config) ⇒ Boolean (private)
# File 'lib/rubocop/cop/registry.rb', line 385
def enabled_cop_name?(cop_name, config) return true if [:only]&.include?(cop_name) # We need to use the cop name in this case, because `for_cop` uses # caching which expects cop names or cop classes as keys. cfg = config.for_cop(cop_name) cop_enabled = cfg.fetch('Enabled') == true || enabled_pending_cop?(cfg, config, cop_name) if .fetch(:safe, false) cop_enabled && cfg.fetch('Safe', true) else cop_enabled end end
#enabled_pending_cop?(cop_cfg, config, cop = nil) ⇒ Boolean
# File 'lib/rubocop/cop/registry.rb', line 265
def enabled_pending_cop?(cop_cfg, config, cop = nil) return false if @options[:disable_pending_cops] return false unless cop_cfg.fetch('Enabled') == 'pending' return true if @options[:enable_pending_cops] return config.enabled_new_cops? unless cop cop_name = cop.is_a?(String) ? cop : cop.cop_name config.enabled_new_cop?(cop_name) end
#enlist(cop)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 86
def enlist(cop) @enrollment_queue << cop end
#filter_by_badge(options = {}) ⇒ Registry
Returns a new registry containing the cops whose badge satisfies the given block, keeping lazy-loaded cops unloaded.
# File 'lib/rubocop/cop/registry.rb', line 124
def filter_by_badge( = {}) clear_enrollment_queue copy = self.class.new([], ) @cops_by_badge.each do |badge, cop_or_name| copy.add_entry(badge, cop_or_name) if yield(badge) end copy end
#find_by_cop_name(cop_name) ⇒ Class?
# File 'lib/rubocop/cop/registry.rb', line 312
def find_by_cop_name(cop_name) clear_enrollment_queue badge = Badge.parse(cop_name) cop_or_name = @cops_by_badge[badge] cop_or_name.is_a?(String) ? load_lazy_cop(badge) : cop_or_name end
#find_cops_by_directive(directive)
When a cop name is given returns a single-element array with the cop class. When a department name is given returns an array with all the cop classes for that department.
# File 'lib/rubocop/cop/registry.rb', line 323
def find_cops_by_directive(directive) cop = find_by_cop_name(directive) cop ? [cop] : cops_for_department(directive) end
#freeze
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 328
def freeze clear_enrollment_queue load_all_lazy_cops unqualified_cop_names # build cache super end
#initialize_copy(reg) (private)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 356
def initialize_copy(reg) super @cops_by_badge = @cops_by_badge.dup @enrollment_queue = @enrollment_queue.dup @departments = @departments.dup @enabled_cache = {}.compare_by_identity @disabled_cache = {}.compare_by_identity @disabled_names_cache = {}.compare_by_identity @warnings = {} @unqualified_cop_names = nil end
#lazy_load(badge, constant_name)
Registers a cop by its badge and constant name without loading the class.
The constant is resolved (loading the cop’s file through autoload) only
when the cop class itself is needed.
# File 'lib/rubocop/cop/registry.rb', line 75
def lazy_load(badge, constant_name) badge = Badge.parse(badge) if badge.is_a?(String) # File any cops enlisted earlier first, so that the registration # order follows the call order. clear_enrollment_queue @departments << badge.department @cops_by_badge[badge] = constant_name unless @cops_by_badge[badge].is_a?(Class) end
#length
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 228
def length clear_enrollment_queue @cops_by_badge.size end
#load_all_lazy_cops (private)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 401
def load_all_lazy_cops # Take a snapshot because loading a cop can load (and thereby register) # another lazy-loaded cop, e.g. its superclass. badges = @cops_by_badge.keys badges.each { |badge| load_lazy_cop(badge) if @cops_by_badge[badge].is_a?(String) } end
#load_lazy_cop(badge) ⇒ Class? (private)
# File 'lib/rubocop/cop/registry.rb', line 410
def load_lazy_cop(badge) constant_name = @cops_by_badge[badge] return constant_name unless constant_name.is_a?(String) cop = Kernel.const_get(constant_name) if equal?(self.class.global) # Resolving the constant fires the autoload, which makes # `Base.inherited` enlist the class into the global registry. # Enrolling through the queue keeps `exclude_from_registry` honored: # a cop that dismissed itself leaves a dangling constant name behind # and is removed from the registry. clear_enrollment_queue cop_or_name = @cops_by_badge[badge] @cops_by_badge.delete(badge) if cop_or_name.is_a?(String) cop_or_name.is_a?(Class) ? cop_or_name : nil else # `Base.inherited` enlists into the global registry, not this copy. @cops_by_badge[badge] = cop end end
#names
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 275
def names clear_enrollment_queue @cops_by_badge.keys.map(&:to_s) end
#names_for_department(department)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 284
def names_for_department(department) department = department.to_sym registered_badges.filter_map { |badge| badge.to_s if badge.department == department } end
#print_department_missing_warning(name, path)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 192
def print_department_missing_warning(name, path) = "no department given for #{name}." if path.end_with?('.rb') += ' Run `rubocop -a --only Migration/DepartmentName` to fix.' end emit_warning(path, ) end
#qualified_cop_name(name, path, warn: true) ⇒ String
Emits a warning if the provided name has an incorrect namespace
Convert a user provided cop name into a properly namespaced name
# File 'lib/rubocop/cop/registry.rb', line 174
def qualified_cop_name(name, path, warn: true) badge = Badge.parse(name) print_department_missing_warning(name, path) if warn && department_missing?(badge, name) return name if registered?(badge) potential_badges = qualify_badge(badge) case potential_badges.size when 0 then name # No namespace found. Deal with it later in caller. when 1 then resolve_badge(badge, potential_badges.first, path, warn: warn) else raise AmbiguousCopName.new(badge, path, potential_badges) end end
#qualify_badge(badge)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 208
def qualify_badge(badge) clear_enrollment_queue @departments .map { |department| badge.with_department(department) } .select { |potential_badge| registered?(potential_badge) } end
#registered?(badge) ⇒ Boolean (private)
# File 'lib/rubocop/cop/registry.rb', line 446
def registered?(badge) clear_enrollment_queue @cops_by_badge.key?(badge) end
#registered_badges (private)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 380
def registered_badges clear_enrollment_queue @cops_by_badge.keys end
#resolve_badge(given_badge, real_badge, source_path, warn: true) (private)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 431
def resolve_badge(given_badge, real_badge, source_path, warn: true) if warn && !given_badge.match?(real_badge) emit_warning(source_path, "#{given_badge} has the wrong namespace - " \ "replace it with #{given_badge.with_department(real_badge.department)}") end real_badge.to_s end
#select(&block)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 302
def select(&block) cops.select(&block) end
#sort!
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 294
def sort! clear_enrollment_queue load_all_lazy_cops @cops_by_badge = @cops_by_badge.sort_by { |badge, _cop| badge.cop_name }.to_h self end
#to_h ⇒ Hash{String => Array<Class>}
# File 'lib/rubocop/cop/registry.rb', line 216
def to_h clear_enrollment_queue load_all_lazy_cops @cops_by_badge.to_h { |_badge, cop| [cop.cop_name, [cop]] } end
#unqualified_cop_names
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 200
def unqualified_cop_names clear_enrollment_queue @unqualified_cop_names ||= @cops_by_badge.keys.to_set do |badge| File.basename(badge.to_s) end << 'RedundantCopDisableDirective' end
#warnings (readonly)
[ GitHub ]# File 'lib/rubocop/cop/registry.rb', line 49
attr_reader :, :warnings
#with_department(department) ⇒ Registry
# File 'lib/rubocop/cop/registry.rb', line 110
def with_department(department) filter_by_badge { |badge| badge.department == department } end
#without_department(department) ⇒ Registry
# File 'lib/rubocop/cop/registry.rb', line 115
def without_department(department) filter_by_badge { |badge| badge.department != department } end