การเขียนส่วนขยาย C ช่วยให้คุณโต้ตอบกับ Ruby จาก C.
คุณอาจต้องการทำเช่นนี้หากมีวิธีการสำคัญเฉพาะที่คุณต้องการปรับให้เหมาะสมด้วยความเร็ว C หรือหากคุณต้องการสร้างอินเทอร์เฟซระหว่างไลบรารี C และ Ruby
อีกทางเลือกหนึ่งคือการใช้โมดูล FFI
ตอนนี้ :
มาค้นพบวิธีเขียนส่วนขยาย C กันเถอะ!
ส่วนขยาย C แรกของคุณ
สร้างไฟล์ชื่อ extconf.rb
ด้วยเนื้อหาเหล่านี้:
require 'mkmf' create_header create_makefile 'foobar'
จากนั้นเรียกใช้ ruby extconf.rb
ซึ่งจะสร้างไฟล์บางไฟล์ให้คุณ (Makefile
&extconf.h
). อย่าเปลี่ยนไฟล์เหล่านี้
ตอนนี้สร้าง foobar.c
, ชื่อนี้มาจาก create_makefile
บรรทัดใน extconf.rb
. คุณสามารถเปลี่ยนได้หากต้องการ แต่ต้องตรงกับ .c
. ของคุณ ชื่อไฟล์เพื่อให้ใช้งานได้
ภายใน foobar.c
คุณเพิ่มสิ่งนี้:
#include "ruby.h" #include "extconf.h" void Init_foobar() { // Your C code goes here }
นี่คือโครงร่างพื้นฐานของส่วนขยาย C ของคุณ สังเกตว่าคุณต้องใช้ชื่อที่คุณประกาศใน extconf.rb
บวกคำว่า Init_
. ในกรณีนี้ Init_foobar
.
คุณสามารถคอมไพล์ได้โดยเรียกใช้ make
และสิ่งที่คุณได้รับคือ so
ไฟล์ที่คุณสามารถโหลดลงในแอปพลิเคชัน Ruby ของคุณโดยใช้ require
.
การเขียนวิธี Ruby จากภาษา C
คุณสามารถสร้างฟังก์ชัน c ที่คุณเรียกใช้ได้จากรหัส Ruby ของคุณ นี่คือการทำงานของคลาสและเมธอดในตัว
วิธี Ruby ทั้งหมดต้องส่งคืน VALUE
. A VALUE
เป็นวัตถุทับทิม
ตัวอย่าง :
VALUE rb_return_nil() { return Qnil; }
ตอนนี้เราจำเป็นต้องแนบฟังก์ชันนี้กับคลาส Ruby หรือโมดูล คุณสามารถสร้างชั้นเรียนใหม่หรือใช้ชั้นเรียนที่มีอยู่ได้
ฉันกำลังสร้างโมดูล :
void Init_foobar() { VALUE mod = rb_define_module("RubyGuides"); rb_define_method(mod, "return_nil", rb_return_nil, 0); }
คุณสามารถใช้ rb_define_method
วิธีการแนบฟังก์ชัน C กับโมดูลนี้
ข้อโต้แย้งคือ :
อาร์กิวเมนต์ | คำอธิบาย |
---|---|
mod | อ็อบเจ็กต์โมดูล |
“print_hello” | ชื่อของวิธี Ruby |
rb_print_hello | ชื่อของฟังก์ชัน C |
0 | จำนวนอาร์กิวเมนต์ที่วิธีนี้รับ ใช้ -1 สำหรับอาร์กิวเมนต์ตัวแปร |
ตอนนี้เรียกใช้ make
อีกครั้งเพื่อคอมไพล์ส่วนขยายแล้วลองแบบนี้:
require 'foobar' include RubyGuides print_hello
ไปเลย คุณเพิ่งเรียกฟังก์ชัน C จาก Ruby!
การสร้าง Ruby Hash จาก C
บ่อยครั้งคุณจะต้องการสร้างและจัดการวัตถุ Ruby จาก C.
คุณสามารถทำได้โดยใช้ C API
ตัวอย่างเช่น ในการสร้างแฮชและเพิ่มองค์ประกอบบางอย่างลงไป:
VALUE create_hash() { hash = rb_hash_new(); rb_hash_aset(hash, rb_str_new2("test"), INT2FIX(1)); return hash; }
สิ่งสำคัญสองประการที่ควรสังเกตที่นี่ อย่างแรกคือ rb_str_new2
ฟังก์ชันนี้จะสร้างสตริงทับทิม
จากนั้น INT2FIX
มาโคร ซึ่งจะแปลงจำนวนเต็มปกติเป็นจำนวนเต็ม Ruby
ตอนนี้ หากคุณเปิดเผยฟังก์ชันนี้แก่ Ruby โดยใช้ rb_define_method
คุณจะได้รับแฮช Ruby ปกติด้วยคีย์เดียว (test
) &ค่า 1
.
อย่าลืมคอมไพล์ส่วนขยายใหม่ทุกครั้งที่ทำการเปลี่ยนแปลง 🙂
การทำงานกับสตริง
ฟังก์ชัน C ของคุณยังสามารถรับพารามิเตอร์ได้
ตัวอย่างเช่น:
VALUE rb_print_length(VALUE self, VALUE str) { if (RB_TYPE_P(str, T_STRING) == 1) { return rb_sprintf("String length: %ld", RSTRING_LEN(str)); } return Qnil; } void Init_foobar() { rb_define_global_function("print_length", rb_print_length, 1); }
ที่นี่เรากำลังใช้ VALUE
(ruby object) เป็นอาร์กิวเมนต์ &จากนั้นเราตรวจสอบให้แน่ใจว่าเป็นสตริงที่มี RB_TYPE_P
มาโคร หลังจากนั้น เราก็พิมพ์ความยาวสตริงโดยใช้ RSTRING_LEN
มาโคร
หากคุณต้องการตัวชี้ไปยังข้อมูลสตริง คุณสามารถใช้ RSTRING_PTR
มาโคร
ตัวอย่าง :
VALUE rb_print_data(VALUE self, VALUE str) { if (RB_TYPE_P(str, T_STRING) == 1) { return rb_sprintf("String length: %s", RSTRING_LEN(str)); } return Qnil; }
สังเกตว่ามีพารามิเตอร์อื่นที่นี่อย่างไร self
, นี่คือวัตถุที่ได้รับการเรียกวิธีการ
หากคุณต้องการกำหนดวิธีการนี้ในคลาส String เอง คุณจะต้องทำดังนี้:
void Init_foobar() { rb_define_method(rb_cString, "print_length", rb_print_length, 0); }
สรุป
คุณได้เรียนรู้วิธีเขียนส่วนขยาย C สำหรับ Ruby เพื่อให้คุณสามารถเข้าถึงพลังทั้งหมดของ C จากโปรแกรม Ruby ของคุณ คุณยังได้เรียนรู้วิธีเปิดเผยฟังก์ชัน C ใน Ruby และวิธีทำงานกับวัตถุ Ruby จาก C เช่น strings &hashes
หากคุณต้องการฟังก์ชันเพิ่มเติมเพื่อโต้ตอบกับ Ruby จากภาษา C คุณอาจต้องค้นหาฟังก์ชันเหล่านี้ในซอร์สโค้ดของ Ruby และการอ่านโค้ดส่วนขยาย C เนื่องจากมีเอกสารไม่ครบถ้วน
หวังว่าบทความนี้จะมีประโยชน์และน่าสนใจ! หากคุณเคย โปรดแชร์กับเพื่อน ๆ ของคุณเพื่อให้พวกเขาได้สนุกไปกับมันด้วย