Added Ruby::Generator class
This class will be used to serialize a Ruby AST back to valid Ruby source code (as a String).
This commit is contained in:
parent
6673f176d8
commit
337d126264
|
@ -50,6 +50,7 @@ require 'oga/html/sax_parser'
|
||||||
require 'oga/html/entities'
|
require 'oga/html/entities'
|
||||||
|
|
||||||
require 'oga/ruby/node'
|
require 'oga/ruby/node'
|
||||||
|
require 'oga/ruby/generator'
|
||||||
|
|
||||||
require 'oga/xpath/lexer'
|
require 'oga/xpath/lexer'
|
||||||
require 'oga/xpath/parser'
|
require 'oga/xpath/parser'
|
||||||
|
|
|
@ -0,0 +1,172 @@
|
||||||
|
module Oga
|
||||||
|
module Ruby
|
||||||
|
##
|
||||||
|
# Class for converting a Ruby AST to a String.
|
||||||
|
#
|
||||||
|
# This class takes a {Oga::Ruby::Node} instance and converts it (and its
|
||||||
|
# child nodes) to a String that in turn can be passed to `eval` and the
|
||||||
|
# likes.
|
||||||
|
#
|
||||||
|
class Generator
|
||||||
|
##
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def process(ast)
|
||||||
|
send(:"on_#{ast.type}", ast)
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes a "begin" node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_begin(ast)
|
||||||
|
ast.to_a.map { |child| process(child) }.join("\n\n")
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes an assignment node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_assign(ast)
|
||||||
|
var, val = *ast
|
||||||
|
|
||||||
|
var_str = process(var)
|
||||||
|
val_str = process(val)
|
||||||
|
|
||||||
|
"#{var_str} = #{val_str}"
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes an equality node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_eq(ast)
|
||||||
|
left, right = *ast
|
||||||
|
|
||||||
|
left_str = process(left)
|
||||||
|
right_str = process(right)
|
||||||
|
|
||||||
|
"#{left_str} == #{right_str}"
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes a boolean "and" node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_and(ast)
|
||||||
|
left, right = *ast
|
||||||
|
|
||||||
|
left_str = process(left)
|
||||||
|
right_str = process(right)
|
||||||
|
|
||||||
|
"#{left_str} && #{right_str}"
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes a boolean "or" node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_or(ast)
|
||||||
|
left, right = *ast
|
||||||
|
|
||||||
|
left_str = process(left)
|
||||||
|
right_str = process(right)
|
||||||
|
|
||||||
|
"(#{left_str} || #{right_str})"
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes an if statement node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_if(ast)
|
||||||
|
cond, body = *ast
|
||||||
|
|
||||||
|
cond_str = process(cond)
|
||||||
|
body_str = process(body)
|
||||||
|
|
||||||
|
<<-EOF
|
||||||
|
if #{cond_str}
|
||||||
|
#{body_str}
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes a method call node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_send(ast)
|
||||||
|
receiver, name, *args = *ast
|
||||||
|
|
||||||
|
call = name.dup
|
||||||
|
|
||||||
|
unless args.empty?
|
||||||
|
arg_strs = args.map { |arg| process(arg) }
|
||||||
|
call = "#{call}(#{arg_strs.join(', ')})"
|
||||||
|
end
|
||||||
|
|
||||||
|
if receiver
|
||||||
|
call = "#{process(receiver)}.#{call}"
|
||||||
|
end
|
||||||
|
|
||||||
|
call
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes a block node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_block(ast)
|
||||||
|
receiver, args, body = *ast
|
||||||
|
|
||||||
|
receiver_str = process(receiver)
|
||||||
|
body_str = body ? process(body) : nil
|
||||||
|
arg_strs = args.map { |arg| process(arg) }
|
||||||
|
|
||||||
|
<<-EOF
|
||||||
|
#{receiver_str} do |#{arg_strs.join(', ')}|
|
||||||
|
#{body_str}
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes a string node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_string(ast)
|
||||||
|
ast.to_a[0].inspect
|
||||||
|
end
|
||||||
|
|
||||||
|
##
|
||||||
|
# Processes a literal node.
|
||||||
|
#
|
||||||
|
# @param [Oga::Ruby::Node] ast
|
||||||
|
# @return [String]
|
||||||
|
#
|
||||||
|
def on_lit(ast)
|
||||||
|
ast.to_a[0]
|
||||||
|
end
|
||||||
|
end # Generator
|
||||||
|
end # Ruby
|
||||||
|
end # Oga
|
|
@ -0,0 +1,137 @@
|
||||||
|
require 'spec_helper'
|
||||||
|
|
||||||
|
describe Oga::Ruby::Generator do
|
||||||
|
before do
|
||||||
|
@generator = described_class.new
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_begin' do
|
||||||
|
it 'returns a String' do
|
||||||
|
node1 = Oga::Ruby::Node.new(:lit, %w{10})
|
||||||
|
node2 = Oga::Ruby::Node.new(:lit, %w{20})
|
||||||
|
joined = node1.followed_by(node2)
|
||||||
|
|
||||||
|
@generator.on_begin(joined).should == "10\n\n20"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_assign' do
|
||||||
|
it 'returns a String' do
|
||||||
|
var = Oga::Ruby::Node.new(:lit, %w{number})
|
||||||
|
val = Oga::Ruby::Node.new(:lit, %w{10})
|
||||||
|
assign = var.assign(val)
|
||||||
|
|
||||||
|
@generator.on_assign(assign).should == 'number = 10'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_eq' do
|
||||||
|
it 'returns a String' do
|
||||||
|
var = Oga::Ruby::Node.new(:lit, %w{number})
|
||||||
|
val = Oga::Ruby::Node.new(:lit, %w{10})
|
||||||
|
eq = var.eq(val)
|
||||||
|
|
||||||
|
@generator.on_eq(eq).should == 'number == 10'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_and' do
|
||||||
|
it 'returns a String' do
|
||||||
|
left = Oga::Ruby::Node.new(:lit, %w{foo})
|
||||||
|
right = Oga::Ruby::Node.new(:lit, %w{bar})
|
||||||
|
condition = left.and(right)
|
||||||
|
|
||||||
|
@generator.on_and(condition).should == 'foo && bar'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_or' do
|
||||||
|
it 'returns a String' do
|
||||||
|
left = Oga::Ruby::Node.new(:lit, %w{foo})
|
||||||
|
right = Oga::Ruby::Node.new(:lit, %w{bar})
|
||||||
|
condition = left.or(right)
|
||||||
|
|
||||||
|
@generator.on_or(condition).should == '(foo || bar)'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_if' do
|
||||||
|
it 'returns a String' do
|
||||||
|
statement = Oga::Ruby::Node.new(:lit, %w{foo}).if_true do
|
||||||
|
Oga::Ruby::Node.new(:lit, %w{bar})
|
||||||
|
end
|
||||||
|
|
||||||
|
@generator.on_if(statement).should == <<-EOF
|
||||||
|
if foo
|
||||||
|
bar
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_send' do
|
||||||
|
describe 'without arguments' do
|
||||||
|
it 'returns a String' do
|
||||||
|
node = Oga::Ruby::Node.new(:lit, %w{number}).foobar
|
||||||
|
|
||||||
|
@generator.on_send(node).should == 'number.foobar'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with arguments' do
|
||||||
|
it 'returns a String' do
|
||||||
|
arg = Oga::Ruby::Node.new(:lit, %w{10})
|
||||||
|
node = Oga::Ruby::Node.new(:lit, %w{number}).foobar(arg)
|
||||||
|
|
||||||
|
@generator.on_send(node).should == 'number.foobar(10)'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_block' do
|
||||||
|
describe 'without arguments' do
|
||||||
|
it 'returns a String' do
|
||||||
|
node = Oga::Ruby::Node.new(:lit, %w{number}).add_block do
|
||||||
|
Oga::Ruby::Node.new(:lit, %w{10})
|
||||||
|
end
|
||||||
|
|
||||||
|
@generator.on_block(node).should == <<-EOF
|
||||||
|
number do ||
|
||||||
|
10
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe 'with arguments' do
|
||||||
|
it 'returns a String' do
|
||||||
|
arg = Oga::Ruby::Node.new(:lit, %w{foo})
|
||||||
|
node = Oga::Ruby::Node.new(:lit, %w{number}).add_block(arg) do
|
||||||
|
Oga::Ruby::Node.new(:lit, %w{10})
|
||||||
|
end
|
||||||
|
|
||||||
|
@generator.on_block(node).should == <<-EOF
|
||||||
|
number do |foo|
|
||||||
|
10
|
||||||
|
end
|
||||||
|
EOF
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_string' do
|
||||||
|
it 'returns a String' do
|
||||||
|
node = Oga::Ruby::Node.new(:string, %w{foo})
|
||||||
|
|
||||||
|
@generator.on_string(node).should == '"foo"'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#on_lit' do
|
||||||
|
it 'returns a String' do
|
||||||
|
node = Oga::Ruby::Node.new(:lit, %w{foo})
|
||||||
|
|
||||||
|
@generator.on_lit(node).should == 'foo'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in New Issue