简体   繁体   English

如何向后运行Ruby函数?

[英]How can I run a Ruby functions backwards?

I want to have a class that runs functions backwards like foo.method1.method2.method3 and I want the funcitons to run method3 method2 then method1. 我想要一个像foo.method1.method2.method3那样向后运行函数的类,我希望函数运行method3 method2然后是method1。 But it goes 1 2 3 now. 但现在它已经进入了1 2 3。 I think this is called lazy evaluation but I'm not sure. 我认为这被称为懒惰评估,但我不确定。

I know next to nothing about Ruby so please excuse this question if its simple and I should know this already. 我对Ruby几乎一无所知所以请原谅这个问题,如果它很简单,我已经知道了。

Sure you can do it. 当然你可以做到。 It sounds like you were on the right path thinking of the lazy evaluation you just need to end every list of method calls with a method that runs the queued methods. 这听起来像是在正确的路径上思考您只需要使用运行排队方法的方法结束每个方法调用列表的惰性求值。

class Foo

  def initialize
    @command_queue = []
  end

  def method1
    @command_queue << :_method1
    self
  end

  def method2
    @command_queue << :_method2
    self
  end

  def method3
    @command_queue << :_method3
    self
  end

  def exec
    @command_queue.reverse.map do |command|
      self.send(command)
    end
    @command_queue = []
  end

  private

  def _method1
    puts "method1"
  end

  def _method2
    puts "method2"
  end

  def _method3
    puts "method3"
  end

end

foo = Foo.new
foo.method1.method2.method3.exec


method3
method2
method1

Maybe you could chain method calls, build an evaluation stack and execute later. 也许你可以链接方法调用,构建一个评估堆栈并在以后执行。 This requires that you call an extra method to evaluate the stack. 这要求您调用额外的方法来评估堆栈。 You could use private methods for the actual implementations. 您可以使用私有方法进行实际实现。

class Weirdo
  def initialize
    @stack = []
  end

  def method_a
    @stack << [:method_a!]
    self #so that the next call gets chained
  end

  def method_b(arg1, arg2)
    @stack << [:method_b!, arg1, arg2]
    self
  end

  def method_c(&block)
    @stack << [:method_c!, block]
    self
  end

  def call_stack
    while @stack.length > 0 do
      send *@stack.pop
    end
  end

  private

  # actual method implementations
  def method_a!
    # method_a functionality
  end

  def method_b!(arg1, arg2)
    # method_b functionality
  end

  def method_c!(&block)
    # method_c functionality
  end
end

so that you can do something like 所以你可以做点什么

w = Weirdo.new
w.method_a.method_b(3,5).method_c{ Time.now }
w.call_stack # => executes c first, b next and a last.

Update 更新

Looks like I managed to miss Pete's answer and posted almost exactly the same answer. 看起来我设法错过了Pete的答案并发布了几乎完全相同的答案。 The only difference is the ability to pass on the arguments to the internal stack. 唯一的区别是能够将参数传递给内部堆栈。

What you really want here is a proxy class that captures the messages, reverses them, and then forwards them on to the actual class: 你真正想要的是一个代理类,它捕获消息,反转它们,然后将它们转发到实际的类:

# This is the proxy class that captures the messages, reverses them, and then forwards them
class Messenger
  def initialize(target)
    @obj = target
    @messages = []
  end

  def method_missing(name, *args, &block)
    @messages << [name, args, block]
    self
  end

  # The return value of this method is an array of the return values of the invoked methods
  def exec
    @messages.reverse.map { |name, args, block| @obj.send(name, *args, &block) }
  end
end

# this is the actual class that implements the methods you want to invoke
# every method on this class just returns its name
class Test
  def self.def_methods(*names)
    names.each { |v| define_method(v) { v } }
  end

  def_methods :a, :b, :c, :d
end

# attach the proxy, store the messages, forward the reversed messages onto the actual class
# and then display the resulting array of method return values
Messenger.new(Test.new).a.b.c.exec.inspect.display  #=> [:c, :b, :a]

I don't think that this is possibl. 我不认为这是可能的。 Here is why: 原因如下:

  • method3 is operating on the result of method2 method3正在对method2的结果进行操作
  • method2 is operating on the result of method1 method2正在对method1的结果进行操作
  • therefore method3 requires that method2 has completed 因此method3要求method2已经完成
  • therefore method2 requires that method1 has completed 因此method2要求method1已完成
  • thus, the execution order must be method3 -> method2 -> method1 因此,执行顺序必须是method3 - > method2 - > method1

I think your only option is to write it as: 我认为你唯一的选择就是把它写成:

foo.method3.method2.method1

As a side note, lazy evaluation is simply delaying a computation until the result is required. 作为旁注,延迟评估只是延迟计算直到需要结果。 For example, if I had a database query that went: 例如,如果我有一个数据库查询:

@results = Result.all

Lazy evaluation would not perform the query until I did something like: 懒惰的评估不会执行查询,直到我做了类似的事情:

puts @results

This is most interesting and useful; 这是最有趣和最有用的; I think that the proxy pattern can indeed be used. 我认为确实可以使用代理模式。 I thought as I read your initial post about a debugger that IBM first provided that allowed executing forward and backward (I think that it was on eclipse for java). 当我读到关于IBM首先提供的允许执行前向和后向的调试器的初始帖子时,我想:我认为它是针对java的eclipse。

I see that OCAML has such a debugger: http://caml.inria.fr/pub/docs/manual-ocaml/manual030.html . 我看到OCAML有这样一个调试器: http ://caml.inria.fr/pub/docs/manual-ocaml/manual030.html。

Don't forget that closures can indeed mess or help this issue. 不要忘记关闭确实会弄乱或帮助解决这个问题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM