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
4 def swap
5 original_class_methods = {}
6 original_instance_methods = {}
7
8 @class_methods.each { |name, proc|
9 if proc
10 begin
11
12
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
19 @meta.instance_eval { define_method(name, proc) }
20 original_class_methods[name] = false
21 end
22 else
23 begin
24
25
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
32 end
33 end
34 }
35
36 @instance_methods.each { |name, proc|
37 if proc
38 begin
39
40 method = @klass.instance_method(name)
41 @klass.instance_eval { define_method(name, proc) }
42 original_instance_methods[name] = method
43 rescue NameError
44
45 @klass.instance_eval { define_method(name, proc) }
46 original_instance_methods[name] = false
47 end
48 else
49 begin
50
51 method = @klass.instance_method(name)
52 @klass.instance_eval { undef_method(name) }
53 original_instance_methods[name] = method
54 rescue NameError
55
56 end
57 end
58 }
59
60 return yield
61 ensure
62 original_class_methods.each { |name, method|
63 if method
64
65
66 @meta.instance_eval { alias_method name, method }
67 @meta.instance_eval { undef_method method }
68 else
69
70 @meta.instance_eval { undef_method(name) }
71 end
72 }
73 original_instance_methods.each { |name, method|
74 if method
75
76 @klass.instance_eval { define_method(name, method) }
77 else
78
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