Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/dart/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
我创建了一个DSL来用ruby定义工厂。有更好的方法吗?_Ruby_Metaprogramming - Fatal编程技术网

我创建了一个DSL来用ruby定义工厂。有更好的方法吗?

我创建了一个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

我有ruby应用程序,我想实现一个DSL来定义工厂。工厂是根据结果(成功或失败)实例化某些对象、执行流程中的某些逻辑、执行某些验证和执行某些回调的类:

好的,这并不是很难做到,但我还想在方法失败或成功后立即停止create方法,比如:

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我对你的解决方案很满意,我不知道about
instance\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