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.



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

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.



190
191
192
# File 'lib/sexp.rb', line 190

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

Instance Attribute Details

#commentsObject

Returns the value of attribute comments.



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

def comments
  @comments
end

#fileObject

Returns the value of attribute file.



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

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.



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

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.



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

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:



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

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.



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

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 #===.)



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

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)


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

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

#compactObject

:nodoc:



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

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.



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

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.



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

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



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

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.



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

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.



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

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:



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

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

#massObject

Returns the size of the sexp, flattened.



183
184
185
# File 'lib/sexp.rb', line 183

def mass
  @mass ||= self.structure.flatten.size
end

#pretty_print(q) ⇒ Object

:nodoc:



194
195
196
197
198
199
200
201
# File 'lib/sexp.rb', line 194

def pretty_print(q) # :nodoc:
  nnd = ')'
  nnd << ".line(#{line})" if line && ENV['VERBOSE']

  q.group(1, 's(', nnd) do
    q.seplist(self) {|v| q.pp v }
  end
end

#sexp_bodyObject

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



213
214
215
# File 'lib/sexp.rb', line 213

def sexp_body
  self[1..-1]
end

#sexp_typeObject

Returns the node type of the Sexp.



206
207
208
# File 'lib/sexp.rb', line 206

def sexp_type
  first
end

#shiftObject

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



221
222
223
224
# File 'lib/sexp.rb', line 221

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



230
231
232
233
234
235
236
237
238
239
240
241
# File 'lib/sexp.rb', line 230

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.



246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
# File 'lib/sexp.rb', line 246

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:



275
276
277
# File 'lib/sexp.rb', line 275

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

#to_sObject

:nodoc:



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

def to_s # :nodoc:
  inspect
end