我创建了一个DSL来用ruby定义工厂。有更好的方法吗?
我有ruby应用程序,我想实现一个DSL来定义工厂。工厂是根据结果(成功或失败)实例化某些对象、执行流程中的某些逻辑、执行某些验证和执行某些回调的类: 好的,这并不是很难做到,但我还想在方法失败或成功后立即停止create方法,比如:我创建了一个DSL来用ruby定义工厂。有更好的方法吗?,ruby,metaprogramming,Ruby,Metaprogramming,我有ruby应用程序,我想实现一个DSL来定义工厂。工厂是根据结果(成功或失败)实例化某些对象、执行流程中的某些逻辑、执行某些验证和执行某些回调的类: 好的,这并不是很难做到,但我还想在方法失败或成功后立即停止create方法,比如: def create(options = {}) # some logic failed! # this method stops execution and yields the callback object puts "you'll never
def create(options = {})
# some logic
failed! # this method stops execution and yields the callback object
puts "you'll never see this"
end
我想到的是:
请参阅下面的部分版本:
require 'fiber'
class Factory
class Callbacks
# omitted some code here, this class is basically a container for
# success and failure callbacks
end
def failed!
@callbacks.failed!
resume_context
end
def succeeded!
@callbacks.succeeded!
resume_context
end
def resume_context ; Fiber.yield ; end
def self.handle(name, &method_body)
define_method "__original_#{name}__", &method_body
define_method name do |*args, &block|
@callbacks = Callbacks.new(self, block)
Fiber.new { send("__original_#{name}__", *args) }.resume
@callbacks
end
end
handle :create do |options = {}|
puts options.inspect
puts "in create"
succeeded!
puts 'after succeeded, never reached here'
end
end
正如您所看到的,类方法handle
定义了两个方法:\uuuuuuu original\u create\uuuuuuuu
和create
,它将\uuuuuuuuuuu original\u create\uuuuuuuuuu>封装在光纤
中,以便立即停止执行并执行回调。我的问题是:有没有更好的方法?不创建\uuuu原始\u创建\uuuuu
方法,甚至不使用光纤
我已经试过了:
def self.handle(name, &method_body)
define_method name do |*args, &block|
@callbacks = Callbacks.new(self, block)
Fiber.new { method_body.call *args }.resume
# above method_body is evaluated in the context of the class.
@callbacks
end
end
但是方法\u body
是在类的上下文中计算的,而不是在实例中:
我还试着像这样对方法\u body
进行实例评估:
def self.handle(name, &method_body)
define_method name do |*args, &block|
@callbacks = Callbacks.new(self, block)
Fiber.new { instance_eval &method_body }.resume
# above we lost the parameters defined by the handle method
@callbacks
end
end
但我丢失了对以下定义参数的引用:
handle :create do |param1, param2|
# method body
end
我找到的唯一方法是使用传递给handle
方法的块定义一个方法,然后定义一个调用原始方法的包装器方法,就像我在上面使用\uuuuuuu original\uuuu create\uuuuu
所做的那样。我不同意定义一个额外的方法,必须有另一种方法来做到这一点:(
任何见解都将不胜感激。一种方法是使用throw
和catch
def create(options = {})
case catch(:result) do
throw :result, :success if ...
throw :result, :error if ...
end
when :success then ...
when :error then ...
end
end
我不确定您需要光纤做什么,所以我会留下它,但您需要的是
不会method\u body.call(*args)
work?@Urigass谢谢你的评论,但是没有,方法\u body是在类而不是实例的上下文中进行评估的。我更新了我的问题,并发布了一个带有完整代码版本的要点链接。你为什么要使用纤维呢?试试instance\u exec*args,&method\u exec
就是这样做的instance\u exec*args,&method\u body
正是我摆脱这个额外方法所需要的。我使用光纤来控制流量。我希望这个方法停止,产生回调并只返回一个方法调用,比如:失败!
。我不想做产生@callbacks并返回
。非常感谢。@Urigassi我对你的解决方案很满意,我不知道aboutinstance\u exec
。我对光纤没有问题,但如果您有更好的方法来完成同样的事情,我将非常感谢您的建议。您能写一个答案让我接受吗?再次感谢您。谢谢@sawa的回答,我不确定我是否遵循了您的建议。我想遵循原则“告诉我,别问"在create方法中。这就是为什么我希望失败!
和成功
方法立即停止执行并生成回调对象。非常感谢,这正是我所需要的。如果有人感兴趣,我使用Fiber
停止执行,立即生成回调并忽略失败下面的所有内容ed!
方法。不确定是否有一种方法可以在不使用光纤的情况下仅通过一次方法调用来完成此操作。如果不使用光纤,我必须执行此操作:失败!并返回。不过,我认为光纤
应该是另一个问题。。。
def create(options = {})
case catch(:result) do
throw :result, :success if ...
throw :result, :error if ...
end
when :success then ...
when :error then ...
end
end
def self.handle(name, &method_body)
define_method name do |*args, &block|
@callbacks = Callbacks.new(self, block)
Fiber.new { instance_exec *args, &method_body }.resume
# above we lost the parameters defined by the handle method
@callbacks
end
end