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

Ruby 2.6先行チェック: Kernel#systemに`exception:`オプションが追加(翻訳)

概要

原著者の許諾を得て翻訳・公開いたします。

Ruby 2.6先行チェック: Kernel#systemにexception:オプションが追加(翻訳)

Ruby 2.6シリーズの記事です。Ruby 2.6.0-preview2は最近リリースされました

私たちが書くRailsアプリの設定/デプロイ自動化スクリプトでは、bundle installrake db:createrake db:migrateなどのシステムコマンドをあちこちで実行しています。

Railsプロジェクトのセットアップスクリプトでのマイグレーションをrake db:migrateで行う必要があるとします。これはKernel#systemメソッドで実行できます。

irb> system('rake db:migrate')

Ruby 2.5.0

systemを実行するとtruefalseが返ります。systemのもうひとつの機能は、例外を握りつぶすことです。

systemコマンドでマイグレーションが成功した場合は、trueを返します。

irb> system('rake db:migrate')
# => true

マイグレーションでテーブルにカラムを追加しようとしたら、テーブルが存在しなかったとしましょう。この場合systemコマンドはfalseを返します。

irb> system('rake db:migrate')
== 20180311211836 AddFirstNameToAdmins: migrating =============================
-- add_column(:admins, :first_name, :string)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "admins" does not exist
: ALTER TABLE "admins" ADD "first_name" character varying
.
.
.
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
# => false

systemコマンドの実行に失敗した場合にfalseが返るので、上では例外が発生しません。

しかし次のように明示的にraiseすればセットアップスクリプトを停止できます。

irb> system('rake db:migrate') || raise('Failed to run migrations')
== 20180311211836 AddFirstNameToAdmins: migrating =============================
-- add_column(:admins, :first_name, :string)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "admins" does not exist
: ALTER TABLE "admins" ADD "first_name" character varying
.
.
.
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Traceback (most recent call last):
        2: from /Users/amit/.rvm/rubies/ruby-2.5.0/bin/irb:11:in `<main>'
        1: from (irb):4
RuntimeError (Failed to run migrations)

Ruby 2.6.0-preview1

Ruby 2.6のKernel#systemではexception: trueオプションが使えるようになったので、上のように明示的なraiseによるスクリプト停止コードを書かなくて済むようになりました。

irb> system('rake db:migrate', exception: true)
== 20180311211836 AddFirstNameToAdmins: migrating =============================
-- add_column(:admins, :first_name, :string)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "admins" does not exist
: ALTER TABLE "admins" ADD "first_name" character varying
.
.
.
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
Traceback (most recent call last):
        3: from /Users/amit/.rvm/rubies/ruby-2.6.0-preview1/bin/irb:11:in `<main>'
        2: from (irb):2
        1: from (irb):2:in `system'
RuntimeError (Command failed with exit 1: rake)

exceptionオプションが指定されていない場合はRuby 2.5と同様にfalseを返します。

irb> system('rake db:migrate', exception: false)
== 20180311211836 AddFirstNameToAdmins: migrating =============================
-- add_column(:admins, :first_name, :string)
rake aborted!
StandardError: An error has occurred, this and all later migrations canceled:

PG::UndefinedTable: ERROR:  relation "admins" does not exist
: ALTER TABLE "admins" ADD "first_name" character varying
.
.
.
Tasks: TOP => db:migrate
(See full trace by running task with --trace)
 => false

なお、スクリプト実行に使えるのはsystemだけではありません。6年前のBigBinaryブログで、backtickexecshpopen3、 popen2e 、Process.spawnとの違いについて説明しています。

関連記事

Ruby 2.6先行チェック: rangeの終端をnilまたは省略できる(翻訳)

Ruby 2.6先行チェック: `String#split`がブロックを取れる(翻訳)


CONTACT

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