Class: Sexp

Inherits:
Array show all
Defined in:
lib/sexp.rb

Overview

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.

Direct Known Subclasses

SexpMatchSpecial

Constant Summary collapse

@@array_types =
[ :array, :args, ]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(*args) ⇒ Sexp

Create a new Sexp containing args.



21
22
23
# File 'lib/sexp.rb', line 21

def initialize(*args)
  super(args)
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(meth, delete = false) ⇒ Object

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



198
199
200
# File 'lib/sexp.rb', line 198

def method_missing meth, delete = false
  find_node meth, delete
end

Instance Attribute Details

#commentsObject

Returns the value of attribute comments.



14
15
16
# File 'lib/sexp.rb', line 14

def comments
  @comments
end

#endline(n = nil) ⇒ Object

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



186
187
188
189
190
191
192
193
# File 'lib/sexp.rb', line 186

def endline(n=nil)
  if n then
    @endline = n
    self
  else
    @endline ||= nil
  end
end

#fileObject

Returns the value of attribute file.



14
15
16
# File 'lib/sexp.rb', line 14

def file
  @file
end

#line(n = nil) ⇒ Object

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.



172
173
174
175
176
177
178
179
# File 'lib/sexp.rb', line 172

def line(n=nil)
  if n then
    @line = n
    self
  else
    @line ||= nil
  end
end

Class Method Details

.from_array(a) ⇒ Object

Creates a new Sexp from Array a.



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/sexp.rb', line 28

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

Instance Method Details

#==(obj) ⇒ Object

:nodoc:



47
48
49
50
51
52
53
# File 'lib/sexp.rb', line 47

def ==(obj) # :nodoc:
  if obj.class == self.class then
    super
  else
    false
  end
end

#===(sexp) ⇒ Object

Returns true if this Sexp’s pattern matches sexp.



58
59
60
61
62
63
64
65
66
67
68
69
# File 'lib/sexp.rb', line 58

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) ⇒ Object

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



74
75
76
# File 'lib/sexp.rb', line 74

def =~(pattern)
  return pattern === self
end

#array_type?Boolean

Returns true if the node_type is array or args.

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

Returns:

  • (Boolean)


83
84
85
86
# File 'lib/sexp.rb', line 83

def array_type?
  type = self.first
  @@array_types.include? type
end

#compactObject

:nodoc:



88
89
90
# File 'lib/sexp.rb', line 88

def compact # :nodoc:
  self.delete_if { |o| o.nil? }
end

#each_of_type(t, &b) ⇒ Object

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



95
96
97
98
99
100
101
102
# File 'lib/sexp.rb', line 95

def each_of_type(t, &b)
  each do | elem |
    if Sexp === elem then
      elem.each_of_type(t, &b)
      b.call(elem) if elem.first == t
    end
  end
end

#find_and_replace_all(from, to) ⇒ Object

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



108
109
110
111
112
113
114
115
116
# File 'lib/sexp.rb', line 108

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) ⇒ Object



145
146
147
148
149
150
151
152
153
154
155
156
157
158
# File 'lib/sexp.rb', line 145

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) ⇒ Object

Find every node with type name.



163
164
165
# File 'lib/sexp.rb', line 163

def find_nodes name
  find_all { | sexp | Sexp === sexp and sexp.first == name }
end

#gsub(pattern, repl) ⇒ Object

Replaces all Sexps matching pattern with Sexp repl.



121
122
123
124
125
126
127
128
129
130
131
132
133
134
# File 'lib/sexp.rb', line 121

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

#inspectObject

:nodoc:



136
137
138
139
140
141
142
143
# File 'lib/sexp.rb', line 136

def inspect # :nodoc:
  sexp_str = self.map {|x|x.inspect}.join(', ')
  if line && ENV['VERBOSE'] then
    "s(#{sexp_str}).line(#{line})"
  else
    "s(#{sexp_str})"
  end
end

#pretty_print(q) ⇒ Object

:nodoc:



202
203
204
205
206
# File 'lib/sexp.rb', line 202

def pretty_print(q) # :nodoc:
  q.group(1, 's(', ')') do
    q.seplist(self) {|v| q.pp v }
  end
end

#sexp_bodyObject

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



218
219
220
# File 'lib/sexp.rb', line 218

def sexp_body
  self[1..-1]
end

#sexp_typeObject

Returns the node type of the Sexp.



211
212
213
# File 'lib/sexp.rb', line 211

def sexp_type
  first
end

#shiftObject

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



226
227
228
229
# File 'lib/sexp.rb', line 226

def shift
  raise "I'm empty" if self.empty?
  super
end

#structureObject

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



235
236
237
238
239
240
241
242
243
244
245
246
# File 'lib/sexp.rb', line 235

def structure
  result = self.class.new
  if Array === self.first then
    result = self.first.structure
  else
    result << self.first
    self.grep(Array).each do |subexp|
      result << subexp.structure
    end
  end
  result
end

#sub(pattern, repl) ⇒ Object

Replaces the Sexp matching pattern with repl.



251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
# File 'lib/sexp.rb', line 251

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

#to_aObject

:nodoc:



280
281
282
# File 'lib/sexp.rb', line 280

def to_a # :nodoc:
  self.map { |o| Sexp === o ? o.to_a : o }
end

#to_sObject

:nodoc:



284
285
286
# File 'lib/sexp.rb', line 284

def to_s # :nodoc:
  inspect
end