Class: RuboCop::Cop::VariableForce::VariableTable Private

Inherits:
Object
  • Object
show all
Defined in:
lib/rubocop/cop/variable_force/variable_table.rb

Overview

This class is part of a private API. You should avoid using this class if possible, as it may be removed or be changed in the future.

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.

Instance Method Summary collapse

Constructor Details

#initialize(hook_receiver = nil) ⇒ VariableTable

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 instance of VariableTable.



12
13
14
# 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_variablesObject

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.



113
114
115
116
117
118
# 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) ⇒ 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.



56
57
58
59
60
61
62
63
64
65
66
# 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_scopeObject

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.



40
41
42
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 40

def current_scope
  scope_stack.last
end

#current_scope_levelObject

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.



44
45
46
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 44

def current_scope_level
  scope_stack.count
end

#declare_variable(name, node) ⇒ 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.



48
49
50
51
52
53
54
# 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) ⇒ 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.



94
95
96
97
98
99
100
101
102
103
104
105
106
107
# 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) ⇒ 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.



16
17
18
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 16

def invoke_hook(hook_name, *args)
  @hook_receiver&.send(hook_name, *args)
end

#pop_scopeObject

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.



32
33
34
35
36
37
38
# 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) ⇒ 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.



24
25
26
27
28
29
30
# 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) ⇒ 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.



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# 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_stackObject

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.



20
21
22
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 20

def scope_stack
  @scope_stack ||= []
end

#variable_exist?(name) ⇒ Boolean

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:

  • (Boolean)


109
110
111
# File 'lib/rubocop/cop/variable_force/variable_table.rb', line 109

def variable_exist?(name)
  find_variable(name)
end