From: Brian Mitchell Date: 2007-09-07T22:18:34+09:00 Subject: Re: before, after and around Ruby 1.9 ------=_Part_119_30028435.1189171096607 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 7bit Content-Disposition: inline On 9/5/07, Yukihiro Matsumoto wrote: > Hi, > > In message "Re: before, after and around Ruby 1.9" > on Thu, 6 Sep 2007 03:07:14 +0900, Trans writes: > > |Any chance Ruby 1.9 will have before, after and around method > |composition support? > > No. Wait for 2.0 for built-in method combination. The vague plan is > making open-class to stack methods on the current ones, unless > explicitly removed, i.e. > > class Foo < Object > def foo > puts "Foo#foo (1)" > end > end > class Foo # re-open > def foo > super # calls the first foo > puts "Foo#foo (2)" > end > end > > will print > > Foo#foo (1) > Foo#foo (2) > > No alias required. > > This works as "around". And "before" and "after" can be rewritten > using "around". Note that this is not a fixed idea at all. > > matz. I started implementing a simple emulator for this super behavior. It seems to work fine for your example: module StackedMethods def self.included(mod) mod.instance_eval do @stack = MethodStack.new @stack.methods = Hash.new {|h,k| h[k] = []} @stack.callers = Hash.new {|h,k| h[k] = Hash.new(-1)} @trampoline = Module.new include @trampoline end mod.extend Hooks end MethodStack = Struct.new(:methods, :callers) module Hooks def method_added(name) stack = @stack # Using this in define_method's closure. stack.methods[name] << instance_method(name) unless @trampoline.instance_methods.include? name @trampoline.class_eval do define_method name do |*a, &b| idx = stack.callers[Thread.current][name] -= 1 begin next_call = stack.methods[name][idx] if next_call next_call.bind(self).call(*a, &b) else super(*a, &b) end ensure stack.callers[Thread.current][name] += 1 end end end end end def method_removed(name) @stack.methods[name] = [] @trampoline.class_eval {remove_method name} end end end Just include the StackedMethods module before the method definitions to use it. The odd thing is I get a crash on my fib example: class Example include StackedMethods def fib(n) if n > 1 fib(n - 2) + fib(n - 1) else 1 end end def fib(n, prefix = 'Calculating fib of ') puts prefix + n.to_s super(n) end end Output: $ ruby19 stacked_methods.rb Calculating fib of 2 Calculating fib of 0 stacked_methods.rb:33: -- control frame ---------- c:7085 p:0023 s:31872 b:31870 l:00139c d:001869 BLOCK stacked_methods.rb:33 c:7084 p:0141 s:31868 b:31867 l:00139c d:001866 LAMBDA stacked_methods.rb:33 c:7083 p:---- s:31864 b:31862 l:001861 d:001861 FINISH :methods c:7082 p:0102 s:31860 b:31858 l:00139c d:001857 LAMBDA stacked_methods.rb:30 c:7081 p:---- s:31855 b:31853 l:001852 d:001852 FINISH :methods c:7080 p:0102 s:31851 b:31849 l:00139c d:001848 LAMBDA stacked_methods.rb:30 c:7079 p:---- s:31846 b:31844 l:001843 d:001843 FINISH :methods c:7078 p:0102 s:31842 b:31840 l:00139c d:001839 LAMBDA stacked_methods.rb:30 ... snip ... c:0014 p:0102 s:0052 b:0050 l:00118c d:000049 LAMBDA stacked_methods.rb:30 c:0013 p:---- s:0047 b:0045 l:000044 d:000044 FINISH :methods c:0012 p:0102 s:0043 b:0041 l:00118c d:000040 LAMBDA stacked_methods.rb:30 c:0011 p:---- s:0038 b:0036 l:000035 d:000035 FINISH :[]= c:0010 p:0008 s:0034 b:0032 l:000031 d:000031 METHOD stacked_methods.rb:59 c:0009 p:0019 s:0028 b:0028 l:000027 d:000027 METHOD stacked_methods.rb:52 c:0008 p:---- s:0024 b:0024 l:000023 d:000023 FINISH :yield c:0007 p:---- s:0022 b:0022 l:000021 d:000021 CFUNC :call c:0006 p:0088 s:0018 b:0018 l:00118c d:000017 LAMBDA stacked_methods.rb:28 c:0005 p:---- s:0015 b:0013 l:000012 d:000012 FINISH :initialize c:0004 p:0008 s:0011 b:0009 l:000008 d:000008 METHOD stacked_methods.rb:59 c:0003 p:0035 s:0005 b:0005 l:000004 d:000004 TOP stacked_methods.rb:63 c:0002 p:---- s:0003 b:0003 l:000002 d:000002 FINISH :inherited c:0001 p:---- s:0001 b:-001 l:000000 d:000000 ------ --------------------------- DBG> : "stacked_methods.rb:30:in `block (2 levels) in method_added'" DBG> : "stacked_methods.rb:30:in `block (2 levels) in method_added'" ... snip ... DBG> : "stacked_methods.rb:30:in `block (2 levels) in method_added'" DBG> : "stacked_methods.rb:30:in `block (2 levels) in method_added'" DBG> : "stacked_methods.rb:59:in `fib'" DBG> : "stacked_methods.rb:52:in `fib'" DBG> : "stacked_methods.rb:28:in `call'" DBG> : "stacked_methods.rb:28:in `block (2 levels) in method_added'" DBG> : "stacked_methods.rb:59:in `fib'" DBG> : "stacked_methods.rb:63:in `
'" -- backtrace of native function call (Use addr2line) -- ------------------------------------------------------- [BUG] Segmentation fault ruby 1.9.0 (2007-09-07) [i686-darwin9.0.0b5] Abort trap It seems it hits a nasty bug somewhere in the VM on this machine. It seems to have an issue with recursive calling on the line with super(*a, &b). It is possibly related to my use of recursion in fib here. I've attached my original source file. Brian. ------=_Part_119_30028435.1189171096607 Content-Type: text/x-ruby-script; name="stacked_methods.rb" Content-Transfer-Encoding: base64 Content-Disposition: attachment; filename="stacked_methods.rb" X-Attachment-Id: f_f6appnjz IyBBIHNpbXBsZSBpbXBsZW1lbnRhdGlvbiBvZiBtZXRob2Qgc3RhY2tpbmcgaW4gcHVyZSBSdWJ5 Cgptb2R1bGUgU3RhY2tlZE1ldGhvZHMKICBkZWYgc2VsZi5pbmNsdWRlZChtb2QpCiAgICBtb2Qu aW5zdGFuY2VfZXZhbCBkbwogICAgICBAc3RhY2sgPSBNZXRob2RTdGFjay5uZXcKICAgICAgQHN0 YWNrLm1ldGhvZHMgPSBIYXNoLm5ldyB7fGgsa3wgaFtrXSA9IFtdfQogICAgICBAc3RhY2suY2Fs bGVycyA9IEhhc2gubmV3IHt8aCxrfCBoW2tdID0gSGFzaC5uZXcoLTEpfQogICAgICBAdHJhbXBv bGluZSA9IE1vZHVsZS5uZXcKICAgICAgaW5jbHVkZSBAdHJhbXBvbGluZQogICAgZW5kCiAgICBt b2QuZXh0ZW5kIEhvb2tzCiAgZW5kCiAgCiAgTWV0aG9kU3RhY2sgPSBTdHJ1Y3QubmV3KDptZXRo b2RzLCA6Y2FsbGVycykKICAKICBtb2R1bGUgSG9va3MKICAgIGRlZiBtZXRob2RfYWRkZWQobmFt ZSkKICAgICAgc3RhY2sgPSBAc3RhY2sgIyBVc2luZyB0aGlzIGluIGRlZmluZV9tZXRob2QncyBj bG9zdXJlLgogICAgICBzdGFjay5tZXRob2RzW25hbWVdIDw8IGluc3RhbmNlX21ldGhvZChuYW1l KQogICAgICB1bmxlc3MgQHRyYW1wb2xpbmUuaW5zdGFuY2VfbWV0aG9kcy5pbmNsdWRlPyBuYW1l CiAgICAgICAgQHRyYW1wb2xpbmUuY2xhc3NfZXZhbCBkbwogICAgICAgICAgZGVmaW5lX21ldGhv ZCBuYW1lIGRvIHwqYSwgJmJ8CiAgICAgICAgICAgIGlkeCA9IHN0YWNrLmNhbGxlcnNbVGhyZWFk LmN1cnJlbnRdW25hbWVdIC09IDEKICAgICAgICAgICAgYmVnaW4KICAgICAgICAgICAgICBuZXh0 X2NhbGwgPSBzdGFjay5tZXRob2RzW25hbWVdW2lkeF0KICAgICAgICAgICAgICBpZiBuZXh0X2Nh bGwKICAgICAgICAgICAgICAgIG5leHRfY2FsbC5iaW5kKHNlbGYpLmNhbGwoKmEsICZiKQogICAg ICAgICAgICAgIGVsc2UKICAgICAgICAgICAgICAgIHN1cGVyKCphLCAmYikKICAgICAgICAgICAg ICBlbmQKICAgICAgICAgICAgZW5zdXJlCiAgICAgICAgICAgICAgc3RhY2suY2FsbGVyc1tUaHJl YWQuY3VycmVudF1bbmFtZV0gKz0gMQogICAgICAgICAgICBlbmQKICAgICAgICAgIGVuZAogICAg ICAgIGVuZAogICAgICBlbmQKICAgIGVuZAogICAgCiAgICBkZWYgbWV0aG9kX3JlbW92ZWQobmFt ZSkKICAgICAgQHN0YWNrLm1ldGhvZHNbbmFtZV0gPSBbXQogICAgICBAdHJhbXBvbGluZS5jbGFz c19ldmFsIHtyZW1vdmVfbWV0aG9kIG5hbWV9CiAgICBlbmQKICBlbmQKZW5kCgpjbGFzcyBFeGFt cGxlCiAgaW5jbHVkZSBTdGFja2VkTWV0aG9kcwogIAogIGRlZiBmaWIobikKICAgIGlmIG4gPiAx CiAgICAgIGZpYihuIC0gMikgKyBmaWIobiAtIDEpCiAgICBlbHNlCiAgICAgIDEKICAgIGVuZAog IGVuZAoKICBkZWYgZmliKG4sIHByZWZpeCA9ICdDYWxjdWxhdGluZyBmaWIgb2YgJykKICAgIHB1 dHMgcHJlZml4ICsgbi50b19zCiAgICBzdXBlcihuKQogIGVuZAplbmQKCkV4YW1wbGUubmV3LmZp YigyKQo= ------=_Part_119_30028435.1189171096607--