123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109 |
- #!/usr/bin/env ruby
- #--
- # Copyright 2004, 2006 by Jim Weirich (jim@weirichhouse.org).
- # All rights reserved.
- # Permission is granted for use, copying, modification, distribution,
- # and distribution of modified versions of this work as long as the
- # above copyright notice is included.
- #++
- ######################################################################
- # BlankSlate provides an abstract base class with no predefined
- # methods (except for <tt>\_\_send__</tt> and <tt>\_\_id__</tt>).
- # BlankSlate is useful as a base class when writing classes that
- # depend upon <tt>method_missing</tt> (e.g. dynamic proxies).
- #
- class BlankSlate
- class << self
-
- # Hide the method named +name+ in the BlankSlate class. Don't
- # hide +instance_eval+ or any method beginning with "__".
- def hide(name)
- if instance_methods.include?(name.to_s) and
- name !~ /^(__|instance_eval)/
- @hidden_methods ||= {}
- @hidden_methods[name.to_sym] = instance_method(name)
- undef_method name
- end
- end
- def find_hidden_method(name)
- @hidden_methods ||= {}
- @hidden_methods[name] || superclass.find_hidden_method(name)
- end
- # Redefine a previously hidden method so that it may be called on a blank
- # slate object.
- def reveal(name)
- hidden_method = find_hidden_method(name)
- fail "Don't know how to reveal method '#{name}'" unless hidden_method
- define_method(name, hidden_method)
- end
- end
-
- instance_methods.each { |m| hide(m) }
- end
- ######################################################################
- # Since Ruby is very dynamic, methods added to the ancestors of
- # BlankSlate <em>after BlankSlate is defined</em> will show up in the
- # list of available BlankSlate methods. We handle this by defining a
- # hook in the Object and Kernel classes that will hide any method
- # defined after BlankSlate has been loaded.
- #
- module Kernel
- class << self
- alias_method :blank_slate_method_added, :method_added
- # Detect method additions to Kernel and remove them in the
- # BlankSlate class.
- def method_added(name)
- result = blank_slate_method_added(name)
- return result if self != Kernel
- BlankSlate.hide(name)
- result
- end
- end
- end
- ######################################################################
- # Same as above, except in Object.
- #
- class Object
- class << self
- alias_method :blank_slate_method_added, :method_added
- # Detect method additions to Object and remove them in the
- # BlankSlate class.
- def method_added(name)
- result = blank_slate_method_added(name)
- return result if self != Object
- BlankSlate.hide(name)
- result
- end
- def find_hidden_method(name)
- nil
- end
- end
- end
- ######################################################################
- # Also, modules included into Object need to be scanned and have their
- # instance methods removed from blank slate. In theory, modules
- # included into Kernel would have to be removed as well, but a
- # "feature" of Ruby prevents late includes into modules from being
- # exposed in the first place.
- #
- class Module
- alias blankslate_original_append_features append_features
- def append_features(mod)
- result = blankslate_original_append_features(mod)
- return result if mod != Object
- instance_methods.each do |name|
- BlankSlate.hide(name)
- end
- result
- end
- end
|