Class: RubyLint::ConstantLoader

Inherits:
Iterator
  • Object
show all
Defined in:
lib/ruby-lint/constant_loader.rb

Overview

The ConstantLoader is an iterator class (using Iterator) that iterates over an AST and tries to load the corresponding built-in definitions. For example, if it finds a constant node for the ERB class it will apply the definitions for ERB to the ones set in #definitions.

This class also takes care of bootstrapping the target definitions so that the bare minimum definitions (e.g. Module and Object) are always available. Global variables are also bootstrapped.

Constant Summary

BOOTSTRAP_CONSTS =

Built-in definitions that should be bootstrapped.

Returns:

  • (Array)
%w{Module Class Kernel BasicObject Object}
BOOTSTRAP_GVARS =

List of global variables that should be bootstrapped.

Returns:

  • (Array)
[
  '$!', '$$', '$&', '$\'', '$*', '$+', '$,', '$-0', '$-F', '$-I', '$-K',
  '$-W', '$-a', '$-d', '$-i', '$-l', '$-p', '$-v', '$-w', '$.', '$/', '$0',
  '$:', '$;', '$<', '$=', '$>', '$?', '$@', '$DEBUG', '$FILENAME', '$KCODE',
  '$LOADED_FEATURES', '$LOAD_PATH', '$PROGRAM_NAME', '$SAFE', '$VERBOSE',
  '$\"', '$\\', '$_', '$`', '$stderr', '$stdin', '$stdout', '$~'
  # Regexp $1, $2,... $99 are lazy loaded when first used
]

Instance Attribute Summary collapse

Attributes inherited from Iterator

#arity_cache, #arity_cache Hash containing the amount of arguments for

Instance Method Summary collapse

Methods inherited from Iterator

#execute_callback, #initialize, #iterate, #skip_child_nodes!

Constructor Details

This class inherits a constructor from RubyLint::Iterator

Instance Attribute Details

#definitionsRubyLint::Definition::RubyObject (readonly)



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/ruby-lint/constant_loader.rb', line 22

class ConstantLoader < Iterator
  attr_reader :loaded, :definitions, :module_nesting

  ##
  # Built-in definitions that should be bootstrapped.
  #
  # @return [Array]
  #
  BOOTSTRAP_CONSTS = %w{Module Class Kernel BasicObject Object}

  ##
  # List of global variables that should be bootstrapped.
  #
  # @return [Array]
  #
  BOOTSTRAP_GVARS = [
    '$!', '$$', '$&', '$\'', '$*', '$+', '$,', '$-0', '$-F', '$-I', '$-K',
    '$-W', '$-a', '$-d', '$-i', '$-l', '$-p', '$-v', '$-w', '$.', '$/', '$0',
    '$:', '$;', '$<', '$=', '$>', '$?', '$@', '$DEBUG', '$FILENAME', '$KCODE',
    '$LOADED_FEATURES', '$LOAD_PATH', '$PROGRAM_NAME', '$SAFE', '$VERBOSE',
    '$\"', '$\\', '$_', '$`', '$stderr', '$stdin', '$stdout', '$~'
    # Regexp $1, $2,... $99 are lazy loaded when first used
  ]

  ##
  # Bootstraps various core definitions.
  #
  def bootstrap
    types = VariablePredicates::RUBY_CLASSES.values

    (BOOTSTRAP_CONSTS | types).each do |name|
      load_constant(name)
    end

    BOOTSTRAP_GVARS.each do |gvar|
      definitions.define_global_variable(gvar)
    end
  end

  ##
  # Bootstraps various core definitions (Fixnum, Object, etc) and loads the
  # extra constants referred in the supplied AST.
  #
  # @param [Array<RubyLint::AST::Node>] ast
  #
  def run(ast)
    ast.each { |node| iterate(node) }
  end

  ##
  # Called after a new instance of the class is created.
  #
  def after_initialize
    @loaded = Set.new
    @module_nesting = []
  end

  def on_module(node)
    name, _body = *node
    cp = ConstantPath.new(name)

    @module_nesting.push(cp.to_s)
  end

  def after_module(_node)
    @module_nesting.pop
  end

  def on_class(node)
    name, _parent, _body = *node
    cp = ConstantPath.new(name)

    @module_nesting.push(cp.to_s)
  end

  def after_class(_node)
    @module_nesting.pop
  end

  ##
  # @param [RubyLint::Node] node
  #
  def on_const(node)
    load_nested_constant(ConstantPath.new(node).to_s)
  end

  ##
  # Checks if the given constant is already loaded or not.
  #
  # @param [String] constant
  # @return [TrueClass|FalseClass]
  #
  def loaded?(constant)
    return loaded.include?(constant)
  end

  ##
  # @return [RubyLint::Definition::Registry]
  #
  def registry
    return RubyLint.registry
  end

  ##
  # Tries to load the definitions for the given constant.
  # Takes into account what modules we are in to resolve the constant name.
  #
  # @param [String] constant name, possibly unqualified
  #
  def load_nested_constant(constant)
    if constant.start_with?("::")
      constant = constant.sub(/^::/, "")
    else
      # ["A", "B", "C"] -> ["A::B::C", "A::B", "A"]
      namespaces = module_nesting.size.downto(1).map do |n|
        module_nesting.take(n).join("::")
      end

      namespaces.each do |ns|
        load_constant("#{ns}::#{constant}")
      end
    end
    load_constant(constant)
  end

  ##
  # Tries to load the definitions for the given constant.
  #
  # @param [String] constant
  #
  def load_constant(constant)
    return if loaded?(constant)

    registry.load(constant)

    return unless registry.include?(constant)

    apply(constant)
  end

  private

  ##
  # @param [String] constant
  #
  def apply(constant)
    loaded << constant

    registry.apply(constant, definitions)
  end
end

#loadedSet (readonly)

Returns Set containing the loaded constants.

Returns:

  • (Set)

    Set containing the loaded constants.



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/ruby-lint/constant_loader.rb', line 22

class ConstantLoader < Iterator
  attr_reader :loaded, :definitions, :module_nesting

  ##
  # Built-in definitions that should be bootstrapped.
  #
  # @return [Array]
  #
  BOOTSTRAP_CONSTS = %w{Module Class Kernel BasicObject Object}

  ##
  # List of global variables that should be bootstrapped.
  #
  # @return [Array]
  #
  BOOTSTRAP_GVARS = [
    '$!', '$$', '$&', '$\'', '$*', '$+', '$,', '$-0', '$-F', '$-I', '$-K',
    '$-W', '$-a', '$-d', '$-i', '$-l', '$-p', '$-v', '$-w', '$.', '$/', '$0',
    '$:', '$;', '$<', '$=', '$>', '$?', '$@', '$DEBUG', '$FILENAME', '$KCODE',
    '$LOADED_FEATURES', '$LOAD_PATH', '$PROGRAM_NAME', '$SAFE', '$VERBOSE',
    '$\"', '$\\', '$_', '$`', '$stderr', '$stdin', '$stdout', '$~'
    # Regexp $1, $2,... $99 are lazy loaded when first used
  ]

  ##
  # Bootstraps various core definitions.
  #
  def bootstrap
    types = VariablePredicates::RUBY_CLASSES.values

    (BOOTSTRAP_CONSTS | types).each do |name|
      load_constant(name)
    end

    BOOTSTRAP_GVARS.each do |gvar|
      definitions.define_global_variable(gvar)
    end
  end

  ##
  # Bootstraps various core definitions (Fixnum, Object, etc) and loads the
  # extra constants referred in the supplied AST.
  #
  # @param [Array<RubyLint::AST::Node>] ast
  #
  def run(ast)
    ast.each { |node| iterate(node) }
  end

  ##
  # Called after a new instance of the class is created.
  #
  def after_initialize
    @loaded = Set.new
    @module_nesting = []
  end

  def on_module(node)
    name, _body = *node
    cp = ConstantPath.new(name)

    @module_nesting.push(cp.to_s)
  end

  def after_module(_node)
    @module_nesting.pop
  end

  def on_class(node)
    name, _parent, _body = *node
    cp = ConstantPath.new(name)

    @module_nesting.push(cp.to_s)
  end

  def after_class(_node)
    @module_nesting.pop
  end

  ##
  # @param [RubyLint::Node] node
  #
  def on_const(node)
    load_nested_constant(ConstantPath.new(node).to_s)
  end

  ##
  # Checks if the given constant is already loaded or not.
  #
  # @param [String] constant
  # @return [TrueClass|FalseClass]
  #
  def loaded?(constant)
    return loaded.include?(constant)
  end

  ##
  # @return [RubyLint::Definition::Registry]
  #
  def registry
    return RubyLint.registry
  end

  ##
  # Tries to load the definitions for the given constant.
  # Takes into account what modules we are in to resolve the constant name.
  #
  # @param [String] constant name, possibly unqualified
  #
  def load_nested_constant(constant)
    if constant.start_with?("::")
      constant = constant.sub(/^::/, "")
    else
      # ["A", "B", "C"] -> ["A::B::C", "A::B", "A"]
      namespaces = module_nesting.size.downto(1).map do |n|
        module_nesting.take(n).join("::")
      end

      namespaces.each do |ns|
        load_constant("#{ns}::#{constant}")
      end
    end
    load_constant(constant)
  end

  ##
  # Tries to load the definitions for the given constant.
  #
  # @param [String] constant
  #
  def load_constant(constant)
    return if loaded?(constant)

    registry.load(constant)

    return unless registry.include?(constant)

    apply(constant)
  end

  private

  ##
  # @param [String] constant
  #
  def apply(constant)
    loaded << constant

    registry.apply(constant, definitions)
  end
end

#module_nestingArray<String> (readonly)

Returns:



22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
# File 'lib/ruby-lint/constant_loader.rb', line 22

class ConstantLoader < Iterator
  attr_reader :loaded, :definitions, :module_nesting

  ##
  # Built-in definitions that should be bootstrapped.
  #
  # @return [Array]
  #
  BOOTSTRAP_CONSTS = %w{Module Class Kernel BasicObject Object}

  ##
  # List of global variables that should be bootstrapped.
  #
  # @return [Array]
  #
  BOOTSTRAP_GVARS = [
    '$!', '$$', '$&', '$\'', '$*', '$+', '$,', '$-0', '$-F', '$-I', '$-K',
    '$-W', '$-a', '$-d', '$-i', '$-l', '$-p', '$-v', '$-w', '$.', '$/', '$0',
    '$:', '$;', '$<', '$=', '$>', '$?', '$@', '$DEBUG', '$FILENAME', '$KCODE',
    '$LOADED_FEATURES', '$LOAD_PATH', '$PROGRAM_NAME', '$SAFE', '$VERBOSE',
    '$\"', '$\\', '$_', '$`', '$stderr', '$stdin', '$stdout', '$~'
    # Regexp $1, $2,... $99 are lazy loaded when first used
  ]

  ##
  # Bootstraps various core definitions.
  #
  def bootstrap
    types = VariablePredicates::RUBY_CLASSES.values

    (BOOTSTRAP_CONSTS | types).each do |name|
      load_constant(name)
    end

    BOOTSTRAP_GVARS.each do |gvar|
      definitions.define_global_variable(gvar)
    end
  end

  ##
  # Bootstraps various core definitions (Fixnum, Object, etc) and loads the
  # extra constants referred in the supplied AST.
  #
  # @param [Array<RubyLint::AST::Node>] ast
  #
  def run(ast)
    ast.each { |node| iterate(node) }
  end

  ##
  # Called after a new instance of the class is created.
  #
  def after_initialize
    @loaded = Set.new
    @module_nesting = []
  end

  def on_module(node)
    name, _body = *node
    cp = ConstantPath.new(name)

    @module_nesting.push(cp.to_s)
  end

  def after_module(_node)
    @module_nesting.pop
  end

  def on_class(node)
    name, _parent, _body = *node
    cp = ConstantPath.new(name)

    @module_nesting.push(cp.to_s)
  end

  def after_class(_node)
    @module_nesting.pop
  end

  ##
  # @param [RubyLint::Node] node
  #
  def on_const(node)
    load_nested_constant(ConstantPath.new(node).to_s)
  end

  ##
  # Checks if the given constant is already loaded or not.
  #
  # @param [String] constant
  # @return [TrueClass|FalseClass]
  #
  def loaded?(constant)
    return loaded.include?(constant)
  end

  ##
  # @return [RubyLint::Definition::Registry]
  #
  def registry
    return RubyLint.registry
  end

  ##
  # Tries to load the definitions for the given constant.
  # Takes into account what modules we are in to resolve the constant name.
  #
  # @param [String] constant name, possibly unqualified
  #
  def load_nested_constant(constant)
    if constant.start_with?("::")
      constant = constant.sub(/^::/, "")
    else
      # ["A", "B", "C"] -> ["A::B::C", "A::B", "A"]
      namespaces = module_nesting.size.downto(1).map do |n|
        module_nesting.take(n).join("::")
      end

      namespaces.each do |ns|
        load_constant("#{ns}::#{constant}")
      end
    end
    load_constant(constant)
  end

  ##
  # Tries to load the definitions for the given constant.
  #
  # @param [String] constant
  #
  def load_constant(constant)
    return if loaded?(constant)

    registry.load(constant)

    return unless registry.include?(constant)

    apply(constant)
  end

  private

  ##
  # @param [String] constant
  #
  def apply(constant)
    loaded << constant

    registry.apply(constant, definitions)
  end
end

Instance Method Details

#after_class(_node) ⇒ Object



97
98
99
# File 'lib/ruby-lint/constant_loader.rb', line 97

def after_class(_node)
  @module_nesting.pop
end

#after_initializeObject

Called after a new instance of the class is created.



74
75
76
77
# File 'lib/ruby-lint/constant_loader.rb', line 74

def after_initialize
  @loaded = Set.new
  @module_nesting = []
end

#after_module(_node) ⇒ Object



86
87
88
# File 'lib/ruby-lint/constant_loader.rb', line 86

def after_module(_node)
  @module_nesting.pop
end

#apply(constant) ⇒ Object (private)

Parameters:



167
168
169
170
171
# File 'lib/ruby-lint/constant_loader.rb', line 167

def apply(constant)
  loaded << constant

  registry.apply(constant, definitions)
end

#bootstrapObject

Bootstraps various core definitions.



49
50
51
52
53
54
55
56
57
58
59
# File 'lib/ruby-lint/constant_loader.rb', line 49

def bootstrap
  types = VariablePredicates::RUBY_CLASSES.values

  (BOOTSTRAP_CONSTS | types).each do |name|
    load_constant(name)
  end

  BOOTSTRAP_GVARS.each do |gvar|
    definitions.define_global_variable(gvar)
  end
end

#load_constant(constant) ⇒ Object

Tries to load the definitions for the given constant.

Parameters:



152
153
154
155
156
157
158
159
160
# File 'lib/ruby-lint/constant_loader.rb', line 152

def load_constant(constant)
  return if loaded?(constant)

  registry.load(constant)

  return unless registry.include?(constant)

  apply(constant)
end

#load_nested_constant(constant) ⇒ Object

Tries to load the definitions for the given constant. Takes into account what modules we are in to resolve the constant name.

Parameters:

  • constant (String)

    name, possibly unqualified



131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
# File 'lib/ruby-lint/constant_loader.rb', line 131

def load_nested_constant(constant)
  if constant.start_with?("::")
    constant = constant.sub(/^::/, "")
  else
    # ["A", "B", "C"] -> ["A::B::C", "A::B", "A"]
    namespaces = module_nesting.size.downto(1).map do |n|
      module_nesting.take(n).join("::")
    end

    namespaces.each do |ns|
      load_constant("#{ns}::#{constant}")
    end
  end
  load_constant(constant)
end

#loaded?(constant) ⇒ TrueClass|FalseClass

Checks if the given constant is already loaded or not.

Parameters:

Returns:

  • (TrueClass|FalseClass)


114
115
116
# File 'lib/ruby-lint/constant_loader.rb', line 114

def loaded?(constant)
  return loaded.include?(constant)
end

#on_class(node) ⇒ Object



90
91
92
93
94
95
# File 'lib/ruby-lint/constant_loader.rb', line 90

def on_class(node)
  name, _parent, _body = *node
  cp = ConstantPath.new(name)

  @module_nesting.push(cp.to_s)
end

#on_const(node) ⇒ Object

Parameters:

  • node (RubyLint::Node)


104
105
106
# File 'lib/ruby-lint/constant_loader.rb', line 104

def on_const(node)
  load_nested_constant(ConstantPath.new(node).to_s)
end

#on_module(node) ⇒ Object



79
80
81
82
83
84
# File 'lib/ruby-lint/constant_loader.rb', line 79

def on_module(node)
  name, _body = *node
  cp = ConstantPath.new(name)

  @module_nesting.push(cp.to_s)
end

#registryRubyLint::Definition::Registry



121
122
123
# File 'lib/ruby-lint/constant_loader.rb', line 121

def registry
  return RubyLint.registry
end

#run(ast) ⇒ Object

Bootstraps various core definitions (Fixnum, Object, etc) and loads the extra constants referred in the supplied AST.

Parameters:



67
68
69
# File 'lib/ruby-lint/constant_loader.rb', line 67

def run(ast)
  ast.each { |node| iterate(node) }
end