独自のLoggerクラスを実装する時をはじめ、インスタンスの生成とインスタンスメソッドの実行をまとめて行いたいケースがあります。具体的には以下のようなコードです。
class MyLogger
def self.logger
# ログを標準出力する
@logger = ActiveSupport::Logger.new(STDOUT)
# ログのフォーマッタをセットする
@logger.formatter = Logger::Formatter.new
# タイムスタンプのフォーマットを設定する
@logger.formatter.datetime_format = '%Y-%m-%d %H:%M:%S'
# 設定が完了したインスタンスを返す
@logger
end
end
上記のコードはProcオブジェクト、begin式、tap
を利用することで簡潔に書き換えられます。
今回はそれぞれの方法を利用して上記のコードを書き換える例について紹介します。
Procオブジェクトを利用する場合
Procクラスはブロックをオブジェクト化するクラスです。
つまりProcオブジェクトとは、Procクラスを利用してオブジェクト化されたブロックのインスタンスのことを指します。
Procオブジェクトを利用すると以下のように書き換えられます。
class MyLogger
def self.logger
@logger ||= proc {
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = Logger::Formatter.new
logger.formatter.datetime_format = '%Y-%m-%d %H:%M:%S'
logger
}.call
end
end
proc {...}
で作成されたProcオブジェクトを.call
で実行することで@logger
にLoggerインスタンスをセットしています。
begin式を利用する場合
Rubyにおけるbegin式の一般的な利用方法はrescue節を組み合わせた例外処理です。
しかし、begin式には『式全体の評価値は本体/rescue節/else節のうち最後に評価された文の値』という特徴があります。 1
begin式では引数を利用できません。今回の例のように引数を利用しない場合であればbegin式で以下のように書き換えられます。
class MyLogger
def self.logger
@logger ||= begin
logger = ActiveSupport::Logger.new(STDOUT)
logger.formatter = Logger::Formatter.new
logger.formatter.datetime_format = '%Y-%m-%d %H:%M:%S'
logger
end
end
end
begin式はProcオブジェクトを利用する場合よりも処理速度が早いです。2
tapを利用する場合
tap
は『selfを引数としてブロックを評価する』『返す値はブロックの評価値ではなくself』という特徴をもつメソッドです。3
tap
を利用すると以下のように書き換えられます。
class MyLogger
def self.logger
@logger ||= ActiveSupport::Logger.new(STDOUT).tap do |logger|
logger.formatter = Logger::Formatter.new
logger.formatter.datetime_format = '%Y-%m-%d %H:%M:%S'
end
end
end
tap
はbegin式と違いスコープを作成します。ですので、一時的に利用する変数logger
はtap
のブロック内でのみ利用可能です。
スコープによって変数が周りに影響を与えなくなるため、tap
のほうがbegin式よりも安全といえます。
さいごに
Twitter(@nishina555)やってます。フォローしてもらえるとうれしいです!