KagemushaでActiveRecordのfindなどのクラスメソッドをswap しようとすると、

   1  singleton method bound for a different object (TypeError)

というエラーが発生するという問題がありました。

このままでは困るので、とりあえず動くようにしてみました。 Unboundにしなければ問題は起こらないと思ったので、 instance_methodの代わりにalias_methodを使っています。

kagemusha_core_ext.rb

   1  require 'uuidtools'
   2  
   3  class Kagemusha #:nodoc:
   4    def swap #:nodoc:
   5      original_class_methods    = {}
   6      original_instance_methods = {}
   7  
   8      @class_methods.each { |name, proc|
   9        if proc
  10          begin
  11            # replace method
  12            #method = @meta.instance_method(name)
  13            method = random_name
  14            @meta.instance_eval { alias_method method, name }
  15            @meta.instance_eval { define_method(name, proc) }
  16            original_class_methods[name] = method
  17          rescue NameError
  18            # insert method
  19            @meta.instance_eval { define_method(name, proc) }
  20            original_class_methods[name] = false
  21          end
  22        else
  23          begin
  24            # remove method
  25            #method = @meta.instance_method(name)
  26            method = random_name
  27            @meta.instance_eval { alias_method method, name }
  28            @meta.instance_eval { undef_method(name) }
  29            original_class_methods[name] = method
  30          rescue NameError
  31            # nop
  32          end
  33        end
  34      }
  35  
  36      @instance_methods.each { |name, proc|
  37        if proc
  38          begin
  39            # replace method
  40            method = @klass.instance_method(name)
  41            @klass.instance_eval { define_method(name, proc) }
  42            original_instance_methods[name] = method
  43          rescue NameError
  44            # insert method
  45            @klass.instance_eval { define_method(name, proc) }
  46            original_instance_methods[name] = false
  47          end
  48        else
  49          begin
  50            # remove method
  51            method = @klass.instance_method(name)
  52            @klass.instance_eval { undef_method(name) }
  53            original_instance_methods[name] = method
  54          rescue NameError
  55            # nop
  56          end
  57        end
  58      }
  59  
  60      return yield
  61    ensure
  62      original_class_methods.each { |name, method|
  63        if method
  64          # replace method
  65          #@meta.instance_eval { define_method(name, method) }
  66          @meta.instance_eval { alias_method name, method }
  67          @meta.instance_eval { undef_method method }
  68        else
  69          # remove method
  70          @meta.instance_eval { undef_method(name) }
  71        end
  72      }
  73      original_instance_methods.each { |name, method|
  74        if method
  75          # replace method
  76          @klass.instance_eval { define_method(name, method) }
  77        else
  78          # remove method
  79          @klass.instance_eval { undef_method(name) }
  80        end
  81      }
  82    end
  83  
  84  private
  85    def random_name
  86      [UUID.random_128].pack("m").tr("=\n", '')
  87    end
  88  end

posted by Png genki on Sun 6 Jul 2008 at 05:22 with 2 comments

Comments:

Face Yuya almost 16 years ago.

こんにちは。Kagemushaの作者のYuyaです。

不具合のご検討、ありがとうございます。 違う方法ではありますが、修正を入れてみました。 もしよろしければ、trunk版をお試し頂けると幸いです。

http://kagemusha.rubyforge.org/svn/trunk/kagemusha/lib/kagemusha/core.rb

Png 瀧内元気 almost 16 years ago.

おお、どうもありがとうございます。便利に使わせていただいています。 Specのカバレッジを上げるのに重宝しています。

or Preview
Social Bookmarks
  • Delicious
  • B_entry656
  • Clip_16_12_w
Services from s21g
twpro(ツイプロ)
Twitterプロフィールを快適検索
地価2009
土地の値段を調べてみよう
MyRestaurant
自分だけのレストラン手帳
Formula
ブログに数式を埋め込める数式コミュニティ