Computer >> คอมพิวเตอร์ >  >> การเขียนโปรแกรม >> Ruby

วิธีเขียนส่วนขยาย Ruby C (ทีละขั้นตอน)

การเขียนส่วนขยาย 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 เนื่องจากมีเอกสารไม่ครบถ้วน

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