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.



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

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 line && ENV['VERBOSE'] then
    "s(#{sexp_str}).line(#{line})"
  else
    "s(#{sexp_str})"
  end
end

#pretty_print(q) ⇒ Object

:nodoc:



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

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.



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

def sexp_body
  self[1..-1]
end

#sexp_typeObject

Returns the node type of the Sexp.



196
197
198
# File 'lib/sexp.rb', line 196

def sexp_type
  first
end

#shiftObject

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



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

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



220
221
222
223
224
225
226
227
228
229
230
231
# File 'lib/sexp.rb', line 220

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.



236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
# File 'lib/sexp.rb', line 236

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:



265
266
267
# File 'lib/sexp.rb', line 265

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

#to_sObject

:nodoc:



269
270
271
# File 'lib/sexp.rb', line 269

def to_s # :nodoc:
  inspect
end