Elvuel

善战者无赫赫之功

  • Home
  • Atom
  • About Elvuel

转-Method triggers:instead before after

Posted on January 25th, 2011 - 农历庚寅[虎]年 腊月廿二

原文:http://snippets.dzone.com/posts/show/3620

class Object

  def self.__rules__
  # container for defined rules, each item is:
  #   [class, event_name, method_name, alias_for_original_method, caller, comment]
    @@rules ||= []
  end

  def self.__create_rule_instead( method, comment = '', &block) # creates and returns new rule
    b_id = "%04x" % block.object_id
    old_method_name = :"__previous_#{method}_#{b_id}"
    alias_method old_method_name, method
    define_method method, &block
    __rules__ << rule = [self, "INSTEAD", method, old_method_name,caller[0], comment ]
    rule
  end

  def self.__create_rule_before( method, comment = '', &block)
    args = instance_method(method).arity == 0 ? '' : '(*args)'
    b_id = "%04x" % block.object_id
    old_method_name = :"__previous_#{method}_#{b_id}"
    alias_method old_method_name, method
    define_method :"__before_#{method}_#{b_id}", &block
    class_eval <<-EOT
      def #{method}#{args}
        __before_#{method}_#{b_id}#{args}
        __previous_#{method}_#{b_id}#{args}
      end
    EOT
    __rules__ << rule = [self, "BEFORE", method, old_method_name, caller[0], comment]
    rule
  end

  def self.__create_rule_after( method, comment = '', &block)
    args = instance_method(method).arity == 0 ? '' : '(*args)'
    b_id = "%04x" % block.object_id
    old_method_name = :"__previous_#{method}_#{b_id}"
    alias_method old_method_name, method
    define_method :"__after_#{method}_#{b_id}", &block
    class_eval <<-EOT
      def #{method}#{args}
        res = __previous_#{method}_#{b_id}#{args}
        __after_#{method}_#{b_id}#{args}
        res
      end
    EOT
    __rules__ << rule = [self, "AFTER", method, old_method_name,caller[0], comment ]
    rule
  end

  def self.__remove_rule( rule ) # has some bugs when rules on subclasses are defined :(
    idx = __rules__.index(rule)
    if idx
      # look for next rule for the same method
      idx += 1
      while idx < __rules__.size
        break if  __rules__[idx][2] == rule[2] && __rules__[idx][0] == rule[0]
        idx+=1
      end
      if idx < __rules__.size
        next_rule = __rules__[idx]
        next_rule[0].send :remove_method, next_rule[3]
        next_rule[0].send :alias_method, next_rule[3], rule[3]
      else
        # that was last
        rule[0].send :remove_method, rule[2]
        rule[0].send :alias_method, rule[2], rule[3]
      end
      __rules__.delete(rule)
    end
  end

end

# Example
class Model
  def save
    puts "save"
  end
  def reload(flag)
    "reloaded"
  end
end

r1 = Model.__create_rule_instead(:reload) {|flag| flag ? "FRESH" : "STALE" }

obj = Model.new

puts "RELOAD:"+obj.reload(true)
puts "RELOAD:"+obj.reload(false)

Object.__remove_rule(r1)
puts "RELOAD:"+obj.reload(false)

Model.__create_rule_before(:save) { puts "BEFORE SAVE" }
r2 = Model.__create_rule_before(:save) { puts "YET BEFORE SAVE" }
Model.__create_rule_after(:save)  { puts "AFTER SAVE" }
r3 = Model.__create_rule_after(:save)  { puts "YET AFTER SAVE" }
obj.save
Object.__remove_rule(r2)
puts "----------"
obj.save
Object.__remove_rule(r3)
puts "----------"
obj.save

# RESULT
==begin
RELOAD:FRESH
RELOAD:STALE
RELOAD:reloaded
YET BEFORE SAVE
BEFORE SAVE
save
AFTER SAVE
YET AFTER SAVE
----------
BEFORE SAVE
save
AFTER SAVE
YET AFTER SAVE
----------
BEFORE SAVE
save
AFTER SAVE
==end

Tags: ruby redefine

Posted in Ruby & Rails   |   0 Comments   |  723 views

Comments

Post your comment


*
*(not shown)
Click,change verify code.


  • Search

  • Categories

    • Ruby & Rails
    • Jobs
    • Uncategorized
  • Recent Posts

    • Prawn使用Annotation坐...
    • ejabberd mod_archive
    • Capybara get session in ...
    • Juggernaut & Rails
    • RottenEgg发布
    • ruby rmagick 生成DM
    • ActiveResource for no r...
    • Rails生成Model文档
    • 转-Method triggers:inst...
    • 招聘-Ruby on Rails软件...
  • Links

    • RailsCasts
    • Alltop Ruby
    • Command Line Refer
    • Ruby Code Snippets
    • GitHub
    • API Dock
    • OpenSourceRails
    • RailsPlugins
    • RailsLab
    • The Ruby Reflector
  • Archives

    • 2012年(1)

    • 2012年01月(1)
    • 2011年(10)

    • 2011年12月(1)
    • 2011年11月(1)
    • 2011年08月(2)
    • 2011年04月(2)
    • 2011年03月(1)
    • 2011年01月(3)
    • 2010年(27)

    • 2010年12月(1)
    • 2010年11月(2)
    • 2010年10月(4)
    • 2010年09月(7)
    • 2010年08月(1)
    • 2010年07月(5)
    • 2010年06月(1)
    • 2010年04月(6)
    • 2009年(13)

    • 2009年10月(1)
    • 2009年05月(2)
    • 2009年04月(1)
    • 2009年03月(2)
    • 2009年02月(7)
    • 2008年(19)

    • 2008年08月(1)
    • 2008年07月(1)
    • 2008年06月(1)
    • 2008年05月(3)
    • 2008年04月(1)
    • 2008年03月(2)
    • 2008年02月(10)

Copyright © 2010 elvuel.com Powered by Elvuel.