From: transfire@... Date: 2006-07-16T10:59:53+09:00 Subject: 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