Macros
¶ ↑
Macros
for Ruby
Install¶ ↑
gem install macros
Usage¶ ↑
Any source file that contains macro definitions, or that requires macro expansion, should be loaded with Macros.require
.
require 'macros' Macros.require 'my_macros' Macros.require 'my_code_using_macros'
Macros
look like normal method definitions, but they are defined inside a Macros do ; end
block.
# my_macros.rb Macros do # Replace the +output+ method with the +puts+ method def with_output(ast) treemap(ast) do |node| if smatch? node, s(:send, nil, :output) s(:send, nil, :puts, *node.children.drop(2)) else node end end end end
Now this code
# my_code_using_macros.rb with_output do output "foo" output "bar" end
Will be transformed into
puts "foo" puts "bar"
Helpers¶ ↑
The macro will receive an instance of Parser::AST::Node
, and must return an instance of Parser::AST::Node
. Inside the macro definition the following convenience functions are available:
s(type, *children)
¶ ↑
Construct an AST node of given type, with specific children.
node?(n)
¶ ↑
Is the given object an AST node?
treemap(node, &tranform)
¶ ↑
Similar to Enumerable#map
, but performs a full tree walk, passing any AST::Node
to the block.
treefilter(node, &pred)
¶ ↑
Returns an array of any node in the tree that satisfies the predicate
sfind(node, spec)
¶ ↑
spec
is an Array of symbols, integers, and arrays. It is used a bit like XPath or CSS locators.
node = s(:def, :a_name, s(:args, s(:arg, :x), s(:arg, :y))) sfind(node, [:def, 1, :args, [:arg, 0]]) # => [:x, y]
smatch?(node, pattern)
¶ ↑
Checks if the node matches the “pattern”
node = s(:def, :a_name, s(:args, s(:arg, :x), s(:arg, :y))) smatch?(node, s(:def, :a_name)) # => true
Is this a joke?¶ ↑
Well, it works, but it’s a toy. Working with Ruby syntax trees is pretty awkward, and macros can easily lead to a mess. You have been warned!
License¶ ↑
© Arne Brasseur 2015
Eclipse Public License