红宝石中的懒惰对象

时间:2015-05-25 10:31:18

标签: ruby lazy-evaluation

如何创建一个完全懒惰的opbjet?我有一个块,我想传递(作为依赖)"当前值" (在调用时),而不是依赖注入时的值。

我实际上无法传递lambda,因为所有服务都需要一个实际的对象,所以他们不会发送:call给他们,只是访问它们。

这个(过于简化的)示例可能会澄清情况:

class Timer
  def initialize(current_time)
    @current_time = current_time
  end

  def print_current_time
    print @current_time
  end
end

class Injector
  def current_time
    # a lazy object that when accessed actually calls the lambda below
    # every single time.
  end

  def current_time_lazy
    -> { Time.now }
  end

  def instantiate(class_name)
    # search for the class, look at the constructor and
    # create an instance with the dependencies injected by
    # name
    # but to be simple
    if class_name == "Timer"
      Timer.new(current_time)
    end
  end
end

timer = Injector.new.instantiate("Timer")
timer.print_current_time # => some time
sleep 2
timer.print_current_time # => some *different* time

实际情况意味着绕过current_user,但根据情况,当前用户可能会在注入这些值后更改。

我真的很感激任何建议(即使现在我会仔细排序依赖注入代码,所以这不会发生,但我认为它非常脆弱)

1 个答案:

答案 0 :(得分:0)

这应该有所帮助:

class Timer
  def initialize(current_time)
    @current_time = current_time
  end
  def print_current_time
    puts @current_time
  end
end

class LazyMaker < BasicObject
  def self.instantiate(class_name, lambada)
    if class_name == 'Timer'
      ::Timer.new(new(class_name, lambada))
    end
  end
  def initialize(class_name, lambada)
    @lambada = lambada
  end
  def method_missing(method, *args)
    @lambada.call.send(method, *args)
  end
end

timer = LazyMaker.instantiate('Timer', -> { Time.now })
timer.print_current_time # some time
sleep 2
timer.print_current_time # some other time

我正在尝试使用委托来实现它,这样我就可以先调用该块,获取一个新对象并将方法调用重定向到它。为什么这样?因为基本上,访问一个对象来做某事意味着在它上面调用一个方法。例如,在print @current_time中,它会发送@current_time.to_s

但由于几乎所有对象都有一些从Ruby中的标准基类继承的方法,如ObjectLazyMaker也有类似to_s的方法。所以我想从LazyMaker继承BasicObject继承,这是一个空白类。所以几乎所有的方法都被委派了。

但是,可能有另一种方法可以做到这一点。