Tech Racho エンジニアの「?」を「!」に。
  • 開発

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であることをわかりやすくするためであると理解しました。

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

関連記事



CONTACT

TechRachoでは、パートナーシップをご検討いただける方からの
ご連絡をお待ちしております。ぜひお気軽にご意見・ご相談ください。