คุณอาจรู้ว่า Ruby ใส่อาร์กิวเมนต์บรรทัดคำสั่งลงในอาร์เรย์สากลชื่อ ARGV แต่ทำไมมันถึงเรียกว่า ARGV? นี่เป็นบทเรียนประวัติศาสตร์น่าสนใจที่เน้นที่รากฐานของ Ruby ในภาษา C
Argument Vector (เวกเตอร์อาร์กิวเมนต์)
ARGV ย่อมาจาก Argument Vector และ "Vector" ในความหมายเก่าๆ นี้หมายถึง "อาร์เรย์มิติเดียว"
ในภาษา C ทุกโปรแกรมมีฟังก์ชัน main() ซึ่งมักจะมีลักษณะประมาณนี้:
int main(int argc, char *argv[]) {
... your code here
}
คุณอาจสังเกตเห็นว่าฟังก์ชัน main มีอาร์กิวเมนต์ 2 ตัว ซึ่งคือ จำนวน (count) และอาร์เรย์ของอาร์กิวเมนต์บรรทัดคำสั่ง ตามลำดับ
เมื่อคุณสั่งให้ bash รันโปรแกรม มันจะทำ system call ซึ่งทำให้ OS เรียกฟังก์ชัน main ของโปรแกรมคุณและส่งค่า argc และ argv เข้าไป
Ruby
Ruby interpreter — MRI อย่างน้อย — เป็นเพียงโปรแกรม C นี่คือฟังก์ชัน main ของ 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));
}
}
เห็นได้ชัดว่า มันส่ง argc และ argv ไปยังฟังก์ชัน ruby_options ซึ่งเรียก ruby_process_options ซึ่งเรียก process_options
ฟังก์ชันนี้จัดการออปชันของ Ruby interpreter ทั้งหมด และในที่สุดเรียก ruby_set_argv ซึ่งตั้งค่า ARGV ที่คุณเห็นในโค้ด Ruby ของคุณ
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);
}
}
ค่อนข้างสะดวก ผมยังใหม่ในการดำดุ้นเข้า codebase ของ MRI แต่สนุกมากที่จะดูกันว่าสิ่งต่างๆ ทำงานอย่างไรจริงๆ