難しいが強力! Rubyのメタプログラミング、self、特異クラス/メソッド、オープンクラスとモンキーパッチ:若手エンジニア/初心者のためのRuby 2.1入門(12)(1/4 ページ)
オープンソースのオブジェクト指向プログラミング言語「Ruby」の文法を一から学ぶための入門連載。最新版の2.1に対応しています。今回は、Rubyの「黒魔術」といわれるメタプログラミングの概要、self、特異メソッド、特異クラス、オープンクラス、モンキーパッチなどの使い方をコード例を交えて解説します。
メタプログラミングのパターンを理解するための土台を習得しよう
今回の主な内容
連載第10回の「RubyのFile/IOクラスで入力と出力、ファイルの読み取りと書き込み、フィルター作成」、第11回の前回「RubyのThread、Fiber、Kernel、forkで並列処理やプロセスの深淵へ」では、データの入出力やスレッド、ファイバー、プロセスといったトピックについて解説しました。これらの知識を活用することにより、データの入出力を自在にコントロールしたり、複数のタスクをスレッドやプロセスといった単位で分割処理を行ったりすることができます。
連載第12回の今回は、RubyをRubyたらしめる、「メタプログラミング」という概念について解説します。込み入った話になるので少し難しいかもしれません。ですが、メタプログラミングとはどういうものかを知っておくことは、初心者からステップアップするためには避けて通れない道です。
メタプログラミングには、さまざまなパターンがあります。メタプログラミングという題材で一冊の本になってしまうほどです。ここでは、数あるメタプログラミングのパターンを理解するための土台となる、selfや特異クラス、特異メソッドといったトピックについて解説します。そして最後に、いくつかの簡単なメタプログラミングのパターンを紹介します。
Rubyの黒魔術「メタプログラミング」とは
そもそも、メタプログラミングとは何でしょうか? C#やJavaといった言語を学んだ方はあまりなじみがないかもしれません。また、C++を学んだ方は、テンプレートを利用したメタプログラミングをご存じの方もいると思います。
映画やゲーム、漫画などの作品で、作中の登場人物ではなく視聴者に語りかけてくるようなセリフを「メタ発言」などと言います。このように、「メタ」という言葉には、より上位の存在や抽象概念といった意味があります。
「メタプログラム」とは、大ざっぱに言うと「コードを生成するコード」のことを指します。もう少し詳細に言うと、「より抽象的な記法を使ってコードを書くことにより、動的にコードを生成するコード」です。そして、メタプログラミングはメタプログラムを書くことを言います。メタプログラムでは、どのようなコードが実行されるかは実行時に決まります。
簡単なコード例
言葉では分かりにくいので、簡単なコード例を使って説明します。
method_name = ARGV[0] define_method method_name do puts "This method is named #{method_name}." end alice
$ ruby meta_programming_01.rb alice This method is named alice. $ ruby meta_programming_01.rb white_rabbit meta_programming_01.rb:7:in 「<main>': undefined local variable or method 「alice' for main:Object (NameError)
では、コードを確認していきましょう。
まず1行目で、「ARGV」を使って、コマンドライン引数に与えられた1番目の文字列を、「method_name」という変数に格納しています。
3〜5行目では、「define_method」という見慣れないメソッドが登場しています。「define_method」は、その名の通り、「メソッドを定義するためのメソッド」です。「hoge」というメソッドを定義するときの、「def hoge〜end」というような記法のメタ版です。
「define_method」の引数には、定義したいメソッドを表す文字列やシンボルを渡します。そして、ブロックの中に定義したメソッドで行いたい処理を記述します。3〜5行目で、コマンドライン引数に与えられた名前のメソッドを定義し、4行目の「puts」で、そのメソッド名を使ったメッセージを出力しています。
6行目では「alice」というメソッドを単純に呼び出しています。
実行例の1行目では、コマンドライン引数に「alice」という文字列を与えているので、きちんとメッセージが出力されています。3行目の実行例では「white_rabbit」という文字列を与えているため、「undefined local variable or method」、つまり「white_rabbitというローカル変数またはメソッドが定義されていない」というエラーが出ています。
ここで、3行目の「define_method」で定義されるメソッド名は、実行時まで分からないことに注目してください。なぜなら、どのような文字列がコマンドライン引数によって与えられるかは、実行される瞬間まで分からないからです。
抽象的なコードは「分かりにくい」
「define_method」を利用した場合、通常の「def」によるメソッドの定義よりも、何となく小難しく見えるかと思います。それは当然の感覚で、より抽象的な書き方をしているので難しく感じるのです。小学校で習うような足し算や引き算は、「右手にりんごが1個、左手にりんごが2個、合わせて3個」のように具体的に想像できるので簡単ですが、大学で学ぶような微分積分などの解析学や圏論といった数学は非常に抽象的で難しいのと同じ理由です。
その抽象度から、メタプログラミングを乱用すると、たちまち誰も読み解けない(1週間後の自分ですら!)スパゲッティコードが出来上がってしまいます。半面、抽象的であるが故に、似たようなコードを抽象的にスッキリまとめて書ける、既存のクラスを自在に拡張できるなどの大きなメリットがあります。
実際に、「Ruby on Rails」「RSpec」といったライブラリでは、メタプログラミングによる黒魔術を効果的に利用しています。
Rubyではカジュアルにメタなコードを書くことができますが、「本当に、これはメタに書くべきか?」という自問を常に怠らないようにしましょう。
Copyright © ITmedia, Inc. All Rights Reserved.
関連記事
- 数々の“スペル”で高度なプログラミング:Rubyの魔術
- 公用語に英語、「再起動」したRubyKaigi 2013が東京で開催
いったん終了していたRubyコミュニティ主催の年次イベントが再開。技術色、国際色を強め、盛況のうちに幕を閉じた - Web業界、今から行くならRubyエンジニアが狙い目?
不況で冷え込んでいたIT業界の転職市場に、回復の兆しが見え始めている。だが、業種や職種によって採用数や条件に大きな差異が生まれている。転職市場の動向を追い、自身のキャリア戦略立案に生かしてほしい。 - Ruby 2.0.0がリリース、大規模化対応の機能などを搭載
生誕20年となる節目を迎えて、プログラミング言語「Ruby」の最新版がリリースされた - 新バージョンで何が変わるのか、Rubyはどこへ向かうのか:まつもと×笹田、Ruby 1.9を語る
- いよいよ始まるRuby 1.9への移行:開発コアメンバが語るRubyの今とこれから(前編)
- Rubyの今後の進化の方向性とは?:開発コアメンバが語るRubyの今とこれから(後編)
- 互換性や脆弱性の問題にどう対応していくのか:Rubyが抱える課題、NaClの前田氏が講演
- Rails Hub情報局:「なんでRubyなんか作った!? 迷惑だ!」に対するMatzの答え
- Rails Hub情報局:Rubyはイノベーション言語として選ばれている
- Rails Hub情報局:Rubyのまつもと氏は、一発屋で終わるのか?
- Rails Hub情報局:Rubyに魔法は要らない
- 数々の“スペル”で高度なプログラミング:Rubyの魔術
- 晴読雨読@エンジニアライフ:『たのしい開発 スタートアップRuby』――なぜRubyistたちはあれほど楽しそうなのか
- 「JRuby 1.7.0」登場、1年半ぶりのメジャーアップデート
JavaVM上のRuby実装「JRuby」の最新版となる「JRuby 1.7.0」が、10月22日にリリースされた。