Computer >> Máy Tính >  >> Lập trình >> Ruby

Cách viết tiện ích mở rộng Ruby C (Từng bước)

Viết một phần mở rộng C cho phép bạn tương tác với Ruby từ C.

Bạn có thể muốn điều này nếu có một phương pháp đặc biệt quan trọng mà bạn muốn tối ưu hóa với tốc độ của C hoặc nếu bạn muốn tạo giao diện giữa thư viện C và Ruby.

Một giải pháp thay thế sẽ là sử dụng mô-đun FFI.

Bây giờ :

Hãy cùng khám phá cách viết tiện ích mở rộng C!

Tiện ích mở rộng C đầu tiên của bạn

Tạo một tệp có tên extconf.rb với những nội dung sau:

require 'mkmf'

create_header
create_makefile 'foobar'

Sau đó chạy ruby extconf.rb sẽ tạo một vài tệp cho bạn (Makefile &extconf.h ). Không thay đổi các tệp này.

Bây giờ, hãy tạo foobar.c , tên này đến từ create_makefile dòng trong extconf.rb . Bạn có thể thay đổi nó nếu bạn muốn nhưng nó phải phù hợp với .c của bạn tên tệp để cái này hoạt động.

Bên trong foobar.c bạn thêm cái này:

#include "ruby.h"
#include "extconf.h"

void Init_foobar()
{
  // Your C code goes here
}

Đây là khung cơ bản của phần mở rộng C của bạn. Lưu ý rằng bạn phải sử dụng tên bạn đã khai báo trên extconf.rb cộng với từ Init_ . Trong trường hợp này Init_foobar .

Bạn có thể biên dịch nó bằng cách chạy make và những gì bạn nhận được là một so tệp mà bạn có thể tải vào ứng dụng Ruby của mình bằng cách sử dụng require .

Viết một phương pháp Ruby từ C

Bạn có thể tạo các hàm c mà bạn có thể gọi từ mã Ruby của mình. Đây là cách các lớp và phương thức tích hợp sẵn hoạt động.

Tất cả các phương thức Ruby phải trả về một VALUE . Một VALUE là một đối tượng Ruby.

Ví dụ :

VALUE rb_return_nil() {
  return Qnil;
}

Bây giờ chúng ta cần đính kèm hàm này vào một lớp hoặc mô-đun Ruby. Bạn có thể tạo một lớp mới hoặc sử dụng một lớp hiện có.

Đây là tôi đang tạo một mô-đun :

void Init_foobar() {
  VALUE mod = rb_define_module("RubyGuides");

  rb_define_method(mod, "return_nil", rb_return_nil, 0);
}

Bạn có thể sử dụng rb_define_method để đính kèm hàm C vào mô-đun này.

Các đối số là :

Đối số Mô tả
mod Đối tượng mô-đun
“print_hello” Tên của phương thức Ruby
rb_print_hello Tên của hàm C
0 Số lượng đối số mà phương pháp này nhận, sử dụng -1 cho các đối số biến

Bây giờ hãy chạy make một lần nữa để biên dịch tiện ích mở rộng và thử nó như thế này:

require 'foobar'

include RubyGuides
print_hello

Vậy là xong, bạn vừa gọi một hàm C từ Ruby!

Tạo Ruby Hash từ C

Thường thì bạn sẽ muốn tạo và thao tác các đối tượng Ruby từ C.

Bạn có thể làm điều đó bằng cách sử dụng API C.

Ví dụ:để tạo một hàm băm và thêm một số phần tử vào nó:

VALUE create_hash() {
  hash = rb_hash_new();

  rb_hash_aset(hash, rb_str_new2("test"), INT2FIX(1));
  return hash;
}

Hai điều quan trọng cần lưu ý ở đây, đầu tiên là rb_str_new2 , điều này tạo ra một chuỗi Ruby.

Sau đó, INT2FIX macro, điều này sẽ chuyển đổi một số nguyên thông thường thành một số nguyên Ruby.

Bây giờ nếu bạn hiển thị hàm này cho Ruby bằng cách sử dụng rb_define_method bạn sẽ nhận được một hàm băm Ruby thông thường với một khóa (test ) &giá trị 1 .

Đừng quên biên dịch lại tiện ích mở rộng của bạn mỗi khi bạn thực hiện thay đổi 🙂

Làm việc với chuỗi

Các hàm C của bạn cũng có thể nhận tham số.

Ví dụ:

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);
}

Ở đây, chúng tôi đang lấy một VALUE (đối tượng ruby) làm đối số và sau đó chúng tôi đảm bảo rằng đó là một chuỗi có RB_TYPE_P vĩ mô. Sau đó, chúng tôi chỉ in độ dài chuỗi bằng RSTRING_LEN macro.

Nếu bạn muốn một con trỏ đến dữ liệu chuỗi, bạn có thể sử dụng RSTRING_PTR macro.

Ví dụ :

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;
}

Cũng lưu ý cách có một tham số khác ở đây, self , đây là đối tượng nhận lệnh gọi phương thức.

Nếu bạn muốn định nghĩa phương thức này trên chính lớp String, bạn sẽ thực hiện như sau:

void Init_foobar()
{
  rb_define_method(rb_cString, "print_length", rb_print_length, 0);
}

Tóm tắt

Bạn đã học cách viết phần mở rộng C cho Ruby để bạn có thể truy cập tất cả sức mạnh của C từ các chương trình Ruby của mình. Bạn cũng đã học cách đưa các hàm C vào Ruby và cách làm việc với các đối tượng Ruby từ C, như chuỗi &băm.

Nếu bạn cần nhiều chức năng hơn để tương tác với Ruby từ C, bạn có thể phải tìm chúng trong mã nguồn của Ruby và đọc mã mở rộng C vì điều này không được ghi chép đầy đủ.

Hy vọng bạn thấy bài viết này hữu ích và thú vị! Nếu bạn đã làm, hãy chia sẻ nó với bạn bè của bạn để họ cũng có thể thưởng thức nó.