module Super
  module S1
    class A
      def foo(a)
        a << "A#foo"
        bar(a)
      end
      def bar(a)
        a << "A#bar"
      end
    end
    class B < A
      def foo(a)
        a << "B#foo"
        super(a)
      end
      def bar(a)
        a << "B#bar"
        super(a)
      end
    end
  end
  
  module S2
    class A
      def baz(a)
        a << "A#baz"
      end
    end
    class B < A
      def foo(a)
        a << "B#foo"
        baz(a)
      end
    end
    class C < B
      def baz(a)
        a << "C#baz"
        super(a)
      end
    end
  end
  
  module S3
    class A
      def foo(a)
        a << "A#foo"
      end
      def self.foo(a)
        a << "A::foo"
      end
      def self.bar(a)
        a << "A::bar"
        foo(a)
      end
    end
    class B < A
      def self.foo(a)
        a << "B::foo"
        super(a)
      end
      def self.bar(a)
        a << "B::bar"
        super(a)
      end
    end
  end
  
  module S4
    class A
      def foo(a)
        a << "A#foo"
      end
    end
    class B < A
      def foo(a, b)
        a << "B#foo(a,#{b})"
        super(a)
      end
    end
  end

  class S5
    def here
      :good
    end
  end

  class S6 < S5
    def under
      yield
    end

    def here
      under {
        super
      }
    end
  end

  class S7 < S5
    define_method(:here) { super() }
  end

  module MS1
    module ModA
      def foo(a)
        a << "ModA#foo"
        bar(a)
      end      
      def bar(a)
        a << "ModA#bar"
      end
    end
    class A
      include ModA
    end
    module ModB
      def bar(a)
        a << "ModB#bar"
        super(a)
      end
    end
    class B < A    
      def foo(a)
        a << "B#foo"
        super(a)
      end
      include ModB
    end
  end
  # 
  # module MS2
  #   class A
  #     def baz(a)
  #       a << "A#baz"
  #     end
  #   end
  #   module ModB
  #     def foo(a)
  #       a << "ModB#foo"
  #       baz(a)
  #     end
  #   end
  #   class B < A
  #     include ModB
  #   end
  #   class C < B
  #     def baz(a)
  #       a << "C#baz"
  #       super(a)
  #     end
  #   end
  # end
  # 
  # module MS3
  #   module ModA
  #     def foo(a)
  #       a << "ModA#foo"
  #     end
  #     def bar(a)
  #       a << "ModA#bar"
  #       foo(a)
  #     end
  #   end
  #   class A
  #     def foo(a)
  #       a << "A#foo"
  #     end
  #     class << self
  #       include ModA
  #     end
  #   end
  #   class B < A
  #     def self.foo(a)
  #       a << "B::foo"
  #       super(a)
  #     end
  #     def self.bar(a)
  #       a << "B::bar"
  #       super(a)
  #     end
  #   end
  # end  
  # 
  # module MS4
  #   module Layer1
  #     def example
  #       5
  #     end
  #   end
  # 
  #   module Layer2
  #     include Layer1
  #     def example
  #       super
  #     end
  #   end
  # 
  #   class A
  #     include Layer2
  #     public :example
  #   end
  # end

  # class MM_A
  #    undef_method :is_a?
  #  end
  # 
  #  class MM_B < MM_A
  #    def is_a?(blah)
  #      # should fire the method_missing below
  #      super
  #    end
  # 
  #    def method_missing(*)
  #      false
  #    end
  #  end
  # 
  #  class Alias1
  #    def name
  #      [:alias1]
  #    end
  #  end
  # 
  #  class Alias2 < Alias1
  #    def initialize
  #      @times = 0
  #    end
  # 
  #    def name
  #      if @times >= 10
  #        raise "runaway super"
  #      end
  # 
  #      @times += 1
  # 
  #      # Use this so that we can see collect all supers that we see.
  #      # One bug that arises is that we call Alias2#name from Alias2#name
  #      # as it's superclass. In that case, either we get a runaway recursion
  #      # super OR we get the return value being [:alias2, :alias2, :alias1]
  #      # rather than [:alias2, :alias1].
  #      #
  #      # Which one depends on caches and how super is implemented.
  #      [:alias2] + super
  #    end
  #  end
  # 
  #  class Alias3 < Alias2
  #    alias_method :name3, :name
  #    # In the method table for Alias3 now should be a special alias entry
  #    # that references Alias2 and Alias2#name (probably as an object).
  #    #
  #    # When name3 is called then, Alias2 (NOT Alias3) is presented as the
  #    # current module to Alias2#name, so that when super is called,
  #    # Alias2->superclass is next.
  #    #
  #    # Otherwise, Alias2 is next, which is where name was to begin with,
  #    # causing the wrong #name method to be called.
  #  end
  # 
  #  module AliasWithSuper
  #    module AS1
  #      def foo
  #        :a
  #      end
  #    end
  # 
  #    module BS1
  #      def foo
  #        [:b, super]
  #      end
  #    end
  # 
  #    class Base
  #      extend AS1
  #      extend BS1
  #    end
  # 
  #    class Trigger < Base
  #      class << self
  #        def foo_quux
  #          foo_baz
  #        end
  # 
  #        alias_method :foo_baz, :foo
  #        alias_method :foo, :foo_quux
  #      end
  #    end
  #  end
  
end