论坛首页 编程语言技术论坛

Rails每周一题(五): alias_method magic

浏览 1736 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2009-04-15   最后修改:2009-08-08

1. alias_method

 

    Makes new_name a new copy of the method old_name . This can be used to retain access to methods that are overridden.

 

 

 module Mod
   alias_method :orig_exit, :exit   # Without alias_method, you have no way to access orig exit.


   def exit(code=0)
     puts "Exiting with code #{code}"
     orig_exit(code)
   end
  end

   include Mod
   exit(99)
 

produces:

 

 

Exiting with code 99
 

2. alias_method_chain

   
    How this method arise? Yes, I guess always we will need to do this whenever we want to enhance a method.

 

alias_method :perform_action_without_benchmark, :perform_action # retain access to old method
alias_method :perform_action, :perform_action_with_benchmark

 

    The following do the same thing.

 

alias_method_chain :perform_action, :benchmark

 

    Take a look at the source code:

 

 

# File active_support/core_ext/module/aliasing.rb, line 23
def alias_method_chain(target, feature)
  # Strip out punctuation on predicates or bang methods since
  # e.g. target?_without_feature is not a valid method name.
  aliased_target, punctuation = target.to_s.sub(/([?!=])$/, ''), $1
  yield(aliased_target, punctuation) if block_given?

  with_method, without_method = "#{aliased_target}_with_#{feature}#{punctuation}", "#{aliased_target}_without_#{feature}#{punctuation}"

  alias_method without_method, target
  alias_method target, with_method

  case
    when public_method_defined?(without_method)
      public target
    when protected_method_defined?(without_method)
      protected target
    when private_method_defined?(without_method)
      private target
  end
end
 

    And it's a enhancement module for benchmarking.

 

 

module Benchmarking
  def self.included(base)
    base.extend(ClassMethods)
    base.class_eval do
      alias_method_chain :perform_action, :benchmark
      alias_method_chain :render, :benchmark
    end
  end
  .....  # where we difine perform_action_with_benchmark and render_with_benchmark
 

    Dynamic language is cool! It makes enhancing easily, what you just need to do is:

 

 

ActionController::Base.class_eval do
  include ActionController::Flash
  include ActionController::Benchmarking
  include ActionController::Caching
  ...
 

   And that's why DHH said, Rails 不是个庞然大物

论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics