class Sexp

Sexps are the basic storage mechanism of SexpProcessor. Sexps have a type (to be renamed node_type) which is the first element of the Sexp. The type is used by SexpProcessor to determine whom to dispatch the Sexp to for processing.

Attributes

comments[RW]
file[RW]
line[W]

Public Class Methods

from_array(a) click to toggle source

Creates a new Sexp from Array a.

# File lib/sexp.rb, line 26
def self.from_array(a)
  ary = Array === a ? a : [a]

  result = self.new

  ary.each do |x|
    case x
    when Sexp
      result << x
    when Array
      result << self.from_array(x)
    else
      result << x
    end
  end

  result
end
new(*args) click to toggle source

Create a new Sexp containing args.

Calls superclass method
# File lib/sexp.rb, line 19
def initialize(*args)
  super(args)
end

Public Instance Methods

===(sexp) click to toggle source

Returns true if this Sexp's pattern matches sexp.

# File lib/sexp.rb, line 52
def ===(sexp)
  return nil unless Sexp === sexp
  pattern = self # this is just for my brain

  return true if pattern == sexp

  sexp.each do |subset|
    return true if pattern === subset
  end

  return nil
end
=~(pattern) click to toggle source

Returns true if this Sexp matches pattern. (Opposite of ===.)

# File lib/sexp.rb, line 68
def =~(pattern)
  return pattern === self
end
array_type?() click to toggle source

Returns true if the node_type is array or args.

REFACTOR: to TypedSexp - we only care when we have units.

# File lib/sexp.rb, line 77
def array_type?
  type = self.first
  @@array_types.include? type
end
deep_each(&block) click to toggle source

Recursively enumerates the sexp yielding to block for every element.

# File lib/sexp.rb, line 89
def deep_each(&block)
  return enum_for(:deep_each) unless block_given?

  self.each_sexp do |sexp|
    block[sexp]
    sexp.deep_each(&block)
  end
end
depth() click to toggle source
# File lib/sexp.rb, line 98
def depth
  1 + (each_sexp.map(&:depth).max || 0)
end
each_of_type(t, &b) click to toggle source

Enumeratates the sexp yielding to b when the node_type == t.

# File lib/sexp.rb, line 105
def each_of_type(t, &b)
  return enum_for(:each_of_type) unless block_given?

  each do | elem |
    if Sexp === elem then
      elem.each_of_type(t, &b)
      b.call(elem) if elem.first == t
    end
  end
end
each_sexp() { |sexp| ... } click to toggle source

Recursively enumerates all sub-sexps skipping non-Sexp elements.

# File lib/sexp.rb, line 119
def each_sexp
  return enum_for(:each_sexp) unless block_given?

  self.each do |sexp|
    next unless Sexp === sexp

    yield sexp
  end
end
find_and_replace_all(from, to) click to toggle source

Replaces all elements whose node_type is from with to. Used only for the most trivial of rewrites.

# File lib/sexp.rb, line 133
def find_and_replace_all(from, to)
  each_with_index do | elem, index |
    if Sexp === elem then
      elem.find_and_replace_all(from, to)
    else
      self[index] = to if elem == from
    end
  end
end
find_node(name, delete = false) click to toggle source
# File lib/sexp.rb, line 170
def find_node name, delete = false
  matches = find_nodes name

  case matches.size
  when 0 then
    nil
  when 1 then
    match = matches.first
    delete match if delete
    match
  else
    raise NoMethodError, "multiple nodes for #{name} were found in #{inspect}"
  end
end
find_nodes(name) click to toggle source

Find every node with type name.

# File lib/sexp.rb, line 188
def find_nodes name
  find_all { | sexp | Sexp === sexp and sexp.first == name }
end
gsub(pattern, repl) click to toggle source

Replaces all Sexps matching pattern with Sexp repl.

# File lib/sexp.rb, line 146
def gsub(pattern, repl)
  return repl if pattern == self

  new = self.map do |subset|
    case subset
    when Sexp then
      subset.gsub(pattern, repl)
    else
      subset
    end
  end

  return Sexp.from_array(new)
end
head()
Alias for: sexp_type
line(n=nil) click to toggle source

If passed a line number, sets the line and returns self. Otherwise returns the line number. This allows you to do message cascades and still get the sexp back.

# File lib/sexp.rb, line 197
def line(n=nil)
  if n then
    @line = n
    self
  else
    @line ||= nil
  end
end
line_max() click to toggle source

Returns the maximum line number of the children of self.

# File lib/sexp.rb, line 209
def line_max
  @line_max ||= self.deep_each.map(&:line).max
end
mass() click to toggle source

Returns the size of the sexp, flattened.

# File lib/sexp.rb, line 216
def mass
  @mass ||=
    inject(1) { |t, s|
    if Sexp === s then
      t + s.mass
    else
      t
    end
  }
end
method_missing(meth, delete = false) click to toggle source

Returns the node named node, deleting it if delete is true.

# File lib/sexp.rb, line 230
def method_missing meth, delete = false
  r = find_node meth, delete
  if ENV["DEBUG"] then
    if r.nil? then
      warn "%p.method_missing(%p) => nil from %s" % [self, meth, caller.first]
    elsif ENV["VERBOSE"]
      warn "%p.method_missing(%p) from %s" % [self, meth, caller.first]
    end
  end
  r
end
rest()
Alias for: sexp_body
sexp_body() click to toggle source

Returns the Sexp body, ie the values without the node type.

# File lib/sexp.rb, line 273
def sexp_body
  self[1..-1]
end
Also aliased as: rest
sexp_type() click to toggle source

Returns the node type of the Sexp.

# File lib/sexp.rb, line 259
def sexp_type
  first
end
Also aliased as: head
sexp_type=(v) click to toggle source

Sets the node type of the Sexp.

# File lib/sexp.rb, line 266
def sexp_type= v
  self[0] = v
end
shift() click to toggle source

If run with debug, Sexp will raise if you shift on an empty Sexp. Helps with debugging.

Calls superclass method
# File lib/sexp.rb, line 284
def shift
  raise "I'm empty" if self.empty?
  super
end
structure() click to toggle source

Returns the bare bones structure of the sexp. s(:a, :b, s(:c, :d), :e) => s(:a, s(:c))

# File lib/sexp.rb, line 293
def structure
  if Array === self.first then
    s(:bogus, *self).structure # TODO: remove >= 4.2.0
  else
    result = s(self.first)
    self.each do |subexp|
      result << subexp.structure if Sexp === subexp
    end
    result
  end
end
sub(pattern, repl) click to toggle source

Replaces the Sexp matching pattern with repl.

# File lib/sexp.rb, line 308
def sub(pattern, repl)
  return repl.dup if pattern == self

  done = false

  new = self.map do |subset|
    if done then
      subset
    else
      case subset
      when Sexp then
        if pattern == subset then
          done = true
          repl.dup
        elsif pattern === subset then
          done = true
          subset.sub pattern, repl
        else
          subset
        end
      else
        subset
      end
    end
  end

  return Sexp.from_array(new)
end