Class: RubyLint::Iterator
- Inherits:
-
Object
- Object
- RubyLint::Iterator
- Defined in:
- lib/ruby-lint/iterator.rb
Overview
The Iterator class provides the means to iterate over an AST generated by Parser using callback methods for the various node types generated by this parser.
For each node type two events are called: one before and one after processing the node and all of its children. The names of these events are the following:
on_Xafter_X
Here "X" is the name of the event. For example, when iterator an integer
this would result in the event names on_integer and after_integer.
These event names are used to call the corresponding callback methods if they exist. Each callback method takes a single argument: the node (an instance of AST::Node) that belongs to the event.
Creating iterator classes is done by extending this particular class and adding the needed methods to it:
class MyIterator < RubyLint::Iterator
def on_int(node)
puts node.children[0]
end
def after_int(node)
puts '---'
end
end
When used this particular iterator class would display the values of all integers it processes. After processing an integer it will display three dashes.
Skipping Child Nodes
The on_* callbacks can tell the Iterator class to not process any
following child nodes by calling skip_child_nodes!:
def on_const(node)
# ...
skip_child_nodes!(node)
end
Internally this uses throw and makes sure to only skip the child nodes of
the specified node (throw calls bubble up regardless of catch calls,
unlike when using begin/rescue).
Direct Known Subclasses
Instance Attribute Summary collapse
-
#arity_cache ⇒ Object
readonly
Returns the value of attribute arity_cache.
-
#arity_cache Hash containing the amount of arguments for(Hashcontainingtheamountofarguments) ⇒ Hash
readonly
each method.
Instance Method Summary collapse
-
#execute_callback(name, *args) ⇒ Object
protected
Executes the specified callback method if it exists.
-
#initialize(options = {}) ⇒ Iterator
constructor
A new instance of Iterator.
-
#iterate(node) ⇒ Object
Recursively processes the specified list of nodes.
-
#skip_child_nodes!(node) ⇒ Object
protected
Instructs #iterate to not process any child nodes.
Constructor Details
#initialize(options = {}) ⇒ Iterator
Returns a new instance of Iterator.
64 65 66 67 68 69 70 71 72 |
# File 'lib/ruby-lint/iterator.rb', line 64 def initialize( = {}) .each do |key, value| instance_variable_set("@#{key}", value) end after_initialize if respond_to?(:after_initialize) @arity_cache = {} end |
Instance Attribute Details
#arity_cache ⇒ Object (readonly)
Returns the value of attribute arity_cache.
58 59 60 |
# File 'lib/ruby-lint/iterator.rb', line 58 def arity_cache @arity_cache end |
#arity_cache Hash containing the amount of arguments for(Hashcontainingtheamountofarguments) ⇒ Hash (readonly)
each method.
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 |
# File 'lib/ruby-lint/iterator.rb', line 57 class Iterator attr_reader :arity_cache ## # @param [Hash] options Hash containing custom options to set for the # iterator. # def initialize( = {}) .each do |key, value| instance_variable_set("@#{key}", value) end after_initialize if respond_to?(:after_initialize) @arity_cache = {} end ## # Recursively processes the specified list of nodes. # # @param [RubyLint::Node] node A node and optionally a set of sub nodes to # iterate over. # def iterate(node) return unless node.is_a?(AST::Node) before = :"on_#{node.type}" after = :"after_#{node.type}" skip_node = catch :skip_child_nodes do execute_callback(before, node) end if skip_node != node node.children.each do |child| iterate(child) if child.is_a?(AST::Node) end end execute_callback(after, node) end protected ## # Instructs {#iterate} to not process any child nodes. # # @param [RubyLint::AST::Node] node # def skip_child_nodes!(node) throw :skip_child_nodes, node end ## # Executes the specified callback method if it exists. # # @param [String|Symbol] name The name of the callback method to execute. # @param [Array] args Arguments to pass to the callback method. # def execute_callback(name, *args) return unless respond_to?(name) unless arity_cache.key?(name) arity_cache[name] = method(name).arity end if arity_cache[name] == 0 send(name) else send(name, *args) end end end |
Instance Method Details
#execute_callback(name, *args) ⇒ Object (protected)
Executes the specified callback method if it exists.
115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/ruby-lint/iterator.rb', line 115 def execute_callback(name, *args) return unless respond_to?(name) unless arity_cache.key?(name) arity_cache[name] = method(name).arity end if arity_cache[name] == 0 send(name) else send(name, *args) end end |
#iterate(node) ⇒ Object
Recursively processes the specified list of nodes.
80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 |
# File 'lib/ruby-lint/iterator.rb', line 80 def iterate(node) return unless node.is_a?(AST::Node) before = :"on_#{node.type}" after = :"after_#{node.type}" skip_node = catch :skip_child_nodes do execute_callback(before, node) end if skip_node != node node.children.each do |child| iterate(child) if child.is_a?(AST::Node) end end execute_callback(after, node) end |
#skip_child_nodes!(node) ⇒ Object (protected)
Instructs #iterate to not process any child nodes.
105 106 107 |
# File 'lib/ruby-lint/iterator.rb', line 105 def skip_child_nodes!(node) throw :skip_child_nodes, node end |