1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 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
|
# This script visits all of the nodes of a specific type within a given source
# file. It uses the visitor class to traverse the AST.
require "prism"
require "pp"
class CaseInsensitiveRegularExpressionVisitor < Prism::Visitor
def initialize(regexps)
@regexps = regexps
end
# As the visitor is walking the tree, this method will only be called when it
# encounters a regular expression node. We can then call any regular
# expression -specific APIs. In this case, we are only interested in the
# regular expressions that are case-insensitive, which we can retrieve with
# the #ignore_case? method.
def visit_regular_expression_node(node)
@regexps << node if node.ignore_case?
super
end
def visit_interpolated_regular_expression_node(node)
@regexps << node if node.ignore_case?
# The default behavior of the visitor is to continue visiting the children
# of the node. Because Ruby is so dynamic, it's actually possible for
# another regular expression to be interpolated in statements contained
# within the #{} contained in this interpolated regular expression node. By
# calling `super`, we ensure the visitor will continue. Failing to call
# `super` will cause the visitor to stop the traversal of the tree, which
# can also be useful in some cases.
super
end
end
result = Prism.parse_stream(DATA)
regexps = []
result.value.accept(CaseInsensitiveRegularExpressionVisitor.new(regexps))
regexps.each do |node|
print node.class.name.split("::", 2).last
print " "
puts PP.pp(node.location, +"")
if node.is_a?(Prism::RegularExpressionNode)
print " "
p node.unescaped
end
end
# =>
# InterpolatedRegularExpressionNode (3,9)-(3,47)
# RegularExpressionNode (3,16)-(3,22)
# "bar"
# RegularExpressionNode (4,9)-(4,15)
# "bar"
__END__
class Foo
REG1 = /foo/
REG2 = /foo #{/bar/i =~ "" ? "bar" : "baz"}/i
REG3 = /bar/i
end
|