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. But it goes 1 2 3 now. I think this is called lazy evaluation but I'm not sure.
我想要一个类像foo。method1。method2一样向后运行函数。method3和我想让函数运行method3然后method1。但现在是1 2 3。我认为这叫做延迟评估,但我不确定。
I know next to nothing about Ruby so please excuse this question if its simple and I should know this already.
我对Ruby几乎一无所知,所以请原谅这个问题,如果它很简单,我应该已经知道了。
5 个解决方案
#1
5
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
#2
4
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. The only difference is the ability to pass on the arguments to the internal stack.
看起来我成功地找到了皮特的答案,并且给出了几乎完全相同的答案。唯一的区别是能够将参数传递到内部堆栈。
#3
3
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]
#4
0
I don't think that this is possibl. Here is why:
我认为这是不可能的。这里是原因:
-
method3
is operating on the result ofmethod2
- method3正在对method2的结果进行操作
-
method2
is operating on the result ofmethod1
- method2正在对method1的结果进行操作
- therefore
method3
requires thatmethod2
has completed - 因此method3要求method2已经完成
- therefore
method2
requires thatmethod1
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
#5
0
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.
不要忘记闭包确实会扰乱或帮助这个问题。
#1
5
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
#2
4
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. The only difference is the ability to pass on the arguments to the internal stack.
看起来我成功地找到了皮特的答案,并且给出了几乎完全相同的答案。唯一的区别是能够将参数传递到内部堆栈。
#3
3
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]
#4
0
I don't think that this is possibl. Here is why:
我认为这是不可能的。这里是原因:
-
method3
is operating on the result ofmethod2
- method3正在对method2的结果进行操作
-
method2
is operating on the result ofmethod1
- method2正在对method1的结果进行操作
- therefore
method3
requires thatmethod2
has completed - 因此method3要求method2已经完成
- therefore
method2
requires thatmethod1
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
#5
0
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.
不要忘记闭包确实会扰乱或帮助这个问题。