Class: RuboCop::Cop::RSpec::UnusedLet::ExternalDefinitions

Inherits:
Object
  • Object
show all
Defined in:
lib/rubocop/cop/rspec/unused_let/external_definitions.rb,
sig/rubocop/cop/rspec/unused_let/external_definitions.rbs

Overview

The SharedExamplePaths patterns resolved to file contents: the absolute paths they expand to, a result-cache checksum covering them, and their parsed definition maps for SharedExampleRegistry's external fallback.

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(patterns:, base_dir:, target_ruby_version:, cache: self.class.default_cache) ⇒ ExternalDefinitions

Returns a new instance of ExternalDefinitions.

RBS:

  • patterns: Array[String]

  • base_dir: String

  • target_ruby_version: Numeric

  • cache: Hash[String, cache_entry]

Parameters:

  • patterns: (Array[String])
  • base_dir: (String)
  • target_ruby_version: (Numeric)
  • cache: (Hash[String, cache_entry]) (defaults to: self.class.default_cache)


35
36
37
38
39
40
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 35

def initialize(patterns:, base_dir:, target_ruby_version:, cache: self.class.default_cache) #: void
  @patterns = patterns
  @base_dir = base_dir
  @target_ruby_version = target_ruby_version
  @cache = cache
end

Instance Attribute Details

#base_dirString (readonly)

Signature:

  • String

Returns:

  • (String)


75
76
77
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 75

def base_dir
  @base_dir
end

#cacheHash[String, cache_entry] (readonly)

Signature:

  • Hash[String, cache_entry]

Returns:

  • (Hash[String, cache_entry])


77
78
79
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 77

def cache
  @cache
end

#patternsArray[String] (readonly)

Signature:

  • Array[String]

Returns:

  • (Array[String])


74
75
76
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 74

def patterns
  @patterns
end

#target_ruby_versionNumeric (readonly)

Signature:

  • Numeric

Returns:

  • (Numeric)


76
77
78
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 76

def target_ruby_version
  @target_ruby_version
end

Class Method Details

.default_cacheHash[String, cache_entry]

Process-wide cache of the external files' definition maps, keyed by absolute path to [[mtime, size], definitions | nil]. Used as the default so a support file shared by many specs is scanned once per process, not once per spec (RuboCop builds a fresh cop instance per inspected file).

Returns:

  • (Hash[String, cache_entry])


27
28
29
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 27

def self.default_cache #: Hash[String, cache_entry]
  @default_cache ||= {}
end

Instance Method Details

#build_definitions_for(path) ⇒ SharedExampleRegistry::definition_mapping?

RBS:

  • path: String

Parameters:

  • path (String)

Returns:

  • (SharedExampleRegistry::definition_mapping, nil)


110
111
112
113
114
115
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 110

def build_definitions_for(path) #: SharedExampleRegistry::definition_mapping?
  ast = RuboCop::AST::ProcessedSource.from_file(path, target_ruby_version).ast
  ast && SharedExampleRegistry.new(ast).local_definitions
rescue RuboCop::Error, SystemCallError
  nil
end

#checksumString?

The paths' digest for RuboCop's result-cache key, which otherwise covers no project file but the inspected one. nil when there is nothing to pre-load.

Returns:

  • (String, nil)


56
57
58
59
60
61
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 56

def checksum #: String?
  found = paths
  return nil if found.empty?

  Digest::SHA1.hexdigest(found.map { file_signature(_1) }.join("\n"))
end

#definitions(excluding:) ⇒ Array[SharedExampleRegistry::definition_mapping]

The paths' definition maps, excluding excluding so the file under investigation is never indexed twice.

RBS:

  • excluding: String?

Parameters:

  • excluding: (String, nil)

Returns:

  • (Array[SharedExampleRegistry::definition_mapping])


67
68
69
70
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 67

def definitions(excluding:) #: Array[SharedExampleRegistry::definition_mapping]
  current = File.expand_path(excluding) if excluding
  paths.reject { _1 == current }.filter_map { definitions_for(_1) }
end

#definitions_for(path) ⇒ SharedExampleRegistry::definition_mapping?

The cached definition map for one external file, or nil when it cannot be read or parsed — in which case the cop stays conservative rather than crashing the run.

RBS:

  • path: String

Parameters:

  • path (String)

Returns:

  • (SharedExampleRegistry::definition_mapping, nil)


96
97
98
99
100
101
102
103
104
105
106
107
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 96

def definitions_for(path) #: SharedExampleRegistry::definition_mapping?
  stat = File.stat(path)
  key = [stat.mtime, stat.size] #: cache_key
  cached = cache[path]
  return cached.last if cached && cached.first == key

  definitions = build_definitions_for(path)
  cache[path] = [key, definitions]
  definitions
rescue SystemCallError
  nil
end

#file_signature(path) ⇒ String

path's identity for the result-cache digest. Content rather than mtime, which git does not preserve: keying on it would let a checkout discard a persisted cache wholesale. An unreadable path still gets a stable entry rather than breaking the run.

RBS:

  • path: String

Parameters:

  • path (String)

Returns:

  • (String)


85
86
87
88
89
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 85

def file_signature(path) #: String
  "#{path}:#{Digest::SHA1.file(path).hexdigest}"
rescue SystemCallError
  "#{path}:"
end

#pathsArray[String]

The absolute paths the patterns expand to, in a stable order. Not cached on the instance: a --server process outlives a run, so a cached expansion would go on ignoring later additions.

Returns:

  • (Array[String])


45
46
47
48
49
50
51
# File 'lib/rubocop/cop/rspec/unused_let/external_definitions.rb', line 45

def paths #: Array[String]
  patterns
    .flat_map { Dir.glob(File.expand_path(_1, base_dir)) }
    .map { File.expand_path(_1) }
    .uniq
    .sort
end