Class: RuboCop::Cop::RSpec::UnusedLet::ScopeStack
- Inherits:
-
Object
- Object
- RuboCop::Cop::RSpec::UnusedLet::ScopeStack
- Defined in:
- lib/rubocop/cop/rspec/unused_let/scope_stack.rb,
sig/rubocop/cop/rspec/unused_let/scope_stack.rbs
Overview
The cop's traversal state: the scopes currently being descended into, innermost last. Resolves a scope's references against its ancestry as it is entered, and reports which of the scopes still on the stack are shared groups once one is left, so the cop itself is left with only lifecycle and reporting.
Instance Attribute Summary collapse
- #check_helper_specs ⇒ Boolean readonly
- #stack ⇒ Array[Scope] readonly
Instance Method Summary collapse
-
#helper_spec?(scope) ⇒ Boolean
The effective
type:is the innermost one in the group's ancestry (each scope already carries its explicit type, or:helperinferred from aspec/helperslocation). -
#ignore_helper_spec?(scope) ⇒ Boolean
A helper spec's auto-included module lives in another file and may reference any
letin scope, so every definition is treated as referenced unlessCheckHelperSpecsopts in. -
#initialize(check_helper_specs:) ⇒ ScopeStack
constructor
A new instance of ScopeStack.
-
#mark(scope) ⇒ void
Resolve
scope's references against its ancestors and mark every definition they reach. -
#mark_downward(scope) ⇒ void
A helper body in an enclosing group can reference a
letdefined here, since it runs in the example's scope. -
#mark_referenced_all(scope) ⇒ void
Treat every
letvisible inscope(its own and its ancestors') as referenced. -
#mark_upward(scope) ⇒ void
A reference made in this group, whether in an example or a helper body, reaches a
letdefined here or in an enclosing group. -
#pop ⇒ Scope?
Pop and return the innermost scope, or
nilif the stack is empty. -
#push(scope) ⇒ void
Resolve
scope's references against its ancestors, then push it as the new innermost scope. -
#shared_groups_for(scope) ⇒ Array[Scope]
The shared blocks among
scopeand the scopes still on the stack (its ancestors), in no particular order.
Constructor Details
#initialize(check_helper_specs:) ⇒ ScopeStack
Returns a new instance of ScopeStack.
14 15 16 17 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 14 def initialize(check_helper_specs:) #: void @check_helper_specs = check_helper_specs @stack = [] end |
Instance Attribute Details
#check_helper_specs ⇒ Boolean (readonly)
46 47 48 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 46 def check_helper_specs @check_helper_specs end |
#stack ⇒ Array[Scope] (readonly)
45 46 47 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 45 def stack @stack end |
Instance Method Details
#helper_spec?(scope) ⇒ Boolean
The effective type: is the innermost one in the group's
ancestry (each scope already carries its explicit type, or
:helper inferred from a spec/helpers location).
97 98 99 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 97 def helper_spec?(scope) #: bool [scope, *stack].filter_map(&:type).first == :helper end |
#ignore_helper_spec?(scope) ⇒ Boolean
A helper spec's auto-included module lives in another file and may
reference any let in scope, so every definition is treated as
referenced unless CheckHelperSpecs opts in. This judgement is
independent of shared inclusions.
86 87 88 89 90 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 86 def ignore_helper_spec?(scope) #: bool return false if check_helper_specs helper_spec?(scope) end |
#mark(scope) ⇒ void
This method returns an undefined value.
Resolve scope's references against its ancestors and mark every
definition they reach. scope is not on the stack yet, so
stack is exactly its ancestors.
53 54 55 56 57 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 53 def mark(scope) #: void mark_upward(scope) mark_downward(scope) mark_referenced_all(scope) if scope.inclusion || ignore_helper_spec?(scope) end |
#mark_downward(scope) ⇒ void
This method returns an undefined value.
A helper body in an enclosing group can reference a let defined
here, since it runs in the example's scope.
74 75 76 77 78 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 74 def mark_downward(scope) #: void scope.defined_names.each do |name| scope.mark_referenced(name) if stack.any? { _1.refs.include?(name) } end end |
#mark_referenced_all(scope) ⇒ void
This method returns an undefined value.
Treat every let visible in scope (its own and its ancestors')
as referenced. Used where references can't be fully seen from
this file: a shared inclusion, or a helper spec's auto-included
module.
107 108 109 110 111 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 107 def mark_referenced_all(scope) #: void [scope, *stack].each do |group| group.defined_names.each { group.mark_referenced(_1) } end end |
#mark_upward(scope) ⇒ void
This method returns an undefined value.
A reference made in this group, whether in an example or a helper
body, reaches a let defined here or in an enclosing group.
63 64 65 66 67 68 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 63 def mark_upward(scope) #: void (scope.refs | scope.refs_in_example).each do |name| scope.mark_referenced(name) stack.each { _1.mark_referenced(name) } end end |
#pop ⇒ Scope?
Pop and return the innermost scope, or nil if the stack is
empty.
30 31 32 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 30 def pop #: Scope? stack.pop end |
#push(scope) ⇒ void
This method returns an undefined value.
Resolve scope's references against its ancestors, then push it
as the new innermost scope.
23 24 25 26 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 23 def push(scope) #: void mark(scope) stack.push(scope) end |
#shared_groups_for(scope) ⇒ Array[Scope]
The shared blocks among scope and the scopes still on the stack
(its ancestors), in no particular order. Call once scope itself
has been popped.
39 40 41 |
# File 'lib/rubocop/cop/rspec/unused_let/scope_stack.rb', line 39 def shared_groups_for(scope) #: Array[Scope] [scope, *stack].select(&:shared?) end |