Created
June 24, 2009 14:09
-
-
Save trans/135295 to your computer and use it in GitHub Desktop.
Dynamically Privatize Methods
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # Method Filter - Dynamically Privatize New Methods | |
| # | |
| # Since Ruby is very dynamic, methods added to Object will show | |
| # up in the list of available methods of subclasses. If we are trying to privatize | |
| # methods to get them out of the way for method_missing, then this could pose | |
| # a problem. We handle this by defining hooks in Object, Kernel and Module | |
| # that will hide any method so defined automatically. | |
| # | |
| # This is rather useless now that Ruby 1.9 provides BasicObject. | |
| 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 | |
| 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment