热门关键字:  ubuntu  分区  函数  linux系统进程  Fedora

当前位置 :| 主页>Linux教程>编程开发>Ruby>

扩展Ruby

来源: 作者: 时间:2007-10-30 Tag: 点击:
 
原文如下:
 

这个例子来自《Programming Ruby》(第二版)的第21章《Extending Ruby》,实现的功能类似于下面这段Ruby代码:

class MyTest
  def initialize
    @arr = Array.new
  end
  def add(obj)
    @arr.push(obj)
  end
end

C实现如下:
#include "ruby.h"

static int id_push;

static VALUE t_init(VALUE self)
{
  VALUE arr;
  arr = rb_ary_new();
  rb_iv_set(self, "@arr", arr);
  return self;
}

static VALUE t_add(VALUE self, VALUE obj)
{
  VALUE arr;
  arr = rb_iv_get(self, "@arr");
  rb_funcall(arr, id_push, 1, obj);
  return arr;
}

VALUE cTest;

void Init_my_test() {
  cTest = rb_define_class("MyTest", rb_cObject);
  rb_define_method(cTest, "initialize", t_init, 0);
  rb_define_method(cTest, "add", t_add, 1);
  id_push = rb_intern("push");
}

扩展Ruby时,所有的表演都是从最后一个函数Init_my_test开始的,它是Ruby核心部分提供给C的接口。在很多设计中,我们会通过接口进行回调,这样,我们就可以代码中调用“未来”的模块。这里呈现的就是这样一个接口,通过它,我们就可以对Ruby进行扩展。它的命名规则是 Init_name。注意,这里的名字并非是类的名字,而是要生成的文件的名字,也是我们在编写程序中require的那个名字,下面还会提到。

通过前面的讲解,我们便不难理解加载这个扩展时的动作,当require出现的时候,调用Init_name这个方法,这样,这个文件中定义的内容便注册到内核中,程序的其它部分便可以使用这些内容了。多次require的时候,多次调用Init_name方法是一种奢侈,这样,会想到cache,不想了,有些远。

我常常把与程序的交互分为两种:一种是程序库,也就是我们编写的程序对其进行调用,完成特定的功能;另一种是框架,也就是我们编写的程序由它调用。通常所说的框架一般包括这两个部分。对比Ruby中的实现,这里的Init_my_test就是属于框架的部分,也就是我们编写出来由Ruby的核心部分进行调用,让这段代码有了运行的机会。再来看这个函数中的实现,从函数名我们就可以看出,这里定义了一个名为“MyTest”的类,之后又为这个类定义两个方法,它们分别是“initialize”方法,其实现为t_init,和“add”方法,其实现为t_add。通过框架和程序库的组合,我们就可以与 Ruby进行交互,既让自己的代码有了参与的机会,也可以让自己完成想做的事情。至于最后的id_push,我们可以认为它就是“push”字符串,因为在Ruby的实现中,字符串总是和一个ID一一对应。

t_init和t_add两个函数的实现很简单,但却为我们演示了很多的东西。在Ruby层次上未曾示人的this指针露出了真容(self),我们有了操作实例变量的机会(rb_iv_set/rb_iv_get),也知道了在这个层次上调用函数的方法(rb_funcall)。

在这里看到的内容,通常会分C和Ruby两个层次上的内容,比如,在Ruby层次上,我们定义给程序定义了名为“initialize”的方法,而它在C层次上的对应是t_init。如果有机会看Ruby的实现,这样的代码会有很多,基本上,引号里面的名字都属于Ruby,比如代码中出现的 "@arr",具有明显的Ruby特征。


上一篇:没有了
下一篇:没有了
最新评论共有 4 位网友发表了评论
发表评论
评论内容:不能超过250字,需审核,请自觉遵守互联网相关政策法规。
用户名: 密码:
匿名?
注册