# Method Filter
#
# This is likely to be deprecated along with BasicObject.
# (Unless somone suggests a good reason to do otherwise.)

class Module

  STANDARD_FILTER = /(\?$|^(__|object_|instance_)|^(send|inspect|dup|clone|null|\W+)$)/

  @@private_filters = {}

  def private_filter( *filter )
    return @@private_filters[self] if filter.empty?
    filter.collect! do |f|
      if f == //
        STANDARD_FILTER
      elsif Regexp === f
        f
      else
        f.to_s
      end
    end
    @@private_filters[self] = filter
    public_instance_methods.each do |name|
      case name.to_s
      when *filter
#puts "public #{name}"
      else
#puts "private #{name}"
        private name
      end
    end
    filter
  end

  #
  #

  def self.filter(name)
    @@private_filters.each do |base, filter|
      case name.to_s
      when *base.private_filter
      else
        base.send(:private,name)
      end
    end
  end

end

# Since Ruby is very dynamic, methods added to the ancestors of
# BasicObject <em>after BasicObject is defined</em> will show up in the
# list of available BasicObject methods.  We handle this by defining
# hooks in Object, Kernel and Module that will hide any defined.

module Kernel
  class << self
    madded = method(:method_added)
    define_method(:method_added) do |name|
      r = madded.call(name)
      return r if self != Kernel
      Module.filter(name)
      r
    end
  end
end

# See Kernel callback.

class Object
  class << self
    madded = method(:method_added)
    define_method(:method_added) do |name|
      r = madded.call(name)
      return r if self != Object
      Module.filter(name)
      r
    end
  end
end



#  _____         _
# |_   _|__  ___| |_
#   | |/ _ \/ __| __|
#   | |  __/\__ \ |_
#   |_|\___||___/\__|
#

=begin testing

  require 'test/unit'

  class TestMethodFilter1 < Test::Unit::TestCase

    class X
      private_filter //
      def foo ; end
      def method_missing(name,*args)
        name
      end
    end

    def test_1_01
      x = X.new
      assert_equal( :class, x.class )
    end

    def test_1_02
      x = X.new
      assert_not_equal( :object_id, x.object_id )
    end

    def test_1_02
      x = X.new
      assert( x.respond_to?(:foo) )
    end

  end

=end
