Class: RuboCop::Cop::VariableForce::VariableTable Private
Relationships & Source Files | |
Inherits: | Object |
Defined in: | lib/rubocop/cop/variable_force/variable_table.rb |
Overview
A VariableTable manages the lifetime of all scopes and local variables in a program. This holds scopes as stack structure, provides a way to add local variables to current scope, and find local variables by considering variable visibility of the current scope.
Class Method Summary
- .new(hook_receiver = nil) ⇒ VariableTable constructor Internal use only
Instance Method Summary
- #accessible_variables Internal use only
- #assign_to_variable(name, node) Internal use only
- #current_scope Internal use only
- #current_scope_level Internal use only
- #declare_variable(name, node) Internal use only
- #find_variable(name) Internal use only
- #invoke_hook(hook_name, *args) Internal use only
- #pop_scope Internal use only
- #push_scope(scope_node) Internal use only
- #reference_variable(name, node) Internal use only
- #scope_stack Internal use only
- #variable_exist?(name) ⇒ Boolean Internal use only
- #mark_variable_as_captured_by_block_if_so(variable) private Internal use only
Constructor Details
.new(hook_receiver = nil) ⇒ VariableTable
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 12
def initialize(hook_receiver = nil) @hook_receiver = hook_receiver end
Instance Method Details
#accessible_variables
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 113
def accessible_variables scope_stack.reverse_each.with_object([]) do |scope, variables| variables.concat(scope.variables.values) break variables unless scope.node.block_type? || scope.node.numblock_type? end end
#assign_to_variable(name, node)
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 56
def assign_to_variable(name, node) variable = find_variable(name) unless variable raise "Assigning to undeclared local variable \"#{name}\" " \ "at #{node.source_range}, #{node.inspect}" end mark_variable_as_captured_by_block_if_so(variable) variable.assign(node) end
#current_scope
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 40
def current_scope scope_stack.last end
#current_scope_level
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 44
def current_scope_level scope_stack.count end
#declare_variable(name, node)
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 48
def declare_variable(name, node) variable = Variable.new(name, node, current_scope) invoke_hook(:before_declaring_variable, variable) current_scope.variables[variable.name] = variable invoke_hook(:after_declaring_variable, variable) variable end
#find_variable(name)
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 94
def find_variable(name) name = name.to_sym scope_stack.reverse_each do |scope| variable = scope.variables[name] return variable if variable # Only block scope allows referencing outer scope variables. node = scope.node return nil unless node.block_type? || node.numblock_type? end nil end
#invoke_hook(hook_name, *args)
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 16
def invoke_hook(hook_name, *args) @hook_receiver&.send(hook_name, *args) end
#mark_variable_as_captured_by_block_if_so(variable) (private)
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 122
def mark_variable_as_captured_by_block_if_so(variable) return unless current_scope.node.block_type? || current_scope.node.numblock_type? return if variable.scope == current_scope variable.capture_with_block! end
#pop_scope
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 32
def pop_scope scope = current_scope invoke_hook(:before_leaving_scope, scope) scope_stack.pop invoke_hook(:after_leaving_scope, scope) scope end
#push_scope(scope_node)
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 24
def push_scope(scope_node) scope = Scope.new(scope_node) invoke_hook(:before_entering_scope, scope) scope_stack.push(scope) invoke_hook(:after_entering_scope, scope) scope end
#reference_variable(name, node)
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 68
def reference_variable(name, node) variable = find_variable(name) # In this code: # # foo = 1 unless foo # # (if # (lvar :foo) nil # (lvasgn :foo # (int 1))) # # Parser knows whether the foo is a variable or method invocation. # This means that if a :lvar node is shown in AST, the variable is # assumed to be already declared, even if we haven't seen any :lvasgn # or :arg node before the :lvar node. # # We don't invoke #declare_variable here otherwise # Variable#declaration_node will be :lvar node, that is actually not. # So just skip. return unless variable mark_variable_as_captured_by_block_if_so(variable) variable.reference!(node) end
#scope_stack
[ GitHub ]# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 20
def scope_stack @scope_stack ||= [] end
#variable_exist?(name) ⇒ Boolean
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 109
def variable_exist?(name) find_variable(name) end