Rubyスタイルガイドを読む: 文法(4)ループ

こんにちは、hachi8833です。

「Rubyスタイルガイドを読む」シリーズの文法編その4は、whileuntilなどのループについてです。

文法(4) ループ

2-25【統一】複数行のwhileuntilでは条件の後にdoを置かない

Do not use while/until condition do for multi-line while/until.

# 不可
while x > 5 do
  #(本文省略)
end

until x > 5 do
  #(本文省略)
end

# 良好
while x > 5
  #(本文省略)
end

until x > 5
  #(本文省略)
end

whileuntilの文法では、以下のようにdoはオプションになっています。このスタイルではdoを置かない方に揃えています。

while 式 [do]
   ...
end

until 式 [do]
   ...
end

2-26【統一】whileuntilの本文が単文の場合は後置にするのが望ましい

Favor modifier while/until usage when you have a single-line body.

# 不可
while some_condition
  do_something
end

# 良好
do_something while some_condition

仕様にもあるように、whileuntilは、後置のifuntilと同様に修飾子として使えるので、うまく使うとコードを簡潔に書くことができます。

# while修飾子
sleep(60) while io_not_ready?

# until修飾子
print(f.gets) until f.eof?

追伸:

whileuntilは条件や結果にかかわらずnilだけを返すのかと思っていたのですが、リファレンス・マニュアルによると式の戻り値を返すこともできるそうです。

  • while は nil を返します。また、引数を伴った break により while 式の戻り値をその値にすることもできます。
  • while 修飾した式は nil を返します。 また、引数を伴った break により while 修飾した式の戻り値をその値にすることもできます。
  • until は nil を返します。また、引数を伴った break により until 式の戻り値をその値にすることもできます。
  • until 修飾した式は nil を返します。 また、引数を伴った break により until 修飾した式の戻り値をその値にすることもできます。
    Ruby 2.4.0リファレンスマニュアルより

2-27【統一】否定条件をwhileで表すよりも、条件を肯定にしてuntilにする方が望ましい

Favor until over while for negative conditions.

# 不可
do_something while !some_condition

# 良好
do_something until some_condition

プログラミング言語の種類を問わず、否定条件を肯定条件に置き換える方が一般に読みやすくなります。

2-28【統一】無限ループはKernel#loopで書くこと

Use Kernel#loop instead of while/until when you need an infinite loop.

# 不可
while true
  do_something
end

until false
  do_something
end

# 良好
loop do
  do_something
end

文法上はwhileuntilに条件を設定しないことでも無限ループを形成できますが、Kernel#loopで統一することでwhileuntilの役割をはっきりさせるという意図と理解しました。

2-29【統一】begin/end/untilbegin/end/whileではなく、Kernel#loopbreakを使う

Use Kernel#loop with break rather than begin/end/until or begin/end/while for post-loop tests.

# 不可
begin
  puts val
  val += 1
end while val < 0

# 良好
loop do
  puts val
  val += 1
  break unless val < 0
end

他の言語でいう「do〜while」的な書き方をする場合はKernel#loopbreakに統一します。

2-30【統一】暗黙のハッシュを引数として渡す場合、外側の波かっこ{ }は省略する

Omit the outer braces around an implicit options hash.

# 不可
user.set({ name: 'John', age: 45, permissions: { read: true } })

# 良好
user.set(name: 'John', age: 45, permissions: { read: true })

1つのハッシュのみを引数として渡すときに波かっこを省略できますが、それをスタイルとして指定しています。これは読みやすさのためでしょうね。

なお、この例では以下のようにさらに丸かっこ( )を省略しても動作しましたが、丸かっこ( )を省略せよという指示はここにはありません。丸かっこの省略については次の項目をご覧ください。

2-31【統一】内部DSLの一部であるメソッドでは、引数の波かっこ{ }と丸かっこ( )を両方省略する

Omit both the outer braces and parentheses for methods that are part of an internal DSL.

class Person < ActiveRecord::Base
  # 不可
  validates(:name, { presence: true, length: { within: 1..10 } })

  # 良好
  validates :name, presence: true, length: { within: 1..10 }
end

内部DSLはRubyの文法に沿ってはいますが独自に拡張されているため、DSLであることをわかりやすくするためであると理解しました。

今回はここまでとします。次回の文法編はブロック関連です。ご期待ください。

関連記事


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

この記事の著者

hachi8833

Twitter: @hachi8833、GitHub: @hachi8833

コボラー、ITコンサル、ローカライズ業界、Rails開発を経てTechRachoの編集・記事作成を担当。
これまでにRuby on Rails チュートリアル第2版の半分ほど、Railsガイドの初期翻訳ではほぼすべてを翻訳。その後も折に触れてそれぞれ一部を翻訳。
かと思うと、正規表現の粋を尽くした日本語エラーチェックサービス enno.jpを運営。
実は最近Go言語が好き。
仕事に関係ないすっとこブログ「あけてくれ」は2000年頃から多少の中断をはさんで継続、現在はnote.muに移転。

hachi8833の書いた記事

BPSアドベントカレンダー

週刊Railsウォッチ

インフラ

BigBinary記事より

ActiveSupport探訪シリーズ