Class: RubyLint::Analysis::Base

Inherits:
Iterator
  • Object
show all
Includes:
MethodEvaluation
Defined in:
lib/ruby-lint/analysis/base.rb

Overview

Base analysis class that provides various helper methods commonly used across analysis classes.

Constant Summary

SCOPES =

Array containing the callback names for which a new scope should be created.

Returns:

  • (Array<Symbol>)
[:root, :block, :class, :def, :module, :sclass]

Instance Attribute Summary collapse

Attributes inherited from Iterator

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

Class Method Summary collapse

Instance Method Summary collapse

Methods included from MethodEvaluation

#unpack_block

Methods inherited from Iterator

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

Constructor Details

This class inherits a constructor from RubyLint::Iterator

Instance Attribute Details

#configRubyLint::Configuration (readonly)



16
17
18
19
20
21
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
# File 'lib/ruby-lint/analysis/base.rb', line 16

class Base < Iterator
  include MethodEvaluation

  attr_reader :report, :vm, :config

  ##
  # Array containing the callback names for which a new scope should be
  # created.
  #
  # @return [Array<Symbol>]
  #
  SCOPES = [:root, :block, :class, :def, :module, :sclass]

  ##
  # Registers the current class in
  # {RubyLint::Configuration.available_analysis_classes}.
  #
  # @param [String] name A human friendly name of the current class.
  #
  def self.register(name)
    Configuration.available_analysis_classes[name] = self
  end

  ##
  # Returns a boolean that indicates if the analysis class should be used
  # or not.
  #
  # @param [RubyLint::AST::Node] ast
  # @param [RubyLint::VirtualMachine] vm
  # @return [TrueClass|FalseClass]
  #
  def self.analyze?(ast, vm)
    return true
  end

  ##
  # Called after a new instance of this class is created.
  #
  def after_initialize
    unless vm.is_a?(VirtualMachine)
      raise(
        ArgumentError,
        'Analysis classes require a valid RubyLint::VirtualMachine ' \
          'instance to be set using `SomeAnalysisClass.new(:vm => ...)`'
      )
    end

    @scopes = []
  end

  SCOPES.each do |type|
    define_method("on_#{type}") do |node|
      set_current_scope(node)
    end

    define_method("after_#{type}") do |node|
      set_previous_scope
    end
  end

  protected

  ##
  # Returns the current scope.
  #
  # @return [RubyLint::Definition::RubyObject]
  #
  def current_scope
    return @scopes[-1]
  end

  ##
  # @return [RubyLint::Definition::RubyObject]
  #
  def previous_scope
    return @scopes[-2]
  end

  ##
  # Sets the current scope to the definition associated with the given
  # node.
  #
  # @param [RubyLint::Node] node
  #
  def set_current_scope(node)
    unless vm.associations.key?(node)
      raise ArgumentError, "No associations for node #{node}"
    end

    @scopes << vm.associations[node]
  end

  ##
  # Sets the current scope back to the previous one.
  #
  def set_previous_scope
    @scopes.pop
  end

  ##
  # Adds an error message to the report.
  #
  # @see #add_message
  #
  def error(*args)
    add_message(:error, *args)
  end

  ##
  # Adds a warning message to the report.
  #
  # @see #add_message
  #
  def warning(*args)
    add_message(:warning, *args)
  end

  ##
  # Adds a regular informational message to the report.
  #
  # @see #add_message
  #
  def info(*args)
    add_message(:info, *args)
  end

  ##
  # Adds a message of the given level.
  #
  # @param [Symbol] level
  # @param [String] message
  # @param [String] node
  #
  def add_message(level, message, node)
    return unless report

    report.add(
      :level    => level,
      :message  => message,
      :line     => node.line,
      :column   => node.column,
      :file     => node.file,
      :node     => node
    )
  end
end

#reportRubyLint::Report (readonly)

Returns:



16
17
18
19
20
21
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
# File 'lib/ruby-lint/analysis/base.rb', line 16

class Base < Iterator
  include MethodEvaluation

  attr_reader :report, :vm, :config

  ##
  # Array containing the callback names for which a new scope should be
  # created.
  #
  # @return [Array<Symbol>]
  #
  SCOPES = [:root, :block, :class, :def, :module, :sclass]

  ##
  # Registers the current class in
  # {RubyLint::Configuration.available_analysis_classes}.
  #
  # @param [String] name A human friendly name of the current class.
  #
  def self.register(name)
    Configuration.available_analysis_classes[name] = self
  end

  ##
  # Returns a boolean that indicates if the analysis class should be used
  # or not.
  #
  # @param [RubyLint::AST::Node] ast
  # @param [RubyLint::VirtualMachine] vm
  # @return [TrueClass|FalseClass]
  #
  def self.analyze?(ast, vm)
    return true
  end

  ##
  # Called after a new instance of this class is created.
  #
  def after_initialize
    unless vm.is_a?(VirtualMachine)
      raise(
        ArgumentError,
        'Analysis classes require a valid RubyLint::VirtualMachine ' \
          'instance to be set using `SomeAnalysisClass.new(:vm => ...)`'
      )
    end

    @scopes = []
  end

  SCOPES.each do |type|
    define_method("on_#{type}") do |node|
      set_current_scope(node)
    end

    define_method("after_#{type}") do |node|
      set_previous_scope
    end
  end

  protected

  ##
  # Returns the current scope.
  #
  # @return [RubyLint::Definition::RubyObject]
  #
  def current_scope
    return @scopes[-1]
  end

  ##
  # @return [RubyLint::Definition::RubyObject]
  #
  def previous_scope
    return @scopes[-2]
  end

  ##
  # Sets the current scope to the definition associated with the given
  # node.
  #
  # @param [RubyLint::Node] node
  #
  def set_current_scope(node)
    unless vm.associations.key?(node)
      raise ArgumentError, "No associations for node #{node}"
    end

    @scopes << vm.associations[node]
  end

  ##
  # Sets the current scope back to the previous one.
  #
  def set_previous_scope
    @scopes.pop
  end

  ##
  # Adds an error message to the report.
  #
  # @see #add_message
  #
  def error(*args)
    add_message(:error, *args)
  end

  ##
  # Adds a warning message to the report.
  #
  # @see #add_message
  #
  def warning(*args)
    add_message(:warning, *args)
  end

  ##
  # Adds a regular informational message to the report.
  #
  # @see #add_message
  #
  def info(*args)
    add_message(:info, *args)
  end

  ##
  # Adds a message of the given level.
  #
  # @param [Symbol] level
  # @param [String] message
  # @param [String] node
  #
  def add_message(level, message, node)
    return unless report

    report.add(
      :level    => level,
      :message  => message,
      :line     => node.line,
      :column   => node.column,
      :file     => node.file,
      :node     => node
    )
  end
end

#vmRubyLint::VirtualMachine (readonly)



16
17
18
19
20
21
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
# File 'lib/ruby-lint/analysis/base.rb', line 16

class Base < Iterator
  include MethodEvaluation

  attr_reader :report, :vm, :config

  ##
  # Array containing the callback names for which a new scope should be
  # created.
  #
  # @return [Array<Symbol>]
  #
  SCOPES = [:root, :block, :class, :def, :module, :sclass]

  ##
  # Registers the current class in
  # {RubyLint::Configuration.available_analysis_classes}.
  #
  # @param [String] name A human friendly name of the current class.
  #
  def self.register(name)
    Configuration.available_analysis_classes[name] = self
  end

  ##
  # Returns a boolean that indicates if the analysis class should be used
  # or not.
  #
  # @param [RubyLint::AST::Node] ast
  # @param [RubyLint::VirtualMachine] vm
  # @return [TrueClass|FalseClass]
  #
  def self.analyze?(ast, vm)
    return true
  end

  ##
  # Called after a new instance of this class is created.
  #
  def after_initialize
    unless vm.is_a?(VirtualMachine)
      raise(
        ArgumentError,
        'Analysis classes require a valid RubyLint::VirtualMachine ' \
          'instance to be set using `SomeAnalysisClass.new(:vm => ...)`'
      )
    end

    @scopes = []
  end

  SCOPES.each do |type|
    define_method("on_#{type}") do |node|
      set_current_scope(node)
    end

    define_method("after_#{type}") do |node|
      set_previous_scope
    end
  end

  protected

  ##
  # Returns the current scope.
  #
  # @return [RubyLint::Definition::RubyObject]
  #
  def current_scope
    return @scopes[-1]
  end

  ##
  # @return [RubyLint::Definition::RubyObject]
  #
  def previous_scope
    return @scopes[-2]
  end

  ##
  # Sets the current scope to the definition associated with the given
  # node.
  #
  # @param [RubyLint::Node] node
  #
  def set_current_scope(node)
    unless vm.associations.key?(node)
      raise ArgumentError, "No associations for node #{node}"
    end

    @scopes << vm.associations[node]
  end

  ##
  # Sets the current scope back to the previous one.
  #
  def set_previous_scope
    @scopes.pop
  end

  ##
  # Adds an error message to the report.
  #
  # @see #add_message
  #
  def error(*args)
    add_message(:error, *args)
  end

  ##
  # Adds a warning message to the report.
  #
  # @see #add_message
  #
  def warning(*args)
    add_message(:warning, *args)
  end

  ##
  # Adds a regular informational message to the report.
  #
  # @see #add_message
  #
  def info(*args)
    add_message(:info, *args)
  end

  ##
  # Adds a message of the given level.
  #
  # @param [Symbol] level
  # @param [String] message
  # @param [String] node
  #
  def add_message(level, message, node)
    return unless report

    report.add(
      :level    => level,
      :message  => message,
      :line     => node.line,
      :column   => node.column,
      :file     => node.file,
      :node     => node
    )
  end
end

Class Method Details

.analyze?(ast, vm) ⇒ TrueClass|FalseClass

Returns a boolean that indicates if the analysis class should be used or not.

Parameters:

Returns:

  • (TrueClass|FalseClass)


47
48
49
# File 'lib/ruby-lint/analysis/base.rb', line 47

def self.analyze?(ast, vm)
  return true
end

.register(name) ⇒ Object

Registers the current class in Configuration.available_analysis_classes.

Parameters:

  • name (String)

    A human friendly name of the current class.



35
36
37
# File 'lib/ruby-lint/analysis/base.rb', line 35

def self.register(name)
  Configuration.available_analysis_classes[name] = self
end

Instance Method Details

#add_message(level, message, node) ⇒ Object (protected)

Adds a message of the given level.

Parameters:



149
150
151
152
153
154
155
156
157
158
159
160
# File 'lib/ruby-lint/analysis/base.rb', line 149

def add_message(level, message, node)
  return unless report

  report.add(
    :level    => level,
    :message  => message,
    :line     => node.line,
    :column   => node.column,
    :file     => node.file,
    :node     => node
  )
end

#after_initializeObject

Called after a new instance of this class is created.



54
55
56
57
58
59
60
61
62
63
64
# File 'lib/ruby-lint/analysis/base.rb', line 54

def after_initialize
  unless vm.is_a?(VirtualMachine)
    raise(
      ArgumentError,
      'Analysis classes require a valid RubyLint::VirtualMachine ' \
        'instance to be set using `SomeAnalysisClass.new(:vm => ...)`'
    )
  end

  @scopes = []
end

#current_scopeRubyLint::Definition::RubyObject (protected)

Returns the current scope.



83
84
85
# File 'lib/ruby-lint/analysis/base.rb', line 83

def current_scope
  return @scopes[-1]
end

#error(*args) ⇒ Object (protected)

Adds an error message to the report.

See Also:



120
121
122
# File 'lib/ruby-lint/analysis/base.rb', line 120

def error(*args)
  add_message(:error, *args)
end

#info(*args) ⇒ Object (protected)

Adds a regular informational message to the report.

See Also:



138
139
140
# File 'lib/ruby-lint/analysis/base.rb', line 138

def info(*args)
  add_message(:info, *args)
end

#previous_scopeRubyLint::Definition::RubyObject (protected)



90
91
92
# File 'lib/ruby-lint/analysis/base.rb', line 90

def previous_scope
  return @scopes[-2]
end

#set_current_scope(node) ⇒ Object (protected)

Sets the current scope to the definition associated with the given node.

Parameters:

  • node (RubyLint::Node)


100
101
102
103
104
105
106
# File 'lib/ruby-lint/analysis/base.rb', line 100

def set_current_scope(node)
  unless vm.associations.key?(node)
    raise ArgumentError, "No associations for node #{node}"
  end

  @scopes << vm.associations[node]
end

#set_previous_scopeObject (protected)

Sets the current scope back to the previous one.



111
112
113
# File 'lib/ruby-lint/analysis/base.rb', line 111

def set_previous_scope
  @scopes.pop
end

#warning(*args) ⇒ Object (protected)

Adds a warning message to the report.

See Also:



129
130
131
# File 'lib/ruby-lint/analysis/base.rb', line 129

def warning(*args)
  add_message(:warning, *args)
end