Added Oga::Ruby::Node

This class will be used for building Ruby ASTs that will be generated
based on XPath expressions.
This commit is contained in:
Yorick Peterse committed 2015-08-19 20:14:20 +02:00
1 parent c25879f18e
commit 6673f176d8
3 files changed
+280

No files matched your search

+2
View File
@@ -49,6 +49,8 @@ require 'oga/html/parser'
require 'oga/html/sax_parser'
require 'oga/html/entities'
require 'oga/ruby/node'
require 'oga/xpath/lexer'
require 'oga/xpath/parser'
require 'oga/xpath/evaluator'
+147
View File
@@ -0,0 +1,147 @@
module Oga
module Ruby
##
# Class representing a single node in a Ruby AST.
#
# The setup of this class is roughly based on the "ast" Gem. The "ast" Gem
# is not used for this class as it provides too many methods that might
# conflict with this class' {#method_missing}.
#
# ASTs can be built by creating a node and then chaining various method
# calls together. For example, the following could be used to build an "if"
# statement:
#
# number1 = Node.new(:lit, %w{10})
# number2 = Node.new(:lit, %w{20})
#
# (number2 > number1).if_true do
# Node.new(:lit, %w{30})
# end
#
# When serialized to Ruby this would roughly lead to the following code:
#
# if 20 > 10
# 30
# end
#
# @private
#
class Node < BasicObject
# @return [Symbol]
attr_reader :type
# @param [Symbol] type
# @param [Array] children
def initialize(type, children = [])
@type = type.to_sym
@children = children
end
# @return [Array]
def to_a
@children
end
##
# Returns an assignment node.
#
# @param [Oga::Ruby::Node] other
# @return [Oga::Ruby::Node]
#
def assign(other)
Node.new(:assign, [self, other])
end
##
# Returns an equality expression node.
#
# @param [Oga::Ruby::Node] other
# @return [Oga::Ruby::Node]
#
def eq(other)
Node.new(:eq, [self, other])
end
##
# Returns a boolean "and" node.
#
# @param [Oga::Ruby::Node] other
# @return [Oga::Ruby::Node]
#
def and(other)
Node.new(:and, [self, other])
end
##
# Returns a boolean "or" node.
#
# @param [Oga::Ruby::Node] other
# @return [Oga::Ruby::Node]
#
def or(other)
Node.new(:or, [self, other])
end
##
# Returns a node for Ruby's "is_a?" method.
#
# @param [Class] klass
# @return [Oga::Ruby::Node]
#
def is_a?(klass)
Node.new(:send, [self, 'is_a?', Node.new(:lit, [klass.to_s])])
end
##
# Wraps the current node in a block.
#
# @param [Array] args Arguments (as Node instances) to pass to the block.
# @return [Oga::Ruby::Node]
#
def add_block(*args)
Node.new(:block, [self, args, yield])
end
##
# Wraps the current node in an if statement node.
#
# The body of this statement is set to the return value of the supplied
# block.
#
# @return [Oga::Ruby::Node]
#
def if_true
Node.new(:if, [self, yield])
end
##
# Chains two nodes together.
#
# @param [Oga::Ruby::Node] other
# @return [Oga::Ruby::Node]
#
def followed_by(other)
Node.new(:begin, [self, other])
end
##
# Returns a node for a method call.
#
# @param [Symbol] name The name of the method to call.
#
# @param [Array] args Any arguments (as Node instances) to pass to the
# method.
#
# @return [Oga::Ruby::Node]
#
def method_missing(name, *args)
Node.new(:send, [self, name.to_s, *args])
end
# @return [String]
def inspect
"(#{type} #{@children.map(&:inspect).join(' ')})"
end
end # Node
end # Ruby
end # Oga