是否可以临时更改链式方法调用的实例变量?

时间:2015-02-02 16:27:01

标签: ruby

我有一个懒惰地将数据从数据库加载到实例变量中的类,它们是数组中数组的事件。该类有几种方法可以分析这个数组,下面是我如何使用它的一个例子。

class Foo
  def initialize
    @a = [1,2,3,4,5] # data from database
  end

  def analyse
    @a.reduce(:+)
  end
end

d = Foo.new
result = d.analyse

我希望能够在一个非常基本的过滤器(例如:<= 3)之后将这些方法应用于数据,我想像能够这样调用它:

d.at(3).analyse

并且at方法仅影响链接analyse调用的实例变量。即。

d = Foo.new # data loaded into instance var [1,2,3,4,5]
d.analyse # 15
d.at(3).analyse # 6
d.analyse # 15

我不知道如果不在at at中重新创建一个全新的对象,我怎么能做到这一点,这感觉效率低下。我有一个工作可以改变我调用at方法的方式 - 而不是世界末日,但我想知道我想要什么是可行的,同时保持高效。

2 个答案:

答案 0 :(得分:0)

您可以准备另一个由at设置的实例变量,在定义时覆盖@a,并由analyse重置。

class Foo
  def initialize
    @a = [1,2,3,4,5]
  end
  def at i
    @b = @a.select{|e| e <= i}
    self
  end
  def array
    if instance_variable_defined?(:@b)
      @b.tap{remove_instance_variable(:@b)}
    else
      @a
    end
  end
  def analyse
    array.reduce(:+)
  end
end

答案 1 :(得分:0)

  

我不确定如何在没有在通话中重新创建一个全新的对象的情况下如何做到这一点,这感觉效率低下。

我不认为创建一个新对象太贵了。您可以从Foo返回新的at,并使用原始数据的子集进行初始化。您有另一个Foo实例和另一个Array实例,但该数组将包含完全相同的对象:

class Foo
  def initialize(a = nil)
    @a = a || [1,2,3,4,5] # use a or fetch data from database
  end

  def analyse
    @a.reduce(:+)
  end

  def at(max)
    Foo.new(@a.take_while { |x| x <= max })
  end
end

示例:

d = Foo.new
d.analyse #=> 15
d.at(3).analyse #=> 6
d.analyse #=> 15