Module#private_filter: critique of dynamic method visibility

The following fancy function does some pretty delicate handling of
method visibility. And as such I would really like to get some extra
eyes on it. I wonder, is it worth it? Can it be improved? Is there a
whole better way of dealing? Etc.

The idea is to be able to define a pattern of methods that will be
granted public visibility, while all others are kept private, even when
new methods are added dynamically to Kernel or Object.

I’m currently using it like so:

class OpenObject < Hash
private_filter //

def method_missing(sym,*args)

end
end

Thanks,
T.

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 a class

after private_filter is defined will show up in the list of public

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 test

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