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

Returns a new instance of MethodBasedSexpProcessor.



452
453
454
455
456
457
458
459
# File 'lib/sexp_processor.rb', line 452

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

Instance Attribute Details

#class_stackObject (readonly)

Returns the value of attribute class_stack.



450
451
452
# File 'lib/sexp_processor.rb', line 450

def class_stack
  @class_stack
end

#method_locationsObject (readonly)

Returns the value of attribute method_locations.



450
451
452
# File 'lib/sexp_processor.rb', line 450

def method_locations
  @method_locations
end

#method_stackObject (readonly)

Returns the value of attribute method_stack.



450
451
452
# File 'lib/sexp_processor.rb', line 450

def method_stack
  @method_stack
end

#sclassObject (readonly)

Returns the value of attribute sclass.



450
451
452
# File 'lib/sexp_processor.rb', line 450

def sclass
  @sclass
end

Instance Method Details

#in_klass(name) ⇒ Object

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



464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
# File 'lib/sexp_processor.rb', line 464

def in_klass name
  if Sexp === name then
    name = case name.first
           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) ⇒ Object

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



491
492
493
494
495
496
497
498
# File 'lib/sexp_processor.rb', line 491

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

#in_sklassObject

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



504
505
506
507
508
509
510
511
512
# File 'lib/sexp_processor.rb', line 504

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.



518
519
520
521
522
523
524
525
526
527
528
# File 'lib/sexp_processor.rb', line 518

def klass_name
  name = @class_stack.first

  if Sexp === name then
    raise "you shouldn't see me"
  elsif @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.



534
535
536
537
538
# File 'lib/sexp_processor.rb', line 534

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 clall super with a block.



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

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.



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

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



580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/sexp_processor.rb', line 580

def process_defs(exp)
  exp.shift unless auto_shift_type # node type
  process exp.shift # recv
  in_method "::#{exp.shift}", exp.file, exp.line 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.



598
599
600
601
602
603
604
605
606
607
608
# File 'lib/sexp_processor.rb', line 598

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.



615
616
617
618
619
620
621
622
623
624
625
# File 'lib/sexp_processor.rb', line 615

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.



630
631
632
633
634
635
# File 'lib/sexp_processor.rb', line 630

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.



640
641
642
# File 'lib/sexp_processor.rb', line 640

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.



648
649
650
651
652
653
654
# File 'lib/sexp_processor.rb', line 648

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

  yield
ensure
  @method_stack = old_method_stack
end