class RubyLint::Iterator
The Iterator
class provides the means to iterate over an AST
generated by {RubyLint::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_X`
-
`after_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 {RubyLint::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`).
@!attribute [r] arity_cache
Hash containing the amount of arguments for
each method. @return [Hash]
Attributes
Public Class Methods
@param [Hash] options Hash containing custom options to set for the
iterator.
# File lib/ruby-lint/iterator.rb, line 64 def initialize(options = {}) options.each do |key, value| instance_variable_set("@#{key}", value) end after_initialize if respond_to?(:after_initialize) @arity_cache = {} end
Public Instance Methods
Recursively processes the specified list of nodes.
@param [RubyLint::Node] node A node and optionally a set of sub nodes to
iterate over.
# 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
Protected Instance Methods
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.
# 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
Instructs {#iterate} to not process any child nodes.
@param [RubyLint::AST::Node] node
# File lib/ruby-lint/iterator.rb, line 105 def skip_child_nodes!(node) throw :skip_child_nodes, node end