[Ruby]クロージャーを使ってブロックを1回だけ実行する

こんにちは、hachi8833です。BPS Advent Calendarの合間を縫うように通常記事もお送りいたします。

高林哲さんの昔のブログ「Ruby: 一回だけ実行されるブロック」を読んでて、「Procかlambdaでクロージャを作れば、もう少し簡潔にできるのでは?」と思ったのでやってみました。

run_onceメソッド

ここではlambdaを使ってみました。

やってみると教科書のコードサンプルみたいな簡潔さです。アラートを最初の1回だけ表示するヘルパーメソッドなんかに使えそうです。

うれしい反面ちょっとさみしいので、YARD記法も足してみました。

コード

# Runs a block only once
# @param the block to run
# @return the object that is returned from the block first; nil after that
def run_once(&block)
  count = 1
  lambda do
    return if count == nil
    count = nil
    yield
  end
end
  • 当初、lambdaを略記法「->」で書いてましたが、後続のブロックが複数行なら略記ではなくlambdaと書くのがスタイルであるという指摘をmorimorihogeさんからいただいたので、改めました。
  • &blockによる明示的なブロック仮引数を使用するのは標準的なスタイルなので、省略しないようにしましょう。

参考: Rubyスタイルガイド: bbatsov/ruby-style-guide

使い方

a = run_once { puts "hello" }
a.call #=> "hello"
a.call #=> nil
a.call #=> nil
a.call #=> nil

応用: run_timesメソッド

上のコードを少し変えれば、渡した数値の回数だけブロックを実行し、以後は実行しないようにもできます。
デフォルト回数は1にしてみました。

コード

# Runs a block n times
# @param [num] (keyword arg) is the number of times to run the block, as well as a block to run
# @return the object that is returned from the block by the times specified; nil after that
def run_times(num: 1, &block)
  lambda do
    return if num < 1 
    num -= 1
    yield
  end
end

使い方

# キーワード引数で回数を渡す(引数のかっこは省略できない)
a = run_times(num:3) { puts "hello" }
a.call #=> "hello"
a.call #=> "hello"
a.call #=> "hello"
a.call #=> nil

callもなしにできればいいなと思いましたが、それは言わない約束ということで。

こぼれ話

クロージャ(closure)は、ブレスレットやネックレスなどを輪にして止めるときの方式・メカニズムを指すこともあるようです。closure rubyで検索してみて気が付きました。

追伸: リファクタリング

公開後、morimorihogeさんからリファクタリング案をいただきました。

  • run_timesの名前付き引数は冗長かも(ブロック以外の引数が1つしかないし、渡す値も明らかなので)
  • メソッドが2つになったのだから共通化してみては。
# リファクタリング後
def run_times(num, &block)
  lambda do
    return if num < 1 
    num -= 1
    yield
  end
end

def run_once(&block)
  run_times(1, &block)
end

関連記事

Ruby on RailsによるWEBシステム開発、Android/iPhoneアプリ開発、電子書籍配信のことならお任せください この記事を書いた人と働こう! Ruby on Rails の開発なら実績豊富なBPS

この記事の著者

hachi8833

Twitter: @hachi8833 コボラー、ITコンサル、ローカライズ業界を経てなぜかWeb開発者志願。 これまでにRuby on Rails チュートリアルの大半、Railsガイドのほぼすべてを翻訳。 かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。 仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

関連する記事

週刊Railsウォッチ

インフラ

Rubyスタイルガイドを読む

BigBinary記事より

ActiveSupport探訪シリーズ