`
simohayha
  • 浏览: 1386514 次
  • 性别: Icon_minigender_1
  • 来自: 火星
社区版块
存档分类
最新评论

rails中的BlankSlate源码分析

    博客分类:
  • ruby
阅读更多
其实这个类实现的功能很简单,那就是实现一个没有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


3
0
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics