Module#private_filter: critique of dynamic method visibility

T

transfire

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( :eek:bject_id, x.object_id )
end

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

end

=end
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,968
Messages
2,570,153
Members
46,701
Latest member
XavierQ83

Latest Threads

Top