如何在方法调度之后和调用方法之前运行方法?

时间:2011-06-28 03:12:30

标签: ruby

当我有以下内容时:

class Foo
  def bar
    puts "#{__method__} was called and found within #{self}"
  end

  def method_missing(meth, *args, &blk)
    puts "#{meth} was called and was not found within #{self}"
  end
end

foo = Foo.new
foo.bar 
# => bar was called and found within #<Foo:0x100138a98>
foo.baz 
# => baz was called and was not found within #<Foo:0x100138a98>

我假设在找到方法时,方法调度看起来有点像:

foo.bar was asked to be called
Search methods defined within #<Foo:0x100138a98>
Method `bar` found
Call the `bar` method

对于未找到的方法:

foo.baz was asked to be called
Search methods defined within #<Foo:0x100138a98>
Method `baz` not found 
Search methods defined within the parent of #<Foo:0x100138a98>
Method `baz` not found
And so on until it hits the parent that has no parent
Loop back around and see if #<Foo:0x100138a98> has a `method_missing` method defined
Method `method_missing` found
Call the `method_missing` method

我想这样介入:

foo.bar was asked to be called
Search methods defined within #<Foo:0x100138a98> to see it has a `method_dispatched` method
Method `method_dispatched` found
Calling `method_dispatched`
Search methods defined within #<Foo:0x100138a98>
...

这将允许开发人员执行以下操作:

class Foo
  def bar
    puts "#{__method__} was called and found within #{self}"
  end

  def method_missing(meth, *args, &blk)
    puts "#{meth} was called and was not found within #{self}"
  end

  def method_dispatched(meth, *args, &blk)
    puts "#{meth} was called within #{self}..."
    puts "continuing with the method dispatch..."
  end
end

foo = Foo.new
foo.bar 
# => bar was called within #<Foo:0x100138a98>...
# => continuing with the method dispatch...
# => bar was called and found within #<Foo:0x100138a98>
foo.baz 
# => bar was called within #<Foo:0x100138a98>...
# => continuing with the method dispatch...
# => baz was called and was not found within #<Foo:0x100138a98>

这让我想到了这个问题..

这可能吗?

2 个答案:

答案 0 :(得分:0)

我不知道你正在寻找的回调。我会在Ruby Delegators上阅读一个可能的解决方案,它比我在下面描述的更优雅。

您可以在method_missing上包装对象和拦截。

class A
  def foo
    puts "hi there, I'm A"
  end 
end 

maybe have B inherit A? 
class B 
  def initialize 
    @a = A.new
  end 

  def method_missing(m, *args, &block)
    puts "hi there, I'm in B"
    @a.send(m, *args, &block) if @a.respond_to? m
    puts "all done"
  end 
end 

答案 1 :(得分:0)

这里有一个Ruby初学者的排序,但我有一些有效的解决方案。所以如果你认为某些东西不是红宝石,请对代码进行评论。

这个想法是为你拥有的方法和undef_method原始方法的别名。这将为您的所有实例方法创建一个别名。然后,您可以使用method_missing调用method_dispatched,然后调用实际方法。

class Test
        def foo
                "foo"
        end

        def method_dispatched(meth, *args, &blk)
                puts "#{meth} was called within #{self}..."
                puts "continuing with the method dispatch..."
        end

        def method_missing(name, *args, &block)
                method_dispatched(name, args, block)  #Calls your standard dispatcher

                if (respond_to?('_' + name.to_s)) # Check if we have a aliased method
                        send('_' + name.to_s)
                else
                        "undef"    #Let the caller know that we cant handle this.
                end
        end

        instance_methods(false).each do |meth|
                if meth != 'method_missing' and meth != 'method_dispatched'
                        alias_method "_#{meth}", meth
                        remove_method(meth)
                end
        end

end

t = Test.new
puts t.foo()
puts t.undefined_method()