การเขียนส่วนขยาย 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 เนื่องจากมีเอกสารไม่ครบถ้วน
หวังว่าบทความนี้จะมีประโยชน์และน่าสนใจ! หากคุณเคย โปรดแชร์กับเพื่อน ๆ ของคุณเพื่อให้พวกเขาได้สนุกไปกับมันด้วย