sexp_processor 4.9.0 → 4.10.0b1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +0 -0
- data.tar.gz.sig +0 -0
- data/History.txt +45 -0
- data/Manifest.txt +1 -0
- data/README.txt +36 -7
- data/Rakefile +4 -0
- data/lib/composite_sexp_processor.rb +4 -4
- data/lib/pt_testcase.rb +21 -25
- data/lib/sexp.rb +1150 -107
- data/lib/sexp_processor.rb +127 -65
- data/lib/strict_sexp.rb +126 -0
- data/lib/unique.rb +7 -1
- data/test/test_composite_sexp_processor.rb +9 -12
- data/test/test_environment.rb +2 -2
- data/test/test_sexp.rb +1311 -113
- data/test/test_sexp_processor.rb +65 -52
- metadata +5 -4
- metadata.gz.sig +0 -0
data/lib/sexp_processor.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
$TESTING = false unless defined? $TESTING
|
2
2
|
|
3
|
-
require
|
3
|
+
require "sexp"
|
4
4
|
|
5
5
|
##
|
6
6
|
# SexpProcessor provides a uniform interface to process Sexps.
|
@@ -33,7 +33,8 @@ require 'sexp'
|
|
33
33
|
|
34
34
|
class SexpProcessor
|
35
35
|
|
36
|
-
|
36
|
+
# duh
|
37
|
+
VERSION = "4.10.0b1"
|
37
38
|
|
38
39
|
##
|
39
40
|
# Automatically shifts off the Sexp type before handing the
|
@@ -102,7 +103,7 @@ class SexpProcessor
|
|
102
103
|
|
103
104
|
dirs.flatten.map { |p|
|
104
105
|
if File.directory? p then
|
105
|
-
Dir[File.join(p,
|
106
|
+
Dir[File.join(p, "**", "*.{#{extensions.join ","}}")]
|
106
107
|
else
|
107
108
|
p
|
108
109
|
end
|
@@ -160,7 +161,10 @@ class SexpProcessor
|
|
160
161
|
end
|
161
162
|
end
|
162
163
|
|
163
|
-
|
164
|
+
##
|
165
|
+
# Raise if +exp+ is not empty.
|
166
|
+
|
167
|
+
def assert_empty meth, exp, exp_orig
|
164
168
|
unless exp.empty? then
|
165
169
|
msg = "exp not empty after #{self.class}.#{meth} on #{exp.inspect}"
|
166
170
|
msg += " from #{exp_orig.inspect}" if $DEBUG
|
@@ -168,30 +172,39 @@ class SexpProcessor
|
|
168
172
|
end
|
169
173
|
end
|
170
174
|
|
171
|
-
|
172
|
-
|
175
|
+
##
|
176
|
+
# Rewrite +exp+ using rewrite_* method for +exp+'s sexp_type, if one
|
177
|
+
# exists.
|
178
|
+
|
179
|
+
def rewrite exp
|
180
|
+
type = exp.sexp_type
|
181
|
+
|
182
|
+
comments = exp.comments
|
173
183
|
|
174
|
-
if @debug.
|
184
|
+
if @debug.key? type then
|
175
185
|
str = exp.inspect
|
176
186
|
puts "// DEBUG (original ): #{str}" if str =~ @debug[type]
|
177
187
|
end
|
178
188
|
|
179
189
|
in_context type do
|
180
|
-
exp.map
|
190
|
+
exp = exp.map { |sub| Array === sub ? rewrite(sub) : sub }
|
181
191
|
end
|
182
192
|
|
183
|
-
|
193
|
+
loop do
|
184
194
|
meth = @rewriters[type]
|
185
195
|
exp = self.send(meth, exp) if meth
|
186
196
|
break unless Sexp === exp
|
187
197
|
|
188
|
-
if @debug.
|
198
|
+
if @debug.key? type then
|
189
199
|
str = exp.inspect
|
190
200
|
puts "// DEBUG (rewritten): #{str}" if str =~ @debug[type]
|
191
201
|
end
|
192
202
|
|
193
|
-
old_type, type = type, exp.
|
194
|
-
|
203
|
+
old_type, type = type, exp.sexp_type
|
204
|
+
break if old_type == type
|
205
|
+
end
|
206
|
+
|
207
|
+
exp.comments = comments
|
195
208
|
|
196
209
|
exp
|
197
210
|
end
|
@@ -201,8 +214,13 @@ class SexpProcessor
|
|
201
214
|
# the Sexp type given. Performs additional checks as specified by
|
202
215
|
# the initializer.
|
203
216
|
|
204
|
-
def process
|
217
|
+
def process exp
|
205
218
|
return nil if exp.nil?
|
219
|
+
|
220
|
+
unless Sexp === exp then
|
221
|
+
raise SexpTypeError, "exp must be a Sexp, was #{exp.class}:#{exp.inspect}"
|
222
|
+
end
|
223
|
+
|
206
224
|
if self.context.empty? then
|
207
225
|
p :rewriting unless debug.empty?
|
208
226
|
exp = self.rewrite(exp)
|
@@ -210,7 +228,7 @@ class SexpProcessor
|
|
210
228
|
end
|
211
229
|
|
212
230
|
unless @unsupported_checked then
|
213
|
-
m = public_methods.grep(/^process_/) { |o| o.to_s.sub(/^process_/,
|
231
|
+
m = public_methods.grep(/^process_/) { |o| o.to_s.sub(/^process_/, "").to_sym }
|
214
232
|
supported = m - (m - @unsupported)
|
215
233
|
|
216
234
|
raise UnsupportedNodeError, "#{supported.inspect} shouldn't be in @unsupported" unless supported.empty?
|
@@ -220,19 +238,19 @@ class SexpProcessor
|
|
220
238
|
|
221
239
|
result = self.expected.new
|
222
240
|
|
223
|
-
type = exp.
|
241
|
+
type = exp.sexp_type
|
224
242
|
raise "type should be a Symbol, not: #{exp.first.inspect}" unless
|
225
243
|
Symbol === type
|
226
244
|
|
227
245
|
in_context type do
|
228
|
-
if @debug.
|
246
|
+
if @debug.key? type then
|
229
247
|
str = exp.inspect
|
230
248
|
puts "// DEBUG:(original ): #{str}" if str =~ @debug[type]
|
231
249
|
end
|
232
250
|
|
233
251
|
exp_orig = nil
|
234
252
|
exp_orig = exp.deep_clone if $DEBUG or
|
235
|
-
@debug.
|
253
|
+
@debug.key? type or @exceptions.key?(type)
|
236
254
|
|
237
255
|
raise UnsupportedNodeError, "'#{type}' is not a supported node type" if
|
238
256
|
@unsupported.include? type
|
@@ -245,40 +263,44 @@ class SexpProcessor
|
|
245
263
|
warn "WARNING: Using default method #{meth} for #{type}"
|
246
264
|
end
|
247
265
|
|
248
|
-
exp.
|
266
|
+
exp = exp.sexp_body if @auto_shift_type and meth != @default_method # HACK
|
249
267
|
|
250
|
-
result = error_handler(type, exp_orig)
|
251
|
-
self.send
|
252
|
-
|
268
|
+
result = error_handler(type, exp_orig) {
|
269
|
+
self.send meth, exp
|
270
|
+
}
|
253
271
|
|
254
|
-
if @debug.
|
272
|
+
if @debug.key? type then
|
255
273
|
str = exp.inspect
|
256
274
|
puts "// DEBUG (processed): #{str}" if str =~ @debug[type]
|
257
275
|
end
|
258
276
|
|
259
|
-
raise SexpTypeError, "Result must be a #{@expected}, was #{result.class}:#{result.inspect}" unless
|
277
|
+
raise SexpTypeError, "Result of #{type} must be a #{@expected}, was #{result.class}:#{result.inspect}" unless
|
278
|
+
@expected === result
|
260
279
|
|
261
280
|
self.assert_empty(meth, exp, exp_orig) if @require_empty
|
262
281
|
else
|
263
282
|
unless @strict then
|
264
283
|
until exp.empty? do
|
265
|
-
sub_exp = exp
|
284
|
+
sub_exp, *exp = exp # HACK
|
266
285
|
sub_result = nil
|
267
286
|
if Array === sub_exp then
|
268
287
|
sub_result = error_handler(type, exp_orig) do
|
269
288
|
process(sub_exp)
|
270
289
|
end
|
271
290
|
raise "Result is a bad type" unless Array === sub_exp
|
272
|
-
raise "Result does not have a type in front: #{sub_exp.inspect}" unless
|
291
|
+
raise "Result does not have a type in front: #{sub_exp.inspect}" unless
|
292
|
+
Symbol === sub_exp.sexp_type unless
|
293
|
+
sub_exp.empty?
|
273
294
|
else
|
274
295
|
sub_result = sub_exp
|
275
296
|
end
|
276
|
-
result << sub_result
|
297
|
+
# result << sub_result
|
298
|
+
result = result.class.new(*result, sub_result) # HACK
|
277
299
|
end
|
278
300
|
|
279
301
|
# NOTE: this is costly, but we are in the generic processor
|
280
302
|
# so we shouldn't hit it too much with RubyToC stuff at least.
|
281
|
-
result.
|
303
|
+
result.c_type ||= exp.c_type if Sexp === exp and exp.respond_to?(:c_type)
|
282
304
|
else
|
283
305
|
msg = "Bug! Unknown node-type #{type.inspect} to #{self.class}"
|
284
306
|
msg += " in #{exp_orig.inspect} from #{caller.inspect}" if $DEBUG
|
@@ -293,28 +315,26 @@ class SexpProcessor
|
|
293
315
|
##
|
294
316
|
# Raises unless the Sexp type for +list+ matches +typ+
|
295
317
|
|
296
|
-
def assert_type
|
318
|
+
def assert_type list, typ
|
297
319
|
raise SexpTypeError, "Expected type #{typ.inspect} in #{list.inspect}" if
|
298
320
|
not Array === list or list.first != typ
|
299
321
|
end
|
300
322
|
|
301
|
-
def error_handler
|
302
|
-
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
end
|
311
|
-
end
|
323
|
+
def error_handler type, exp = nil # :nodoc:
|
324
|
+
yield
|
325
|
+
rescue StandardError => err
|
326
|
+
return @exceptions[type].call self, exp, err if @exceptions.key? type
|
327
|
+
|
328
|
+
warn "#{err.class} Exception thrown while processing #{type} for sexp #{exp.inspect} #{caller.inspect}" if
|
329
|
+
$DEBUG
|
330
|
+
|
331
|
+
raise
|
312
332
|
end
|
313
333
|
|
314
334
|
##
|
315
335
|
# Registers an error handler for +node+
|
316
336
|
|
317
|
-
def on_error_in
|
337
|
+
def on_error_in node_type, &block
|
318
338
|
@exceptions[node_type] = block
|
319
339
|
end
|
320
340
|
|
@@ -329,13 +349,9 @@ class SexpProcessor
|
|
329
349
|
# return s(:dummy, process(exp), s(:extra, 42))
|
330
350
|
# end
|
331
351
|
|
332
|
-
def process_dummy
|
352
|
+
def process_dummy exp
|
333
353
|
result = @expected.new(:dummy) rescue @expected.new
|
334
|
-
|
335
|
-
until exp.empty? do
|
336
|
-
result << self.process(exp.shift)
|
337
|
-
end
|
338
|
-
|
354
|
+
result << self.process(exp.shift) until exp.empty?
|
339
355
|
result
|
340
356
|
end
|
341
357
|
|
@@ -362,11 +378,16 @@ class SexpProcessor
|
|
362
378
|
env.scope(&block)
|
363
379
|
end
|
364
380
|
|
381
|
+
##
|
382
|
+
# Track a stack of contexts that the processor is in, pushing on
|
383
|
+
# +type+ yielding, and then removing the context from the stack.
|
384
|
+
|
365
385
|
def in_context type
|
366
386
|
self.context.unshift type
|
367
387
|
|
368
388
|
yield
|
369
389
|
|
390
|
+
ensure
|
370
391
|
self.context.shift
|
371
392
|
end
|
372
393
|
|
@@ -376,35 +397,55 @@ class SexpProcessor
|
|
376
397
|
# itches too much...
|
377
398
|
|
378
399
|
class Environment
|
379
|
-
def initialize
|
400
|
+
def initialize #:nodoc:
|
380
401
|
@env = []
|
381
402
|
@env.unshift({})
|
382
403
|
end
|
383
404
|
|
405
|
+
##
|
406
|
+
# Flatten out all scopes and return all key/value pairs.
|
407
|
+
|
384
408
|
def all
|
385
409
|
@env.reverse.inject { |env, scope| env.merge scope }
|
386
410
|
end
|
387
411
|
|
412
|
+
##
|
413
|
+
# Return the current number of scopes.
|
414
|
+
|
388
415
|
def depth
|
389
416
|
@env.length
|
390
417
|
end
|
391
418
|
|
392
419
|
# TODO: depth_of
|
393
420
|
|
421
|
+
##
|
422
|
+
# Get +name+ from env at whatever scope it is defined in, or return nil.
|
423
|
+
|
394
424
|
def [] name
|
395
|
-
hash = @env.find { |closure| closure.
|
425
|
+
hash = @env.find { |closure| closure.key? name }
|
396
426
|
hash[name] if hash
|
397
427
|
end
|
398
428
|
|
429
|
+
##
|
430
|
+
# If +name+ exists in the env, set it to +val+ in whatever scope
|
431
|
+
# it is in. If it doesn't exist, set +name+ to +val+ in the
|
432
|
+
# current scope.
|
433
|
+
|
399
434
|
def []= name, val
|
400
|
-
hash = @env.find { |closure| closure.
|
435
|
+
hash = @env.find { |closure| closure.key? name } || current
|
401
436
|
hash[name] = val
|
402
437
|
end
|
403
438
|
|
439
|
+
##
|
440
|
+
# Get the current/top environment.
|
441
|
+
|
404
442
|
def current
|
405
443
|
@env.first
|
406
444
|
end
|
407
445
|
|
446
|
+
##
|
447
|
+
# Create a new scope and yield to the block passed.
|
448
|
+
|
408
449
|
def scope
|
409
450
|
@env.unshift({})
|
410
451
|
begin
|
@@ -423,7 +464,7 @@ end
|
|
423
464
|
# AKA, an interpreter.
|
424
465
|
|
425
466
|
class SexpInterpreter < SexpProcessor
|
426
|
-
def initialize
|
467
|
+
def initialize #:nodoc:
|
427
468
|
super
|
428
469
|
|
429
470
|
self.expected = Object
|
@@ -442,9 +483,30 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
442
483
|
@@no_class = :main
|
443
484
|
@@no_method = :none
|
444
485
|
|
445
|
-
|
486
|
+
##
|
487
|
+
# A stack of the classes/modules that are being processed
|
446
488
|
|
447
|
-
|
489
|
+
attr_reader :class_stack
|
490
|
+
|
491
|
+
##
|
492
|
+
# A stack of the methods that are being processed. You'd think it'd
|
493
|
+
# only ever be 1 deep, but you'd be wrong. People do terrible things
|
494
|
+
# in/to ruby.
|
495
|
+
|
496
|
+
attr_reader :method_stack
|
497
|
+
|
498
|
+
##
|
499
|
+
# A stack of the singleton classes that are being processed.
|
500
|
+
|
501
|
+
attr_reader :sclass
|
502
|
+
|
503
|
+
##
|
504
|
+
# A lookup table of all the method locations that have been
|
505
|
+
# processed so far.
|
506
|
+
|
507
|
+
attr_reader :method_locations
|
508
|
+
|
509
|
+
def initialize #:nodoc:
|
448
510
|
super
|
449
511
|
@sclass = []
|
450
512
|
@class_stack = []
|
@@ -458,7 +520,7 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
458
520
|
|
459
521
|
def in_klass name
|
460
522
|
if Sexp === name then
|
461
|
-
name = case name.
|
523
|
+
name = case name.sexp_type
|
462
524
|
when :colon2 then
|
463
525
|
name = name.flatten
|
464
526
|
name.delete :const
|
@@ -483,7 +545,7 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
483
545
|
##
|
484
546
|
# Adds name to the method stack, for the duration of the block
|
485
547
|
|
486
|
-
def in_method name, file, line, line_max=nil
|
548
|
+
def in_method name, file, line, line_max = nil
|
487
549
|
method_name = Regexp === name ? name.inspect : name.to_s
|
488
550
|
@method_stack.unshift method_name
|
489
551
|
line_max = "-#{line_max}" if line_max
|
@@ -514,10 +576,10 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
514
576
|
def klass_name
|
515
577
|
name = @class_stack.first
|
516
578
|
|
517
|
-
if Sexp === name
|
518
|
-
|
519
|
-
|
520
|
-
@class_stack.reverse.join("::").sub(/\([^\)]+\)$/,
|
579
|
+
raise "you shouldn't see me" if Sexp === name
|
580
|
+
|
581
|
+
if @class_stack.any?
|
582
|
+
@class_stack.reverse.join("::").sub(/\([^\)]+\)$/, "")
|
521
583
|
else
|
522
584
|
@@no_class
|
523
585
|
end
|
@@ -535,10 +597,10 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
535
597
|
|
536
598
|
##
|
537
599
|
# Process a class node until empty. Tracks all nesting. If you have
|
538
|
-
# to subclass and override this method, you can
|
600
|
+
# to subclass and override this method, you can call super with a
|
539
601
|
# block.
|
540
602
|
|
541
|
-
def process_class
|
603
|
+
def process_class exp
|
542
604
|
exp.shift unless auto_shift_type # node type
|
543
605
|
in_klass exp.shift do
|
544
606
|
if block_given? then
|
@@ -555,7 +617,7 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
555
617
|
# have to subclass and override this method, you can clall super
|
556
618
|
# with a block.
|
557
619
|
|
558
|
-
def process_defn
|
620
|
+
def process_defn exp
|
559
621
|
exp.shift unless auto_shift_type # node type
|
560
622
|
name = @sclass.empty? ? exp.shift : "::#{exp.shift}"
|
561
623
|
|
@@ -574,7 +636,7 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
574
636
|
# If you have to subclass and override this method, you can clall
|
575
637
|
# super with a block.
|
576
638
|
|
577
|
-
def process_defs
|
639
|
+
def process_defs exp
|
578
640
|
exp.shift unless auto_shift_type # node type
|
579
641
|
process exp.shift # recv
|
580
642
|
in_method "::#{exp.shift}", exp.file, exp.line, exp.line_max do
|
@@ -592,7 +654,7 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
592
654
|
# to subclass and override this method, you can clall super with a
|
593
655
|
# block.
|
594
656
|
|
595
|
-
def process_module
|
657
|
+
def process_module exp
|
596
658
|
exp.shift unless auto_shift_type # node type
|
597
659
|
in_klass exp.shift do
|
598
660
|
if block_given? then
|
@@ -609,7 +671,7 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
609
671
|
# you have to subclass and override this method, you can clall super
|
610
672
|
# with a block.
|
611
673
|
|
612
|
-
def process_sclass
|
674
|
+
def process_sclass exp
|
613
675
|
exp.shift unless auto_shift_type # node type
|
614
676
|
in_sklass do
|
615
677
|
if block_given? then
|
@@ -651,7 +713,7 @@ class MethodBasedSexpProcessor < SexpProcessor
|
|
651
713
|
end
|
652
714
|
end
|
653
715
|
|
654
|
-
class Object
|
716
|
+
class Object # :nodoc:
|
655
717
|
|
656
718
|
##
|
657
719
|
# deep_clone is the usual Marshalling hack to make a deep copy.
|
data/lib/strict_sexp.rb
ADDED
@@ -0,0 +1,126 @@
|
|
1
|
+
# :stopdoc:
|
2
|
+
|
3
|
+
##
|
4
|
+
# I'm starting to warm up to this idea!
|
5
|
+
# ENV["STRICT_SEXP"] turns on various levels of conformance checking
|
6
|
+
#
|
7
|
+
# 1 = sexp[0] => sexp_type
|
8
|
+
# 1 = sexp.first => sexp_type
|
9
|
+
# 1 = sexp[0] = x => sexp_type = x
|
10
|
+
# 1 = sexp[1..-1] => sexp_body
|
11
|
+
# 1 = sexp[1..-1] = x => sexp_body = x
|
12
|
+
# 1 = sexp[-1] => last
|
13
|
+
# 2 = sexp[1] => no
|
14
|
+
# 2 = sexp[1] = x => no
|
15
|
+
# 3 = sexp[n] => no
|
16
|
+
# 3 = sexp[n] = x => no
|
17
|
+
# 3 = sexp.node_name => no (ie, method_missing)
|
18
|
+
# 4 = sexp.replace x => no
|
19
|
+
# 4 = sexp.concat x => no
|
20
|
+
# 4 = sexp.collect! => no
|
21
|
+
# 4 = sexp.compact! => no
|
22
|
+
# 4 = sexp.flatten! => no
|
23
|
+
# 4 = sexp.map! => no
|
24
|
+
# 4 = sexp.reject! => no
|
25
|
+
# 4 = sexp.reverse! => no
|
26
|
+
# 4 = sexp.rotate! => no
|
27
|
+
# 4 = sexp.select! => no
|
28
|
+
# 4 = sexp.shuffle! => no
|
29
|
+
# 4 = sexp.slice! => no
|
30
|
+
# 4 = sexp.sort! => no
|
31
|
+
# 4 = sexp.sort_by! => no
|
32
|
+
# 4 = sexp.uniq! => no
|
33
|
+
# 4 = sexp.unshift => no
|
34
|
+
# 4 = sexp.push => no
|
35
|
+
# 4 = sexp.pop => no
|
36
|
+
# 4 = sexp << => no
|
37
|
+
|
38
|
+
class Sexp
|
39
|
+
alias :safe_idx :[]
|
40
|
+
alias :safe_asgn :[]=
|
41
|
+
alias :sexp_type= :sexp_type=
|
42
|
+
alias :sexp_body= :sexp_body=
|
43
|
+
alias :shift :shift
|
44
|
+
|
45
|
+
def self.nuke_method name, level
|
46
|
+
define_method name do |*args|
|
47
|
+
raise "no: %p.%s %p" % [self, name, args]
|
48
|
+
end if __strict >= level
|
49
|
+
end
|
50
|
+
|
51
|
+
def self.__strict
|
52
|
+
ENV["STRICT_SEXP"].to_i
|
53
|
+
end
|
54
|
+
|
55
|
+
def __strict
|
56
|
+
self.class.__strict
|
57
|
+
end
|
58
|
+
|
59
|
+
undef_method :method_missing if __strict > 2
|
60
|
+
|
61
|
+
def method_missing msg, *args
|
62
|
+
raise "don't call method_missing on Sexps: %p.(%s)" % [msg, args.inspect[1..-2]]
|
63
|
+
end if __strict > 2
|
64
|
+
|
65
|
+
def [] i
|
66
|
+
raise "no idx: #{inspect}[#{i}]" if __strict > 2
|
67
|
+
raise "no idx>1: #{inspect}[#{i}]" if Integer === i && i > 1 if __strict > 1
|
68
|
+
raise "use sexp_type" if i == 0
|
69
|
+
raise "use sexp_body" if i == (1..-1)
|
70
|
+
raise "use last" if i == -1
|
71
|
+
self.safe_idx i
|
72
|
+
end
|
73
|
+
|
74
|
+
def []= i, v
|
75
|
+
raise "use sexp_type=" if i == 0
|
76
|
+
raise "use sexp_body=" if i == (1..-1)
|
77
|
+
raise "no asgn>1: #{inspect}[#{i}] = #{v.inspect}" if Integer === i && i > 1 if
|
78
|
+
__strict > 1
|
79
|
+
raise "no asgn: #{inspect}[#{i}] = #{v.inspect}" if
|
80
|
+
__strict > 2
|
81
|
+
self.safe_asgn i, v
|
82
|
+
end
|
83
|
+
|
84
|
+
def first
|
85
|
+
raise "use sexp_type"
|
86
|
+
end
|
87
|
+
|
88
|
+
nuke_method :collect!, 4
|
89
|
+
nuke_method :compact!, 4
|
90
|
+
nuke_method :concat, 4
|
91
|
+
nuke_method :flatten!, 4
|
92
|
+
nuke_method :map!, 4
|
93
|
+
nuke_method :pop, 4
|
94
|
+
nuke_method :push, 4
|
95
|
+
nuke_method :reject!, 4
|
96
|
+
nuke_method :replace, 4
|
97
|
+
nuke_method :reverse!, 4
|
98
|
+
nuke_method :rotate!, 4
|
99
|
+
nuke_method :select!, 4
|
100
|
+
nuke_method :shuffle!, 4
|
101
|
+
nuke_method :slice!, 4
|
102
|
+
nuke_method :sort!, 4
|
103
|
+
nuke_method :sort_by!, 4
|
104
|
+
nuke_method :uniq!, 4
|
105
|
+
nuke_method :unshift, 4
|
106
|
+
nuke_method :<<, 5
|
107
|
+
nuke_method :shift, 5
|
108
|
+
|
109
|
+
def sexp_type
|
110
|
+
safe_idx 0
|
111
|
+
end
|
112
|
+
|
113
|
+
def sexp_body from = 1
|
114
|
+
safe_idx from..-1
|
115
|
+
end
|
116
|
+
|
117
|
+
def sexp_type= v
|
118
|
+
self.safe_asgn 0, v
|
119
|
+
end
|
120
|
+
|
121
|
+
def sexp_body= v
|
122
|
+
self.safe_asgn 1..-1, v
|
123
|
+
end
|
124
|
+
end unless Sexp.new.respond_to? :safe_asgn if ENV["STRICT_SEXP"]
|
125
|
+
|
126
|
+
# :startdoc:
|