其实这个类实现的功能很简单,那就是实现一个没有predefined 方法的类(除了__send__与__id__).自己也尝试着写了一个,思路什么和BlankSlate很接近,不过代码就丑陋多了。
当写这段代码之前,我们先要分析一下如何才能去掉predefined的方法,这里有三种predefined的方法。
1 Object类本身自带的一些实例方法.
2 打开Kernel模块,或者Object类,然后动态的加入的方法。
module Kernel
def name1
"bo"
end
end
class Object
def name2
"bo"
end
end
3 Object类include的模块里面所含有的方法:
module Name
def name3
"bo"
end
end
class Object
include Name
end
接下来看代码,我在里面会有注释 :
class BlankSlate
class << self
#首先,我们定义一个hide方法,这个方法就是隐藏掉BlankSlate类中名字为name的方法,可是instance_eval方法,或者__开头的方法,并不需要被隐藏.
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
#这个是为了恢复所被隐藏的方法,首先使用上面的方法查找到方法,(这里使用了define_method,这个方法其实也就是动态的定义一个方法,name就是他的名字,详细的用法可以看我前面的文章)
def reveal(name)
bound_method = nil
unbound_method = find_hidden_method(name)
fail "Don't know how to reveal method '#{name}'" unless unbound_method
define_method(name) do |*args|
bound_method ||= unbound_method.bind(self)
bound_method.call(*args)
end
end
end
#这里执行hide操作
instance_methods.each { |m| hide(m) }
end
######################################################################
#这里解决了第二个问题,那就是当一个方法被加入的时候,能够hide这个方法(这里使用了method_added(这个方法我认为是当加入了一个方法之后,然后就会调用这个方法,name就是你所加入的方法的名字).
module Kernel
class << self
alias_method :blank_slate_method_added, :method_added
def method_added(name)
result = blank_slate_method_added(name)
return result if self != Kernel
BlankSlate.hide(name)
result
end
end
end
这里其实我们也可以这么做:
module Kernel
class << self
# Detect method additions to Kernel and remove them in the
# BlankSlate class.
def method_added(name)
return super if self != Kernel
BlankSlate.hide(name)
super
end
end
end
######################################################################
#这个和上面一样的。
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
######################################################################
#这里是为了解决第三个问题,要注意的是append_features就是include时发生的动作,也就可以说,他其实就是include.所以这里我们必须先保存老的append_features方法,先加入mod方法,然后undef它,最后再返回其他的方法.
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