Class: MethodBasedSexpProcessor

Inherits:
SexpProcessor show all
Defined in:
lib/sexp_processor.rb

Overview

A simple subclass of SexpProcessor that tracks method and class stacks for you. Use #method_name, #klass_name, or #signature to refer to where you’re at in processing. If you have to subclass process_(class|module|defn|defs) you must call super.

Constant Summary collapse

@@no_class =
:main
@@no_method =
:none

Constants inherited from SexpProcessor

SexpProcessor::VERSION

Instance Attribute Summary collapse

Attributes inherited from SexpProcessor

#auto_shift_type, #context, #debug, #default_method, #env, #expected, #require_empty, #strict, #unsupported, #warn_on_default

Instance Method Summary collapse

Methods inherited from SexpProcessor

#assert_empty, #assert_type, #error_handler, expand_dirs_to_files, #in_context, #on_error_in, #process, #process_dummy, processors, #rewrite, rewriters, #scope

Constructor Details

#initializeMethodBasedSexpProcessor

:nodoc:



509
510
511
512
513
514
515
516
# File 'lib/sexp_processor.rb', line 509

def initialize #:nodoc:
  super
  @sclass              = []
  @class_stack         = []
  @method_stack        = []
  @method_locations    = {}
  self.require_empty   = false
end

Instance Attribute Details

#class_stackObject (readonly)

A stack of the classes/modules that are being processed



489
490
491
# File 'lib/sexp_processor.rb', line 489

def class_stack
  @class_stack
end

#method_locationsObject (readonly)

A lookup table of all the method locations that have been processed so far.



507
508
509
# File 'lib/sexp_processor.rb', line 507

def method_locations
  @method_locations
end

#method_stackObject (readonly)

A stack of the methods that are being processed. You’d think it’d only ever be 1 deep, but you’d be wrong. People do terrible things in/to ruby.



496
497
498
# File 'lib/sexp_processor.rb', line 496

def method_stack
  @method_stack
end

#sclassObject (readonly)

A stack of the singleton classes that are being processed.



501
502
503
# File 'lib/sexp_processor.rb', line 501

def sclass
  @sclass
end

Instance Method Details

#in_klass(name) ⇒ Object

Adds name to the class stack, for the duration of the block



521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# File 'lib/sexp_processor.rb', line 521

def in_klass name
  if Sexp === name then
    name = case name.sexp_type
           when :colon2 then
             name = name.flatten
             name.delete :const
             name.delete :colon2
             name.join("::")
           when :colon3 then
             name.last.to_s
           else
             raise "unknown type #{name.inspect}"
           end
  end

  @class_stack.unshift name

  with_new_method_stack do
    yield
  end
ensure
  @class_stack.shift
end

#in_method(name, file, line, line_max = nil) ⇒ Object

Adds name to the method stack, for the duration of the block



548
549
550
551
552
553
554
555
556
# File 'lib/sexp_processor.rb', line 548

def in_method name, file, line, line_max = nil
  method_name = Regexp === name ? name.inspect : name.to_s
  @method_stack.unshift method_name
  line_max = "-#{line_max}" if line_max
  @method_locations[signature] = "#{file}:#{line}#{line_max}"
  yield
ensure
  @method_stack.shift
end

#in_sklassObject

Tracks whether we’re in a singleton class or not. Doesn’t track actual receiver.



562
563
564
565
566
567
568
569
570
# File 'lib/sexp_processor.rb', line 562

def in_sklass
  @sclass.push true

  with_new_method_stack do
    yield
  end
ensure
  @sclass.pop
end

#klass_nameObject

Returns the first class in the list, or @@no_class if there are none.



576
577
578
579
580
581
582
583
584
585
586
# File 'lib/sexp_processor.rb', line 576

def klass_name
  name = @class_stack.first

  raise "you shouldn't see me" if Sexp === name

  if @class_stack.any?
    @class_stack.reverse.join("::").sub(/\([^\)]+\)$/, "")
  else
    @@no_class
  end
end

#method_nameObject

Returns the first method in the list, or “#none” if there are none.



592
593
594
595
596
# File 'lib/sexp_processor.rb', line 592

def method_name
  m = @method_stack.first || @@no_method
  m = "##{m}" unless m =~ /::/
  m
end

#process_class(exp) ⇒ Object

Process a class node until empty. Tracks all nesting. If you have to subclass and override this method, you can call super with a block.



603
604
605
606
607
608
609
610
611
612
613
# File 'lib/sexp_processor.rb', line 603

def process_class exp
  exp.shift unless auto_shift_type # node type
  in_klass exp.shift do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end

#process_defn(exp) ⇒ Object

Process a method node until empty. Tracks your location. If you have to subclass and override this method, you can clall super with a block.



620
621
622
623
624
625
626
627
628
629
630
631
632
# File 'lib/sexp_processor.rb', line 620

def process_defn exp
  exp.shift unless auto_shift_type # node type
  name = @sclass.empty? ? exp.shift : "::#{exp.shift}"

  in_method name, exp.file, exp.line, exp.line_max do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end

#process_defs(exp) ⇒ Object

Process a singleton method node until empty. Tracks your location. If you have to subclass and override this method, you can clall super with a block.



639
640
641
642
643
644
645
646
647
648
649
650
# File 'lib/sexp_processor.rb', line 639

def process_defs exp
  exp.shift unless auto_shift_type # node type
  process exp.shift # recv
  in_method "::#{exp.shift}", exp.file, exp.line, exp.line_max do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end

#process_module(exp) ⇒ Object

Process a module node until empty. Tracks all nesting. If you have to subclass and override this method, you can clall super with a block.



657
658
659
660
661
662
663
664
665
666
667
# File 'lib/sexp_processor.rb', line 657

def process_module exp
  exp.shift unless auto_shift_type # node type
  in_klass exp.shift do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end

#process_sclass(exp) ⇒ Object

Process a singleton class node until empty. Tracks all nesting. If you have to subclass and override this method, you can clall super with a block.



674
675
676
677
678
679
680
681
682
683
684
# File 'lib/sexp_processor.rb', line 674

def process_sclass exp
  exp.shift unless auto_shift_type # node type
  in_sklass do
    if block_given? then
      yield
    else
      process_until_empty exp
    end
  end
  s()
end

#process_until_empty(exp) ⇒ Object

Process each element of #exp in turn.



689
690
691
692
693
694
# File 'lib/sexp_processor.rb', line 689

def process_until_empty exp
  until exp.empty?
    sexp = exp.shift
    process sexp if Sexp === sexp
  end
end

#signatureObject

Returns the method signature for the current method.



699
700
701
# File 'lib/sexp_processor.rb', line 699

def signature
  "#{klass_name}#{method_name}"
end

#with_new_method_stackObject

Reset the method stack for the duration of the block. Used for class scoping.



707
708
709
710
711
712
713
# File 'lib/sexp_processor.rb', line 707

def with_new_method_stack
  old_method_stack, @method_stack = @method_stack, []

  yield
ensure
  @method_stack = old_method_stack
end