-
Rubyがコードを解析する様子を覗いてみよう
実用的なTipsから少し離れて、今回はRubyのちょっとした「お楽しみトリック」をご紹介します。 Rubyは実行前にコードを解析している Rubyはプログラムを実行する前に、必ずそのソースコードを解析(パース)しなければなりません。この処理を担っているのがパーサーであり、その正体は一種のステートマシン(状態機械)です。 そして実は、あまり知られていないコマンドラインフラグを使うことで、このステートマシンが行うすべての動作をログとして出力できます。 -y フラグでパーサーの動きを可視化する 次のようなごく単純なコードを例にしてみましょう。 a = 1 + 2 このファイルを -y フラグ付
-
Rubyでコマンドライン操作をレベルアップさせる方法
コマンドラインを本当にマスターするには、数十、場合によっては数百もの小さなユーティリティプログラムを使いこなす必要があります。それぞれが微妙に異なる動作をするため、最初は圧倒されてしまうことも少なくありません。 幸いなことに、こうした単一目的のツールの多くは、Rubyのような汎用プログラミング言語に置き換えることができます。すでにあるRubyの知識をそのまま活かして、コマンドラインスキルを一段引き上げられるのです。 この記事では、Rubyを「コマンドラインのスイスアーミーナイフ」として使うための基礎を解説します。小手先のワンライナーを大量に並べるのではなく、仕組みそのものを理解してもらい、読者
-
RubyのRationalクラスで分数と有理数を操作する方法
正直に告白します。私は浮動小数点数があまり好きではありません。コンピュータにとっては確かに便利な存在ですが、人間の目には次のような結果は理解しがたいものです。 129.95 * 100 # => 12994.999999999998 この結果は数学的な美しさに反しているだけでなく、ユーザー体験(UX)の観点からも好ましくありません。 もしレシピに「小麦粉を0.37211927843カップ計ってください」と書いてあったら、読んだ人はきっと著者のセンスに苦笑しながら、実際には3分の1カップを測ることになるでしょう。 多くの人は、任意の桁の小数よりも分数の方がはるかにイメージしやすいものです
-
RubyのTracePointで複雑な例外の挙動を調査する方法
例外の挙動を把握するのは、時に非常に難しいものです。特に大規模なアプリケーションではその傾向が強まります。既存のプロジェクトでコードを書いていて、例外をraiseしたのに奇妙なことが起こった経験はありませんか?例外がどこかで握りつぶされている。環境変数が書き換えられている。あるいは、自分のraiseした例外が別の例外に包まれてしまう——そんなケースです。 この記事では、TracePointを使ってアプリケーション内の例外についてより詳しい情報を得るためのシンプルな方法を紹介します。例外が握りつぶされていたとしても、その動きを追跡できます。 わかりやすい例:コントローラでrescueできない
-
Rubyで例外発生時に処理を再試行する方法:retryキーワードとContinuationの活用術
すべてのエラーが致命的というわけではありません。中には、単に「もう一度試せば解決する」ことを示しているだけのものもあります。幸い、Rubyには「再試行」を簡単に実現できる興味深い仕組みがいくつか用意されています。ただし、そのすべてが自明だったり、広く知られていたりするわけではありません。この記事では、これらの仕組みと、実務での活用方法について詳しく見ていきます。 retryキーワードの基本 これは一見当たり前の話に思えるかもしれませんが、それはその存在を知っている人だけの話です。筆者自身も、Rubyでのキャリアがある程度進んでから、便利なretryキーワードの存在を初めて知りました。 r
-
RubyのException#causeでネストされた例外の原因を追跡する方法
Rubyでは、例外をrescueして別の種類の例外として再送出(re-raise)するのは非常によくあるパターンです。ActionViewはその分かりやすい例の一つです。以前TracePointについて取り上げた記事でも触れましたが、ActionViewはテンプレート内で発生した例外をすべて握りつぶし、ActionView::Template::Errorとして再送出します。 しかし、この挙動だけでは不十分な場合があります。元の例外には問題解決につながる重要なデータが含まれていることが多く、どうしても元の例外そのものが必要になるのです。幸い、Ruby 2.1以降ではException#caus
-
動的例外マッチャーでRubyのrescueをレベルアップさせる
Rubyでrescue節を使う際、どの種類の例外を捕捉するかを指定できます。方法はシンプルで、例外クラスのリストを渡すだけです。 begin raise RuntimeError rescue RuntimeError, NoMethodError puts rescued! end しかし、コードを書いている時点で、実際にどの例外クラスが発生するか分からない場合はどうでしょうか?最も分かりやすい解決策は、すべての例外を捕捉し、何らかの判定を行った上で、条件を満たさない例外を再スローすることです。例えば、次のようなコードです。 begin raise FUBAR! The shi
-
Unicornはどのようにnginxと通信するのか?Rubyで学ぶUNIXソケットの基礎
Ruby製のアプリケーションサーバーは、通常nginxのようなWebサーバーと組み合わせて運用されます。ユーザーがRailsアプリケーションのページをリクエストすると、nginxがそのリクエストを受け取り、アプリケーションサーバーへ処理を委譲します。しかし、この仕組みは具体的にどのように実現されているのでしょうか?nginxはどのようにしてUnicornと会話しているのでしょうか? 最も効率的な方法のひとつが「UNIXドメインソケット(UNIXソケット)」を使うことです。本記事では、まずソケットの基本から解説し、最終的には自作のシンプルなアプリケーションサーバーを作成して、それをnginxでプ
-
ByebugとRails、Powを使ったリモートデバッグのやり方
Ruby 2.x向けの優れたデバッガー「Byebug」をご存じない方は、ぜひ一度試してみてください。シンプルでありながら多機能で、日々のRuby開発を強力にサポートしてくれるツールです。開発者自身による説明がこちらです。 ByebugはRuby 2向けの、使いやすく機能豊富なデバッガーです。実行制御には新しいTracePoint API、コールスタックのナビゲーションにはDebug Inspector APIを採用しているため、Ruby内部のコアソースに依存しません。C拡張として実装されているため動作が高速で、充実したテストスイートを備えているため信頼性も高いのが特徴です。 基本的な使い方
-
Rubyのcaseステートメント徹底解説 ― 知られざる高度なマッチング術
caseステートメントほどシンプルで地味な構文はありません。C言語から受け継いだ構文で、「大量のif文を置き換えるためのもの」と思われがちです。それ以上の何者でもないのでしょうか?実は違います。 Rubyのcaseステートメントは、想像以上に豊かで奥深い機能を備えています。まずは次の例を見てください。 case Hi there when String puts case statements match class end # 出力: case statements match class この例が示すように、caseステートメントはオブジェクトの値だけでなく、そのクラスまで判定でき
-
Rubyで例外発生時にローカル変数とインスタンス変数をログに記録する方法
簡単には再現できないバグに悩まされたことはありませんか?アプリをしばらく使い続けたユーザーの環境でだけ発生し、エラーメッセージやバックトレースを見ても原因がさっぱり分からない——そんな経験を持つ開発者は多いはずです。 こうした場面で役立つのが、例外が発生する直前のアプリの状態をスナップショットとして記録しておく手法です。たとえば、すべてのローカル変数とその値の一覧を取得できれば、デバッグの強力な手がかりになります。実は、これは思ったより簡単に実現できるのです。 この記事では、例外発生時点でのローカル変数をキャプチャする方法を紹介します。ただし、最初に重要な注意点があります。ここで紹介するテ
-
Rubyで学ぶUNIXデーモンの仕組み――理論と実装のステップバイステップ解説
UNIXデーモンとは、バックグラウンドで動き続けるプログラムのことです。Nginx、PostgreSQL、OpenSSHなどがその代表例として挙げられます。デーモンはいくつかの特殊なテクニックを使ってプロセスを「切り離し(detach)」し、どの端末からも独立した状態で動作できるようにしています。 筆者は昔からデーモンに何かと魅了されてきました(名前の響きのせいかもしれません)。そこで今回は、デーモンがどのように動作するのか、そしてRubyでどうやって作れるのかを解説します。 ……ただし、その前に。 本番環境では真似しないでください! 正直なところ、自分でデーモンを作りたい場面はほとん
-
Rubyの奇妙なErrno例外の正体を理解する ― OSエラーとRubyをつなぐ仕組み
Rubyの例外階層を覗いたことがあるなら、そこに少し奇妙なものが混ざっていることに気づいたかもしれません。RuntimeErrorやNoMethodErrorといった馴染み深い例外に加えて、Errno::*という不思議な表記を見かけたことはないでしょうか。 Exception StandardError ... SystemCallError Errno::* ... ディスクが満杯の状態で書き込みを行ったり、不安定なネットワーク越しにAPIコールを試みたりした経験があれば、この種のエラーに遭遇したことがあるはずです。実際、存在しないファイルを開こうと
-
Rubyで例外にコンテキストデータを追加する3つの方法
標準のバックトレースやエラーメッセージだけでは、エラーの原因を特定するのに十分な情報が得られないことがあります。そんなときに役立つのが、例外への追加データの付与です。幸い、Rubyではこれをとても簡単に実現できます。 エラーメッセージをカスタマイズする 例外にコンテキスト情報を加える最もシンプルな方法は、メッセージそのものに情報を組み込んでしまうことです。次の例では、発生した例外を捕捉し、新しいメッセージを付けて再送出しています。 begin raise foo rescue => e raise e.class, bar end # RuntimeError: bar
-
RubyのFiddleで任意のCライブラリを操作する方法 ― 知られざる標準ライブラリの隠れた実力
Fiddleは、Ruby 1.9.xで標準ライブラリに追加された、あまり知られていないモジュールです。Rubyから直接Cライブラリとやり取りできるだけでなく、実行中のRubyインタプリタそのものを調査・改変することさえ可能です。 Fiddleの仕組みは、libffiという広く使われているCライブラリをラップすることに基づいています。libffiは、ある言語で書かれたコードから別の言語で書かれた関数を呼び出せるようにするライブラリです。「ffi」は「Foreign Function Interface(外部関数インターフェース)」の略称です。さらに、Fiddleの活用範囲はC言語にとどまりませ
-
絵文字の力でSidekiqの全キューを一括クリアする方法
Honeybadgerでは日頃からSidekiqを多用しており、その利便性には大いに助けられています。しかし、開発作業の中で何度も遭遇する厄介な問題がひとつあります。 開発中に溜め込まれたジョブの問題 実は私は、開発環境では普段Sidekiqを起動していません。ところが手動テストを進める過程で、気づけば大量のジョブがキューに登録されてしまいます。そして次にSidekiqを起動したとき、それらの古いジョブをすべて処理しようとしてしまうのです。これは困りものです。 特定の1つのキューからジョブを削除するコードスニペットなら、検索すればすぐに見つかります。しかし、私たちのアプリケーションには多
-
Railsの開発環境で表示される派手な例外ページの仕組みを徹底解説
Railsで開発をしていて何かがうまくいかないとき、とても見やすいエラー詳細ページが表示されるのは嬉しいところです。バックトレースにはアプリに関連する部分がハイライトされ、POSTされたパラメータを確認したり、環境変数やセッション変数を調査することもできます。 今回は、こうした洗練されたエラーページがどのように動作しているのかを詳しく見ていきます。 ActionPackの中身を覗いてみる 今回主に扱うファイルは actionpack/lib/action_dispatch/middleware/debug_exceptions.rb です。開発モードのエラーページ表示において、最も重
-
Rubyで任意のオブジェクトを例外としてraiseする方法
Rubyのraise構文には、発生させたいエラーの種類を指定するための書き方がいくつかあります。以下のコードでは、RuntimeErrorを発生させる3つの方法を紹介します。 raise hello raise RuntimeError, hello raise RuntimeError.new(hello) # ...上記はすべて RuntimeError: hello という結果になる ここまでは便利ですが、例外以外のものを発生させたい場合はどうなるでしょうか?たとえば数値をraiseしたいとしたら?残念ながら、Rubyはそれを許してくれません。次のようなエラーメッセージが表示されます
-
Rubyで例外のベンチマークを取ってみた ― やっぱり遅い
Rubyにおいて、例外は他のフロー制御の仕組みに比べて遅いのではないか――私はずっとそう疑ってきました。なにしろ、例外は単純なbreakやreturnよりもはるかに複雑な仕組みですから。とはいえ、私の勘が外れたことも過去にはありました。そこで、実際に計測して確かめてみることにしたのです。 以下のコードでは、benchmark-ipsというgemを使い、「例外でループを抜ける」「breakで抜ける」「returnで抜ける」という3つの手法の相対的なパフォーマンスを比較しています。Web上ではMRI 1.9で同様のベンチマークを行った例を見かけましたが、今回はMRI 2.2で試してみました。
-
Rubyのlazy Enumeratorで巨大ファイルを効率的に操作する方法
Rubyが強力で柔軟な言語とされる理由の中心には、Enumerator(列挙子)の存在があります。さらに「lazy(遅延)」Enumeratorを使えば、非常に大きなコレクションでも効率的に処理できるようになります。 実は、ファイルとは「行」や「文字」の大きなコレクションにすぎません。つまり、lazy Enumeratorを使えば、ファイルに対して非常に興味深く強力な操作が可能になるのです。 そもそもEnumeratorとは? eachのようなメソッドを使うたびに、実はEnumeratorが生成されています。[1,2,3].map { ... }.reduce { ... }のようにメソ