Class: Moxml::XPath::Ruby::Node

Inherits:
BasicObject
Defined in:
lib/moxml/xpath/ruby/node.rb

Overview

Class representing a single node in a Ruby AST.

This class provides a fluent DSL for building Ruby code dynamically. It’s modeled after the “ast” gem but simplified to avoid method conflicts.

Examples:

Building an if statement

number1 = Node.new(:lit, ['10'])
number2 = Node.new(:lit, ['20'])

(number2 > number1).if_true do
  Node.new(:lit, ['30'])
end

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(type, children = []) ⇒ Node

Returns a new instance of Node.

Parameters:

  • type (Symbol)

    The type of AST node

  • children (Array) (defaults to: [])

    Child nodes or values



28
29
30
31
# File 'lib/moxml/xpath/ruby/node.rb', line 28

def initialize(type, children = [])
  @type = type.to_sym
  @children = children
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(name, *args) ⇒ Moxml::XPath::Ruby::Node

Returns a node for a method call.

Parameters:

  • name (Symbol)

    The name of the method to call

  • args (Array)

    Any arguments (as Node instances) to pass

Returns:



175
176
177
# File 'lib/moxml/xpath/ruby/node.rb', line 175

def method_missing(name, *args)
  Node.new(:send, [self, name.to_s, *args])
end

Instance Attribute Details

#typeSymbol (readonly)

Returns:

  • (Symbol)


24
25
26
# File 'lib/moxml/xpath/ruby/node.rb', line 24

def type
  @type
end

Instance Method Details

#add_block(*args) ⇒ Moxml::XPath::Ruby::Node

Wraps the current node in a block.

Parameters:

  • args (Array)

    Arguments (as Node instances) to pass to the block

Returns:



113
114
115
# File 'lib/moxml/xpath/ruby/node.rb', line 113

def add_block(*args)
  Node.new(:block, [self, args, yield])
end

#and(other) ⇒ Moxml::XPath::Ruby::Node

Returns a boolean “and” node.

Parameters:

Returns:



71
72
73
# File 'lib/moxml/xpath/ruby/node.rb', line 71

def and(other)
  Node.new(:and, [self, other])
end

#assign(other) ⇒ Moxml::XPath::Ruby::Node

Returns an assignment node.

Wraps assigned values in a begin/end block to ensure that multiple lines of code result in the proper value being assigned.

Parameters:

Returns:



53
54
55
56
57
# File 'lib/moxml/xpath/ruby/node.rb', line 53

def assign(other)
  other = other.wrap if other.type == :followed_by

  Node.new(:assign, [self, other])
end

#elseMoxml::XPath::Ruby::Node

Adds an “else” statement to the current node.

This method assumes it’s being called only on “if” nodes.



156
157
158
# File 'lib/moxml/xpath/ruby/node.rb', line 156

def else
  Node.new(:if, @children + [yield])
end

#eq(other) ⇒ Moxml::XPath::Ruby::Node

Returns an equality expression node.

Parameters:

Returns:



63
64
65
# File 'lib/moxml/xpath/ruby/node.rb', line 63

def eq(other)
  Node.new(:eq, [self, other])
end

#followed_by(other = nil) ⇒ Moxml::XPath::Ruby::Node

Chains two nodes together.

Parameters:

Returns:



164
165
166
167
168
# File 'lib/moxml/xpath/ruby/node.rb', line 164

def followed_by(other = nil)
  other = yield if ::Kernel.block_given?

  Node.new(:followed_by, [self, other])
end

#if_false(&block) ⇒ Object

Wraps the current node in an ‘if !…` statement.

See Also:

  • Moxml::XPath::Ruby::Node.[[#if_true]


137
138
139
# File 'lib/moxml/xpath/ruby/node.rb', line 137

def if_false(&block)
  self.not.if_true(&block)
end

#if_trueMoxml::XPath::Ruby::Node

Wraps the current node in an if statement node.

The body of this statement is set to the return value of the supplied block.



130
131
132
# File 'lib/moxml/xpath/ruby/node.rb', line 130

def if_true
  Node.new(:if, [self, yield])
end

#inspectString

Returns:

  • (String)


187
188
189
# File 'lib/moxml/xpath/ruby/node.rb', line 187

def inspect
  "(#{type} #{@children.map(&:inspect).join(' ')})"
end

#is_a?(klass) ⇒ Moxml::XPath::Ruby::Node

Returns a node for Ruby’s “is_a?” method.

Parameters:

  • klass (Class)

Returns:



97
98
99
100
101
102
103
104
105
106
107
# File 'lib/moxml/xpath/ruby/node.rb', line 97

def is_a?(klass)
  # If klass is already a Node (e.g., a const node), use it directly
  # Otherwise wrap it in a lit node
  klass_node = if klass.respond_to?(:type)
                 klass
               else
                 Node.new(:lit, [klass.to_s])
               end

  Node.new(:send, [self, "is_a?", klass_node])
end

#notMoxml::XPath::Ruby::Node

Returns a node that evaluates to its inverse.

Examples:

foo.not # => !foo

Returns:



89
90
91
# File 'lib/moxml/xpath/ruby/node.rb', line 89

def not
  !self
end

#or(other) ⇒ Moxml::XPath::Ruby::Node

Returns a boolean “or” node.

Parameters:

Returns:



79
80
81
# File 'lib/moxml/xpath/ruby/node.rb', line 79

def or(other)
  Node.new(:or, [self, other])
end

#to_aArray Also known as: to_ary

Returns:

  • (Array)


34
35
36
# File 'lib/moxml/xpath/ruby/node.rb', line 34

def to_a
  @children
end

#to_arrayMoxml::XPath::Ruby::Node

Returns a “to_a” call node.



42
43
44
# File 'lib/moxml/xpath/ruby/node.rb', line 42

def to_array
  Node.new(:send, [self, :to_a])
end

#to_strObject

Prevent implicit string conversion - Nodes must be explicitly processed



180
181
182
183
184
# File 'lib/moxml/xpath/ruby/node.rb', line 180

def to_str
  ::Kernel.raise ::TypeError, "Cannot implicitly

 convert #{self.class} to String. Use Generator#process instead."
end

#while_trueMoxml::XPath::Ruby::Node

Wraps the current node in a ‘while` statement.

The body of this statement is set to the return value of the supplied block.



147
148
149
# File 'lib/moxml/xpath/ruby/node.rb', line 147

def while_true
  Node.new(:while, [self, yield])
end

#wrapMoxml::XPath::Ruby::Node

Wraps the current node in a ‘begin` node.



120
121
122
# File 'lib/moxml/xpath/ruby/node.rb', line 120

def wrap
  Node.new(:begin, [self])
end