博客荒废好长一段时间了,总感觉再不写点什么我说不定都提不起劲给VPS续费了……
mRuby已经release了1.0.0版本,虽然无论是文档还是社区建设mRuby都还有很长的一段路要走,但是对我来说尝鲜已经是足够了。
既然你会翻到这里估计我也就不用再费口舌介绍什么是mRuby了,那么下面我们就直接进入正题好了。
编译
Linux
之前在linux上编译过一次,不过说起来linux上编译起来真的有难度么?连configure都不需要直接装上bison、automake和ruby然后在代码根目录直接make就好。
Windows
曾经试过在Windows上编译一个Ruby出来,不过因为种种原因作罢了,这次编译mRuby也算是补回这个遗憾。
- 去GNUWIN32下载bison、make以及mingw32
- 安装一个版本的ruby
- 在环境变量中添加bison、make、gcc(mingw32提供)所在的路径,具体方法自己google
- 在mRuby源码的根目录下make
- Done
编译好了以后在build/host/bin/下提供了mruby、mirb和mrbc,分别对应ruby、irb以及rbc
mruby和mirb不用多说,mrbc好像是编译rb程序用的,我没用过就不多说了。
嵌入
正如mRuby名字所揭示的那样,她是一门专门用于嵌入(Embedded)的轻量级语言,类似于Lua。既然如此我们就首先来测试一下将Ruby嵌入到C程序中去。
#include<stdio.h>
#include<stdlib.h>
#include<mruby.h>
#include<mruby/compile.h>
int main(){
char ruby_code[] = "puts ‘Hello World’";
mrb_state *mrb = mrb_open();
mrb_load_string(mrb,ruby_code);
return 0;
}
嗯……好像还真是比Ruby简单不少……顺带一提之前我曾经试着在windows下将Ruby嵌入到C程序中去,可是使用RubyInstaller提供的名字叫1.9.1的lib总是会在运行的时候报段错误……(Ruby版本1.9.3),当然在Linux下没有任何问题就是了。
顺带一提,请自行设置include文件的搜索位置,以及需要链接的lib(libmruby.a,位于build\host\lib下),在此仅提供Code::Blocks自动生成的编译命令
mingw32-gcc.exe -Wall -g -IF:\mruby\mruby-1.0.0\include -c F:\mruby\main.c -o obj\Debug\main.o
mingw32-g++.exe -LF:\mruby\mruby-1.0.0\build\host\lib -o bin\Debug\mruby.exe obj\Debug\main.o -lmingw32 F:\mruby\mruby-1.0.0\build\host\lib\libmruby.a
好像同时指定了lib的搜索位置以及lib文件的绝对路径,嘛,不要在意
扩充
在C程序里单独嵌入一个Ruby命令没什么意思,我们来为其扩充一些我们自己定义的内容。
#include<stdio.h>
#include<stdlib.h>
#include<mruby.h>
#include<mruby/compile.h>
mrb_value foo_add(mrb_state\* mrb,mrb_value self){
int a,b;
mrb_get_args(mrb,"ii",&a,&b);
return mrb_fixnum_value(a+b);
}
int main(){
char ruby_code[] = "p Foo.new.add(1,2)";
mrb_state \*mrb = mrb_open();
struct RClass\* foo_class;
foo_class = mrb_define_class(mrb,"Foo",mrb->object_class);
mrb_define_method(mrb,foo_class,"add",foo_add,MRB_ARGS_REQ(2));
mrb_load_string(mrb,ruby_code);
return 0;
}
这样,我们就添加了一个名为Foo的类以及其一个实例方法add
参考代码,我们可以了解一下mrb定义方法的一般方式,foo_add是作为方法的具体实现函数,其返回类型以及参数类型都是固定的。而ruby传给该方法的参数则需要通过mrb_get_args(mrb,args...)
获取。其中args表示各个参数的类型。具体参考此表:
string mruby type C type note
o: Object [mrb_value]
C: class/module [mrb_value]
S: String [mrb_value]
A: Array [mrb_value]
H: Hash [mrb_value]
s: String [char\*,int] Receive two arguments.
z: String [char\*] NUL terminated string.
a: Array [mrb_value\*,mrb_int] Receive two arguments.
f: Float [mrb_float]
i: Integer [mrb_int]
b: Boolean [mrb_bool]
n: Symbol [mrb_sym]
&: Block [mrb_value]
\*: rest argument [mrb_value\*,int] Receive the rest of the arguments as an array.
|: optional Next argument of '|' and later are optional.
\*来源于src/class.c内部的注释
需要指出的是,所有的ruby变量都是mrb_value类型, foo_add
函数的self参数指代instance自己。而对于mrb_define_class_method
定义的类方法等self指代的是该类(Class类的instance)本身。
至于mrb_define_class
以及mrb_define_method
及其参数意义就不用我说了吧?稍微懂点英语就可以看懂了。
还有ruby中每个方法必须要有一个返回值,所以即使你没有返回值也要return mrb_nil_value();
,而且函数必须返回mrb_value。(我一开始就直接想都没想用了void作为返回类型……)
很明显,这种方法只适合少量的零散的定义,而对于大量的,更加结构化的工程这种方法也有其局限性,而我们又常常会想要在Ruby类中储存一些持久化数据,但这又会牵扯到Ruby的垃圾回收(GC)工作机理,这一切我们会在后面讲解。
下一讲:
《mRuby:mrbgems以及在Ruby对象中储存struct》