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
-
#enabled_preview_cop?(cop_cfg, config) ⇒ Boolean
Preview cops are opt-in and stay silent otherwise, so unlike pending cops they are never reported as needing a decision.
- #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.
375 376 377 |
# File 'lib/rubocop/cop/registry.rb', line 375 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
304 305 306 |
# File 'lib/rubocop/cop/registry.rb', line 304 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
294 295 296 |
# File 'lib/rubocop/cop/registry.rb', line 294 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
320 321 322 |
# File 'lib/rubocop/cop/registry.rb', line 320 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 |
#enabled_preview_cop?(cop_cfg, config) ⇒ Boolean
Preview cops are opt-in and stay silent otherwise, so unlike pending cops they are never reported as needing a decision.
285 286 287 |
# File 'lib/rubocop/cop/registry.rb', line 285 def enabled_preview_cop?(cop_cfg, config) cop_cfg.fetch('Enabled') == 'preview' && config.preview?(@options) 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?
326 327 328 329 330 331 332 |
# File 'lib/rubocop/cop/registry.rb', line 326 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.
337 338 339 340 |
# File 'lib/rubocop/cop/registry.rb', line 337 def find_cops_by_directive(directive) cop = find_by_cop_name(directive) cop ? [cop] : cops_for_department(directive) end |
#freeze ⇒ Object
357 358 359 360 361 362 363 364 365 366 367 368 369 370 |
# File 'lib/rubocop/cop/registry.rb', line 357 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.
347 348 349 350 351 352 353 354 355 |
# File 'lib/rubocop/cop/registry.rb', line 347 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
289 290 291 292 |
# File 'lib/rubocop/cop/registry.rb', line 289 def names clear_enrollment_queue @cops_by_badge.keys.map(&:to_s) end |
#names_for_department(department) ⇒ Object
298 299 300 301 302 |
# File 'lib/rubocop/cop/registry.rb', line 298 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
316 317 318 |
# File 'lib/rubocop/cop/registry.rb', line 316 def select(&block) cops.select(&block) end |
#sort! ⇒ Object
308 309 310 311 312 313 314 |
# File 'lib/rubocop/cop/registry.rb', line 308 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
378 379 380 |
# File 'lib/rubocop/cop/registry.rb', line 378 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 |