Class: RuboCop::Cop::Registry
- Inherits:
-
Object
- Object
- RuboCop::Cop::Registry
- Includes:
- Enumerable
- Defined in:
- lib/rubocop/cop/registry.rb
Overview
Registry that tracks all cops by their badge and department.
Class Attribute Summary collapse
-
.global ⇒ Object
readonly
Returns the value of attribute global.
Instance Attribute Summary collapse
-
#options ⇒ Object
readonly
Returns the value of attribute options.
-
#warnings ⇒ Object
readonly
Returns the value of attribute warnings.
Class Method Summary collapse
- .all ⇒ Object
- .qualified_cop?(name) ⇒ Boolean
- .qualified_cop_name(name, origin, warn: true, correct_namespace: true) ⇒ Object
- .reset! ⇒ Object
-
.with_temporary_global(temp_global = global.dup) ⇒ Object
Changes momentarily the global registry Intended for testing purposes.
Instance Method Summary collapse
- #==(other) ⇒ Object
- #contains_cop_matching?(names) ⇒ Boolean
- #cops ⇒ Object
- #cops_for_department(department) ⇒ Object
-
#department?(name) ⇒ Boolean
Checks if given name is department.
- #department_missing?(badge, name) ⇒ Boolean
-
#departments ⇒ Array<Symbol>
List of departments for current cops.
- #disabled(config) ⇒ Object
-
#disabled_names(config) ⇒ Array<String>
private
Returns the names of the disabled cops without loading any of them.
- #dismiss(cop) ⇒ Object
- #each(&block) ⇒ Object
-
#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) ⇒ Object
-
#filter_by_badge(options = {}) ⇒ Registry
private
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) ⇒ Object
When a cop name is given returns a single-element array with the cop class.
- #freeze ⇒ Object
-
#initialize(cops = [], options = {}) ⇒ Registry
constructor
A new instance of Registry.
-
#lazy_load(badge, constant_name) ⇒ Object
Registers a cop by its badge and constant name without loading the class.
- #length ⇒ Object
-
#load_all_lazy_cops ⇒ Object
private
Loads all cops that are registered for lazy loading.
- #names ⇒ Object
- #names_for_department(department) ⇒ Object
- #print_department_missing_warning(name, path) ⇒ Object
-
#qualified_cop_name(name, path, warn: true, correct_namespace: true) ⇒ String
Convert a user provided cop name into a properly namespaced name.
- #qualify_badge(badge) ⇒ Object
- #resolve_cop_name(badge, name, path, warn) ⇒ Object
- #select(&block) ⇒ Object
- #sort! ⇒ Object
- #to_h ⇒ Hash{String => Array<Class>}
- #unqualified_cop_names ⇒ Object
- #warnings?(path) ⇒ Boolean
-
#with_department(department) ⇒ Registry
Cops for that specific department.
-
#without_department(department) ⇒ Registry
Cops not for a specific department.
Constructor Details
#initialize(cops = [], options = {}) ⇒ Registry
Returns a new instance of Registry.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
# 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 ⇒ Object (readonly)
Returns the value of attribute global.
369 370 371 |
# File 'lib/rubocop/cop/registry.rb', line 369 def global @global end |
Instance Attribute Details
#options ⇒ Object (readonly)
Returns the value of attribute options.
49 50 51 |
# File 'lib/rubocop/cop/registry.rb', line 49 def @options end |
#warnings ⇒ Object (readonly)
Returns the value of attribute warnings.
49 50 51 |
# File 'lib/rubocop/cop/registry.rb', line 49 def warnings @warnings end |
Class Method Details
.all ⇒ Object
22 23 24 |
# File 'lib/rubocop/cop/registry.rb', line 22 def self.all global.without_department(:Test).cops end |
.qualified_cop?(name) ⇒ Boolean
44 45 46 47 |
# 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, correct_namespace: true) ⇒ Object
26 27 28 |
# File 'lib/rubocop/cop/registry.rb', line 26 def self.qualified_cop_name(name, origin, warn: true, correct_namespace: true) global.qualified_cop_name(name, origin, warn: warn, correct_namespace: correct_namespace) end |
.reset! ⇒ Object
40 41 42 |
# File 'lib/rubocop/cop/registry.rb', line 40 def self.reset! @global = new end |
.with_temporary_global(temp_global = global.dup) ⇒ Object
Changes momentarily the global registry Intended for testing purposes
32 33 34 35 36 37 38 |
# 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 Method Details
#==(other) ⇒ Object
298 299 300 |
# File 'lib/rubocop/cop/registry.rb', line 298 def ==(other) cops == other.cops end |
#contains_cop_matching?(names) ⇒ Boolean
138 139 140 |
# File 'lib/rubocop/cop/registry.rb', line 138 def contains_cop_matching?(names) registered_badges.any? { |badge| badge.match_name?(names) } end |
#cops ⇒ Object
230 231 232 233 234 |
# File 'lib/rubocop/cop/registry.rb', line 230 def cops clear_enrollment_queue load_all_lazy_cops @cops_by_badge.values end |
#cops_for_department(department) ⇒ Object
288 289 290 |
# File 'lib/rubocop/cop/registry.rb', line 288 def cops_for_department(department) with_department(department.to_sym).cops end |
#department?(name) ⇒ Boolean
Returns Checks if given name is department.
134 135 136 |
# File 'lib/rubocop/cop/registry.rb', line 134 def department?(name) departments.include?(name.to_sym) end |
#department_missing?(badge, name) ⇒ Boolean
196 197 198 |
# File 'lib/rubocop/cop/registry.rb', line 196 def department_missing?(badge, name) !badge.qualified? && unqualified_cop_names.include?(name) end |
#departments ⇒ Array<Symbol>
Returns list of departments for current cops.
104 105 106 107 |
# File 'lib/rubocop/cop/registry.rb', line 104 def departments clear_enrollment_queue @departments.to_a end |
#disabled(config) ⇒ Object
253 254 255 |
# File 'lib/rubocop/cop/registry.rb', line 253 def disabled(config) @disabled_cache[config] ||= reject { |cop| enabled?(cop, config) } end |
#disabled_names(config) ⇒ Array<String>
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns the names of the disabled cops without loading any of them.
261 262 263 264 265 266 |
# File 'lib/rubocop/cop/registry.rb', line 261 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) ⇒ Object
90 91 92 93 94 95 96 97 98 99 100 101 |
# 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) ⇒ Object
314 315 316 |
# File 'lib/rubocop/cop/registry.rb', line 314 def each(&block) cops.each(&block) end |
#enabled(config) ⇒ Array<Class>
Returns the enabled cop classes, loading lazy-loaded cops only when they are enabled.
244 245 246 247 248 249 250 251 |
# File 'lib/rubocop/cop/registry.rb', line 244 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
268 269 270 |
# File 'lib/rubocop/cop/registry.rb', line 268 def enabled?(cop, config) enabled_cop_name?(cop.cop_name, config) end |
#enabled_pending_cop?(cop_cfg, config, cop = nil) ⇒ Boolean
273 274 275 276 277 278 279 280 281 |
# File 'lib/rubocop/cop/registry.rb', line 273 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) ⇒ Object
86 87 88 |
# File 'lib/rubocop/cop/registry.rb', line 86 def enlist(cop) @enrollment_queue << cop end |
#filter_by_badge(options = {}) ⇒ Registry
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Returns a new registry containing the cops whose badge satisfies the given block, keeping lazy-loaded cops unloaded.
124 125 126 127 128 129 130 131 |
# 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?
320 321 322 323 324 325 326 |
# File 'lib/rubocop/cop/registry.rb', line 320 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) ⇒ Object
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.
331 332 333 334 |
# File 'lib/rubocop/cop/registry.rb', line 331 def find_cops_by_directive(directive) cop = find_by_cop_name(directive) cop ? [cop] : cops_for_department(directive) end |
#freeze ⇒ Object
351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/rubocop/cop/registry.rb', line 351 def freeze clear_enrollment_queue load_all_lazy_cops unqualified_cop_names # build cache # Freeze the structural collections as well, so that a cop class defined after # the freeze fails fast at its `enlist`/`lazy_load` call site instead of corrupting # the registry and failing much later. @cops_by_badge.freeze @departments.freeze @enrollment_queue.freeze super end |
#lazy_load(badge, constant_name) ⇒ Object
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.
75 76 77 78 79 80 81 82 83 84 |
# 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 ⇒ Object
236 237 238 239 |
# File 'lib/rubocop/cop/registry.rb', line 236 def length clear_enrollment_queue @cops_by_badge.size end |
#load_all_lazy_cops ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Loads all cops that are registered for lazy loading. Useful when lazily registered cops must not outlive the current global registry, e.g. before a temporary global registry is discarded in tests.
341 342 343 344 345 346 347 348 349 |
# File 'lib/rubocop/cop/registry.rb', line 341 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 do |badge| load_lazy_cop(badge) if @cops_by_badge[badge].is_a?(String) end end |
#names ⇒ Object
283 284 285 286 |
# File 'lib/rubocop/cop/registry.rb', line 283 def names clear_enrollment_queue @cops_by_badge.keys.map(&:to_s) end |
#names_for_department(department) ⇒ Object
292 293 294 295 296 |
# File 'lib/rubocop/cop/registry.rb', line 292 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) ⇒ Object
200 201 202 203 204 205 206 |
# File 'lib/rubocop/cop/registry.rb', line 200 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, correct_namespace: true) ⇒ String
Emits a warning if the provided name has an incorrect namespace
Convert a user provided cop name into a properly namespaced name
174 175 176 177 178 179 180 181 182 183 184 |
# File 'lib/rubocop/cop/registry.rb', line 174 def qualified_cop_name(name, path, warn: true, correct_namespace: true) badge = Badge.parse(name) print_department_missing_warning(name, path) if warn && department_missing?(badge, name) return name if registered?(badge) # A name qualified with the wrong department is returned as is when # namespace correction is not wanted, so the caller can surface the # mistake instead of silently acting on the corrected name. return name if badge.qualified? && !correct_namespace resolve_cop_name(badge, name, path, warn) end |
#qualify_badge(badge) ⇒ Object
216 217 218 219 220 221 |
# File 'lib/rubocop/cop/registry.rb', line 216 def qualify_badge(badge) clear_enrollment_queue @departments .map { |department| badge.with_department(department) } .select { |potential_badge| registered?(potential_badge) } end |
#resolve_cop_name(badge, name, path, warn) ⇒ Object
186 187 188 189 190 191 192 193 194 |
# File 'lib/rubocop/cop/registry.rb', line 186 def resolve_cop_name(badge, name, path, warn) 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 |
#select(&block) ⇒ Object
310 311 312 |
# File 'lib/rubocop/cop/registry.rb', line 310 def select(&block) cops.select(&block) end |
#sort! ⇒ Object
302 303 304 305 306 307 308 |
# File 'lib/rubocop/cop/registry.rb', line 302 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>}
224 225 226 227 228 |
# File 'lib/rubocop/cop/registry.rb', line 224 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 ⇒ Object
208 209 210 211 212 213 214 |
# File 'lib/rubocop/cop/registry.rb', line 208 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?(path) ⇒ Boolean
372 373 374 |
# File 'lib/rubocop/cop/registry.rb', line 372 def warnings?(path) @warnings[path] end |
#with_department(department) ⇒ Registry
Returns Cops for that specific department.
110 111 112 |
# File 'lib/rubocop/cop/registry.rb', line 110 def with_department(department) filter_by_badge { |badge| badge.department == department } end |
#without_department(department) ⇒ Registry
Returns Cops not for a specific department.
115 116 117 |
# File 'lib/rubocop/cop/registry.rb', line 115 def without_department(department) filter_by_badge { |badge| badge.department != department } end |