我正在尝试确定是否有可能在 Ruby 中确定方法链何时完成调用。
假设我有一个从数据库中检索信息的类。我经常只想调用该类的一个实例来访问 all 包含的数据,但在许多情况下,我链接了应用过滤器等的附加方法。目前,实际的数据检索是由一个总是最后调用的方法执行的,比如所以:
all_data = data_retriever.run
filtered_data = data_retriever.condition({k1: v1}).run
filtered_data = data_retriever.condition({k1: v1}).condition({k2: v2}).run
这很好用,但我忍不住认为 Ruby 可能有办法做到这一点,而无需在每次使用结束时添加像
.run
这样的方法。当我完成链接方法时,我的班级是否有可能“知道”?比如在调用所有链式方法后执行的钩子?
class DataRetriever
@conditions = {}
def initialize()
end
def condition(condition_hash)
@conditions << condition_hash
end
#...
def after_chains
# run the data retrieval code using the contents of @conditions
end
end
不,链接方法等同于一个接一个地调用它们。呼叫者无法区分呼叫方式。这实际上很好,请考虑以下几点:
retriever = data_retriever.condition({k1: v1})
retriever.condition({k2: v2}) if something
retriever.condition({k3: v3}) if something_else
data = retriever.run
在上面的示例中,您可能不希望第一行已经触发数据检索。
但是,您可以使用更微妙的入口点来触发执行,而不是
run
,例如each
是 Ruby 默认的枚举方法:
data = data_retriever.condition({k1: v1})
data.each do |entry|
# ...
end
引擎盖下:
class DataRetriever
def run
@data = # retrieve actual data
end
def each(&block)
run unless @data
@data.each(&block)
end
end
只需确保在添加更多条件时使
@data
无效(或者freeze
run
之后的对象)。
你甚至可以从
each
调用inspect
:(你可能想缩写长数据)
class DataRetriever
def inspect
"#<DataRetriever data=#{each.to_a.inspect}>"
end
end
在 irb:
filtered_data = DataRetriever.new.condition({k1: v1})
#=> #<DataRetriever data=[1, 2, 3]>