Bạn có thể biết Ruby đưa command-line arguments vào một global array tên là ARGV. Nhưng tại sao nó lại gọi là ARGV? Đây là một bài học lịch sử thú vị làm nổi bật nguồn gốc của Ruby từ C.
Argument Vector
ARGV là viết tắt của argument vector. Và "vector" trong cách dùng cũ kỳ lạ này nghĩa là "một mảng một chiều".
Trong C, mọi chương trình có hàm main(). Nó thường trông như sau:
int main(int argc, char *argv[]) {
... your code here
}
Như bạn thấy, hàm main có hai arguments. Chúng lần lượt là count và một mảng command-line arguments.
Khi bạn bảo bash chạy chương trình, nó làm system call khiến OS gọi hàm main của chương trình và truyền các giá trị argc và argv cụ thể.
Ruby
Ruby interpreter — MRI ít nhất — chỉ là một chương trình C. Đây là hàm main của Ruby:
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));
}
}
Như bạn thấy, nó truyền argc và argv cho hàm ruby_options, hàm này gọi ruby_process_options, hàm này gọi process_options.
Đó xử lý tất cả ruby interpreter options và cuối cùng gọi ruby_set_argv, set ARGV bạn thấy trong Ruby code.
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);
}
}
Khá gọn gàng. Tôi vẫn mới khi đào sâu vào MRI codebase, nhưng khá vui khi nhảy vào xem chính xác mọi thứ hoạt động như thế nào.