sexp_processor 4.3.0 → 4.4.0

Sign up to get free protection for your applications and to get access to all the features.
data.tar.gz.sig CHANGED
Binary file
data/History.txt CHANGED
@@ -1,3 +1,9 @@
1
+ === 4.4.0 / 2013-10-18
2
+
3
+ * 1 minor enhancement:
4
+
5
+ * Added MethodBasedSexpProcessor, extracted from Flog.
6
+
1
7
  === 4.3.0 / 2013-08-19
2
8
 
3
9
  * 1 minor enhancement:
@@ -33,7 +33,7 @@ require 'sexp'
33
33
 
34
34
  class SexpProcessor
35
35
 
36
- VERSION = "4.3.0"
36
+ VERSION = "4.4.0"
37
37
 
38
38
  ##
39
39
  # Automatically shifts off the Sexp type before handing the
@@ -404,6 +404,205 @@ class SexpInterpreter < SexpProcessor
404
404
  end
405
405
  end
406
406
 
407
+ ##
408
+ # A simple subclass of SexpProcessor that tracks method and class
409
+ # stacks for you. Use #method_name, #klass_name, or #signature to
410
+ # refer to where you're at in processing. If you have to subclass
411
+ # process_(class|module|defn|defs) you _must_ call super.
412
+
413
+ class MethodBasedSexpProcessor < SexpProcessor
414
+ @@no_class = :main
415
+ @@no_method = :none
416
+
417
+ attr_reader :class_stack, :method_stack, :sclass, :method_locations
418
+
419
+ def initialize
420
+ super
421
+ @sclass = []
422
+ @class_stack = []
423
+ @method_stack = []
424
+ @method_locations = {}
425
+ self.require_empty = false
426
+ end
427
+
428
+ ##
429
+ # Adds name to the class stack, for the duration of the block
430
+
431
+ def in_klass name
432
+ if Sexp === name then
433
+ name = case name.first
434
+ when :colon2 then
435
+ name = name.flatten
436
+ name.delete :const
437
+ name.delete :colon2
438
+ name.join("::")
439
+ when :colon3 then
440
+ name.last.to_s
441
+ else
442
+ raise "unknown type #{name.inspect}"
443
+ end
444
+ end
445
+
446
+ @class_stack.unshift name
447
+ yield
448
+ ensure
449
+ @class_stack.shift
450
+ end
451
+
452
+ ##
453
+ # Adds name to the method stack, for the duration of the block
454
+
455
+ def in_method(name, file, line)
456
+ method_name = Regexp === name ? name.inspect : name.to_s
457
+ @method_stack.unshift method_name
458
+ @method_locations[signature] = "#{file}:#{line}"
459
+ yield
460
+ ensure
461
+ @method_stack.shift
462
+ end
463
+
464
+ ##
465
+ # Tracks whether we're in a singleton class or not. Doesn't track
466
+ # actual receiver.
467
+
468
+ def in_sklass
469
+ @sclass.push true
470
+ yield
471
+ ensure
472
+ @sclass.pop
473
+ end
474
+
475
+ ##
476
+ # Returns the first class in the list, or @@no_class if there are
477
+ # none.
478
+
479
+ def klass_name
480
+ name = @class_stack.first
481
+
482
+ if Sexp === name then
483
+ raise "you shouldn't see me"
484
+ elsif @class_stack.any?
485
+ @class_stack.reverse.join("::").sub(/\([^\)]+\)$/, '')
486
+ else
487
+ @@no_class
488
+ end
489
+ end
490
+
491
+ ##
492
+ # Returns the first method in the list, or "#none" if there are
493
+ # none.
494
+
495
+ def method_name
496
+ m = @method_stack.first || @@no_method
497
+ m = "##{m}" unless m =~ /::/
498
+ m
499
+ end
500
+
501
+ ##
502
+ # Process a class node until empty. Tracks all nesting. If you have
503
+ # to subclass and override this method, you can clall super with a
504
+ # block.
505
+
506
+ def process_class(exp)
507
+ exp.shift unless auto_shift_type # node type
508
+ in_klass exp.shift do
509
+ if block_given? then
510
+ yield
511
+ else
512
+ process_until_empty exp
513
+ end
514
+ end
515
+ s()
516
+ end
517
+
518
+ ##
519
+ # Process a method node until empty. Tracks your location. If you
520
+ # have to subclass and override this method, you can clall super
521
+ # with a block.
522
+
523
+ def process_defn(exp)
524
+ exp.shift unless auto_shift_type # node type
525
+ name = @sclass.empty? ? exp.shift : "::#{exp.shift}"
526
+ in_method name, exp.file, exp.line do
527
+ if block_given? then
528
+ yield
529
+ else
530
+ process_until_empty exp
531
+ end
532
+ end
533
+ s()
534
+ end
535
+
536
+ ##
537
+ # Process a singleton method node until empty. Tracks your location.
538
+ # If you have to subclass and override this method, you can clall
539
+ # super with a block.
540
+
541
+ def process_defs(exp)
542
+ exp.shift unless auto_shift_type # node type
543
+ process exp.shift # recv
544
+ in_method "::#{exp.shift}", exp.file, exp.line do
545
+ if block_given? then
546
+ yield
547
+ else
548
+ process_until_empty exp
549
+ end
550
+ end
551
+ s()
552
+ end
553
+
554
+ ##
555
+ # Process a module node until empty. Tracks all nesting. If you have
556
+ # to subclass and override this method, you can clall super with a
557
+ # block.
558
+
559
+ def process_module(exp)
560
+ exp.shift unless auto_shift_type # node type
561
+ in_klass exp.shift do
562
+ if block_given? then
563
+ yield
564
+ else
565
+ process_until_empty exp
566
+ end
567
+ end
568
+ s()
569
+ end
570
+
571
+ ##
572
+ # Process a singleton class node until empty. Tracks all nesting. If
573
+ # you have to subclass and override this method, you can clall super
574
+ # with a block.
575
+
576
+ def process_sclass(exp)
577
+ exp.shift unless auto_shift_type # node type
578
+ in_sklass do
579
+ if block_given? then
580
+ yield
581
+ else
582
+ process_until_empty exp
583
+ end
584
+ end
585
+ s()
586
+ end
587
+
588
+ ##
589
+ # Process each element of #exp in turn.
590
+
591
+ def process_until_empty exp
592
+ until exp.empty?
593
+ sexp = exp.shift
594
+ process sexp if Sexp === sexp
595
+ end
596
+ end
597
+
598
+ ##
599
+ # Returns the method signature for the current method.
600
+
601
+ def signature
602
+ "#{klass_name}#{method_name}"
603
+ end
604
+ end
605
+
407
606
  class Object
408
607
 
409
608
  ##
@@ -295,3 +295,78 @@ class TestSexpProcessor < Minitest::Test
295
295
  def test_warn_on_default=; skip; end
296
296
 
297
297
  end
298
+
299
+ class TestMethodBasedSexpProcessor < Minitest::Test
300
+ attr_accessor :processor
301
+
302
+ def setup
303
+ self.processor = MethodBasedSexpProcessor.new
304
+ end
305
+
306
+ def test_in_klass
307
+ assert_empty processor.class_stack
308
+
309
+ processor.in_klass "xxx::yyy" do
310
+ assert_equal ["xxx::yyy"], processor.class_stack
311
+ end
312
+
313
+ assert_empty processor.class_stack
314
+ end
315
+
316
+ def test_in_method
317
+ assert_empty processor.method_stack
318
+
319
+ processor.in_method "xxx", "file.rb", 42 do
320
+ assert_equal ["xxx"], processor.method_stack
321
+ end
322
+
323
+ assert_empty processor.method_stack
324
+
325
+ expected = {"main#xxx" => "file.rb:42"}
326
+ assert_equal expected, processor.method_locations
327
+ end
328
+
329
+ def test_klass_name
330
+ assert_equal :main, processor.klass_name
331
+
332
+ processor.class_stack << "whatevs" << "flog"
333
+ assert_equal "flog::whatevs", processor.klass_name
334
+ end
335
+
336
+ def test_klass_name_sexp
337
+ processor.in_klass s(:colon2, s(:const, :X), :Y) do
338
+ assert_equal "X::Y", processor.klass_name
339
+ end
340
+
341
+ processor.in_klass s(:colon3, :Y) do
342
+ assert_equal "Y", processor.klass_name
343
+ end
344
+ end
345
+
346
+ def test_method_name
347
+ assert_equal "#none", processor.method_name
348
+
349
+ processor.method_stack << "whatevs"
350
+ assert_equal "#whatevs", processor.method_name
351
+ end
352
+
353
+ def test_method_name_cls
354
+ assert_equal "#none", processor.method_name
355
+
356
+ processor.method_stack << "::whatevs"
357
+ assert_equal "::whatevs", processor.method_name
358
+ end
359
+
360
+ def test_signature
361
+ assert_equal "main#none", processor.signature
362
+
363
+ processor.class_stack << "X"
364
+ assert_equal "X#none", processor.signature
365
+
366
+ processor.method_stack << "y"
367
+ assert_equal "X#y", processor.signature
368
+
369
+ processor.class_stack.shift
370
+ assert_equal "main#y", processor.signature
371
+ end
372
+ end
metadata CHANGED
@@ -1,13 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sexp_processor
3
3
  version: !ruby/object:Gem::Version
4
- hash: 51
4
+ hash: 47
5
5
  prerelease:
6
6
  segments:
7
7
  - 4
8
- - 3
8
+ - 4
9
9
  - 0
10
- version: 4.3.0
10
+ version: 4.4.0
11
11
  platform: ruby
12
12
  authors:
13
13
  - Ryan Davis
@@ -16,9 +16,9 @@ bindir: bin
16
16
  cert_chain:
17
17
  - |
18
18
  -----BEGIN CERTIFICATE-----
19
- MIIDPjCCAiagAwIBAgIBADANBgkqhkiG9w0BAQUFADBFMRMwEQYDVQQDDApyeWFu
19
+ MIIDPjCCAiagAwIBAgIBATANBgkqhkiG9w0BAQUFADBFMRMwEQYDVQQDDApyeWFu
20
20
  ZC1ydWJ5MRkwFwYKCZImiZPyLGQBGRYJemVuc3BpZGVyMRMwEQYKCZImiZPyLGQB
21
- GRYDY29tMB4XDTA5MDMwNjE4NTMxNVoXDTEwMDMwNjE4NTMxNVowRTETMBEGA1UE
21
+ GRYDY29tMB4XDTEzMDkxNjIzMDQxMloXDTE0MDkxNjIzMDQxMlowRTETMBEGA1UE
22
22
  AwwKcnlhbmQtcnVieTEZMBcGCgmSJomT8ixkARkWCXplbnNwaWRlcjETMBEGCgmS
23
23
  JomT8ixkARkWA2NvbTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALda
24
24
  b9DCgK+627gPJkB6XfjZ1itoOQvpqH1EXScSaba9/S2VF22VYQbXU1xQXL/WzCkx
@@ -28,15 +28,15 @@ cert_chain:
28
28
  qhtV7HJxNKuPj/JFH0D2cswvzznE/a5FOYO68g+YCuFi5L8wZuuM8zzdwjrWHqSV
29
29
  gBEfoTEGr7Zii72cx+sCAwEAAaM5MDcwCQYDVR0TBAIwADALBgNVHQ8EBAMCBLAw
30
30
  HQYDVR0OBBYEFEfFe9md/r/tj/Wmwpy+MI8d9k/hMA0GCSqGSIb3DQEBBQUAA4IB
31
- AQAY59gYvDxqSqgC92nAP9P8dnGgfZgLxP237xS6XxFGJSghdz/nI6pusfCWKM8m
32
- vzjjH2wUMSSf3tNudQ3rCGLf2epkcU13/rguI88wO6MrE0wi4ZqLQX+eZQFskJb/
33
- w6x9W1ur8eR01s397LSMexySDBrJOh34cm2AlfKr/jokKCTwcM0OvVZnAutaovC0
34
- l1SVZ0ecg88bsWHA0Yhh7NFxK1utWoIhtB6AFC/+trM0FQEB/jZkIS8SaNzn96Rl
35
- n0sZEf77FLf5peR8TP/PtmIg7Cyqz23sLM4mCOoTGIy5OcZ8TdyiyINUHtb5ej/T
36
- FBHgymkyj/AOSqKRIpXPhjC6
31
+ AQCFZ7JTzoy1gcG4d8A6dmOJy7ygtO5MFpRIz8HuKCF5566nOvpy7aHhDDzFmQuu
32
+ FX3zDU6ghx5cQIueDhf2SGOncyBmmJRRYawm3wI0o1MeN6LZJ/3cRaOTjSFy6+S6
33
+ zqDmHBp8fVA2TGJtO0BLNkbGVrBJjh0UPmSoGzWlRhEVnYC33TpDAbNA+u39UrQI
34
+ ynwhNN7YbnmSR7+JU2cUjBFv2iPBO+TGuWC+9L2zn3NHjuc6tnmSYipA9y8Hv+As
35
+ Y4evBVezr3SjXz08vPqRO5YRdO3zfeMT8gBjRqZjWJGMZ2lD4XNfrs7eky74CyZw
36
+ xx3n58i0lQkBE1EpKE0lFu/y
37
37
  -----END CERTIFICATE-----
38
38
 
39
- date: 2013-08-19 00:00:00 Z
39
+ date: 2013-10-18 00:00:00 Z
40
40
  dependencies:
41
41
  - !ruby/object:Gem::Dependency
42
42
  name: minitest
metadata.gz.sig CHANGED
Binary file