RubyのARGVはどうやって設定される?C言語に由来する「引数ベクター」の秘密
Rubyがコマンドライン引数をARGVというグローバル配列に格納することは、多くの方がご存じでしょう。しかし、なぜそれが「ARGV」という名前なのか、疑問に思ったことはありませんか?実はそこには、RubyのルーツであるC言語につながる興味深い歴史的背景があるのです。
Argument Vector(引数ベクター)とは
ARGVは「argument vector」の略です。ここでいう「vector(ベクター)」とは、少し古風な用法で「1次元配列」を意味しています。
C言語では、すべてのプログラムにmain()関数が必要で、一般的には次のような形をしています。
int main(int argc, char *argv[]) {
... your code here
}
お気づきのとおり、main関数は2つの引数を受け取ります。それぞれ「コマンドライン引数の個数(count)」と「コマンドライン引数の配列(array)」です。
bashなどからプログラムを実行すると、システムコールが発行され、OSがそのプログラムのmain関数を呼び出します。このとき、適切なargcとargvの値が渡される仕組みになっています。
RubyにおけるARGVの設定流程
Rubyインタプリタ(少なくともMRI)は、実体としてはひとつのCプログラムです。以下がRubyのmain関数です。
int
main(int argc, char **argv)
{
#ifdef RUBY_DEBUG_ENV
ruby_set_debug_option(getenv("RUBY_DEBUG"));
#endif
#ifdef HAVE_LOCALE_H
setlocale(LC_CTYPE, "");
#endif
ruby_sysinit(&argc, &argv);
{
RUBY_INIT_STACK;
ruby_init();
return ruby_run_node(ruby_options(argc, argv));
}
}
ご覧のとおり、argcとargvはruby_optionsという関数へ渡され、さらにその中でruby_process_optionsが呼ばれ、続いてprocess_optionsが呼び出されます。
この一連の流れでRubyインタプリタ自身のオプションがすべて処理され、最終的にruby_set_argvが実行されます。これこそが、私たちがRubyコードの中で目にするARGVを設定している関数です。
void
ruby_set_argv(int argc, char **argv)
{
int i;
VALUE av = rb_argv;
#if defined(USE_DLN_A_OUT)
if (origarg.argv)
dln_argv0 = origarg.argv[0];
else
dln_argv0 = argv[0];
#endif
rb_ary_clear(av);
for (i = 0; i < argc; i++) {
VALUE arg = external_str_new_cstr(argv[i]);
OBJ_FREEZE(arg);
rb_ary_push(av, arg);
}
}
このコードでは、まず既存のrb_argv配列をクリアし、受け取った各引数をRubyの文字列オブジェクトに変換したうえで、凍結(freeze)して配列に追加していきます。こうして、Rubyスクリプト側から参照できるARGVが完成するのです。
なかなか興味深い仕組みですね。MRIのコードベースを深く掘り下げ始めたばかりですが、内部で何が起きているのかを実際に確認できるのは、とても楽しい体験です。
-
RubyのStructとOpenStructの使い方を徹底解説!値オブジェクトを簡単に作る方法
Rubyには、関連する属性をまとめて保持する「値オブジェクト」を手軽に作れるStructという組み込みクラスが用意されています。本記事では、Structの基本的な使い方から注意点、そしてOpenStructとの違いまで詳しく解説します。 そもそもStructとは何か? StructはRubyに組み込まれたクラスで、新しいクラスを動的に生成し、値オブジェクト(Value Object)を作成するために使われます。値オブジェクトとは、関連性のある複数の属性をひとまとめにして扱うためのオブジェクトです。 具体例を挙げてみましょう。 2つの座標(xとy)を持つPointというデータを表したい場合、この
-
【Redis入門】SMEMBERSコマンドでセットの全要素を取得する方法
このチュートリアルでは、redis-cliでSMEMBERSコマンドを使用して、指定したキーに保存されたセット(Set)型の値からすべての要素を取得する方法を解説します。 SMEMBERSは、セットに格納されている全メンバーを一括で取得できるシンプルかつ便利なコマンドです。それでは、基本的な使い方を見ていきましょう。 構文 redis host:port> SMEMBERS <keyname> 戻り値 配列(Array):セットに含まれるすべての要素を返します。 エラー:キーが存在するものの、そのキーに保存されている値がセット型ではない場合にエラーを返します。 使用例 ま