Pointcut Your Javascript
Jan 24, 2008 @ 11:29 pmSorry for all of the RKelly updates, but thats what I’ve been doing in my free time. I mean, besides J-School. But I don’t think anyone wants to read my poor Japanese!
I wanted to make my ASTs easily searchable, so I added an AOP style interface to my AST. The AST will now let you pointcut your javascript and give you back a list of all of the points it finds. Take this javascript for example:
try {
Element.update('another_id',"blah blah blah");
Element.update(10,"blah blah blah");
} catch (e) { }
Lets say you wanted to find every place that Element.update() was called with 2 arguments, and mess with those arguments. You can pointcut the ast, then modify the arguments by giving the AST a pattern to match on like so:
parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("Element.update(Object, Object)").matches.each do |m|
m.arguments.value.each { |x|
x.value = rand(20)
}
end
puts ast.to_ecma
But lets say you only want to update the call that was made with a number as the first parameter. No problem! Just change your pattern to use a number, like so:
parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("Element.update(Number, Object)").matches.each do |m|
m.arguments.value.each { |x|
x.value = rand(20)
}
end
puts ast.to_ecma
You can even get more specific and match the arguments exactly. For example, matching just the function call where the first argument is ‘another_id’:
parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("Element.update('another_id', Object)").matches.each do |m|
m.arguments.value.each { |x|
x.value = rand(20)
}
end
Maybe you don’t care the update is being called on an Element, but you want to match all places that update is being called on something. The pointcut will match on node type too, so this is a perfectly valid pattern:
parser = RKelly::Parser.new
ast = parser.parse(DATA.read)
ast.pointcut("ResolveNode.update('another_id', Object)").matches.each do |m|
m.arguments.value.each { |x|
x.value = rand(20)
}
end
Hopefully you get the picture. This feature isn’t full tested yet, but I think I might do my first RKelly release after I finish testing.