やりたいこと
配列をネストしたブロックに変換したい。
たとえば、ブロックを受け取る transaction という共通の名前のクラスメソッドを持ったクラス CuteDB, CoolDB, EpicDB があるとして
nested_transactions([CuteDB, CoolDB, EpicDB]) do
hoge
end
を
CuteDB.transaction do
CoolDB.transaction do
EpicDB.transaction do
hoge
end
end
end
という構造に変換したい。ネストする順番を動的に決定するのが目的。
方法
Proc オブジェクトと Enumerable#inject を利用する。
(@kts_h さんのコメントのおかげで nested_transactions メソッドの実装がシンプルになりました )
module CuteDB
def self.transaction
puts('CuteDB start')
yield
puts('CuteDB end')
end
end
module CoolDB
def self.transaction
puts('CoolDB start')
yield
puts('CoolDB end')
end
end
module EpicDB
def self.transaction
puts('EpicDB start')
yield
puts('EpicDB end')
end
end
def nested_transactions(dbs, &block)
# 配列の最初の要素を一番外側、最後の要素の一番内側にしたいので
# reverse (reverse_each) する。
dbs.reverse_each.inject(block) do |nested_blocks, db|
proc { db.transaction(&nested_blocks) }
end.call
end
nested_transactions([CuteDB, CoolDB, EpicDB]) do
puts('I am working on my precious DBs.')
end
# CuteDB start
# CoolDB start
# EpicDB start
# I am working on my precious DBs.
# EpicDB end
# CoolDB end
# CuteDB end
nested_transactions([EpicDB, CuteDB]) do
puts('I am working on my precious DBs.')
end
# EpicDB start
# CuteDB start
# I am working on my precious DBs.
# CuteDB end
# EpicDB end