mRuby:mrbgems以及在Ruby对象中储存struct

Written by zumikua Updated at 2015-01-30 16:25:47 UTC

mRuby拥有自己的包管理系统,mrbgems。与gem不同的是,mrbgems静态的,是在编译mruby时发挥作用的,而rubygems则是在ruby编译好以后可以进行动态的扩展。

mrbgems

首先我们来看一下官方给出的样例mrbgem

#include <mruby.h>
#include <stdio.h>

static mrb\_value
mrb\_c\_method(mrb\_state \*mrb, mrb\_value self)
{
  puts("A C Extension");
  return self;
}

void
mrb\_c\_extension\_example\_gem\_init(mrb\_state\* mrb) {
  struct RClass \*class\_cextension = mrb\_define\_module(mrb, "CExtension");
  mrb\_define\_class\_method(mrb, class\_cextension, "c\_method", mrb\_c\_method, MRB\_ARGS\_NONE());
}

void
mrb\_c\_extension\_example\_gem\_final(mrb\_state\* mrb) {
  // finalizer
}

来源于examples\mrbgems\cextensionexample\src\example.c

mrbgem要求你定义mrb\_YOURGEMNAME\_gem\_init(mrb\_state\* mrb)函数以及mrb\_YOURGEMNAME\_gem\_final(mrb\_state\* mrb)函数,分别会在加载与结束的时候被调用。当然即使没有什么内容一个空函数也是不能少的。其中函数的内容就和我们在上一节中所使用的差不多。

下面,我们来看看mrbgem.rake

MRuby::Gem::Specification.new('c\_extension\_example') do |spec|
  spec.license = 'MIT'
  spec.author  = 'mruby developers'
end

其中cextensionexample是你的gem的名字。license是许可证,author是作者,感觉说的好像有点多……具体自己参考这里吧,其对gem的路径格式也有定义。

创建完以后,在mruby的根目录下的build\_config.rb中加一行conf.gem 'mrbgems/mruby-c-extension'当然要记得指向你自己的gem地址,我就不多说了。

最后make一下,编译过程中没错误的话就可以用了。在将其嵌入到程序之前,你可以使用mirb先测试一下。

使用C struct

有时候我们可能会需要使用Ruby变量来储存一些数据,比如C的struct。在一个Ruby对象中储存struct有两种方法,一种是用对象本身包装成一个C Struct。我个人认为这个方法更加麻烦一点,而且可扩展性也不算太高……不能让一个对象拥有两个struct之类……另一种方法是为该对象定义一个实例变量(instance variable),用这个实例变量包装struct。

用实例本身包装

#include "mruby.h"
#include "mruby/compile.h"
#include "mruby/data.h"
#include "mruby/class.h"
#include "mruby/variable.h"
#include <stdlib.h>
#include <stdio.h>
struct Foo {
  int a;
};
static void foo\_free(mrb\_state\* mrb,void\* p){
  free(p);
  printf("Freed\n");
}
static struct mrb\_data\_type foo\_data\_type = {
  "foo", foo\_free
};
mrb\_value new\_foo(mrb\_state\* mrb,mrb\_value self){
  struct Foo\* f;
  f = (struct Foo\*)DATA\_PTR(self);
  if(f){
    mrb\_free(mrb,f);
  }
  DATA\_TYPE(self) = &foo\_data\_type;
  DATA\_PTR(self) = NULL;
  f  = (struct Foo\*)mrb\_malloc(mrb,sizeof(struct Foo));
  f->a = 0;
  DATA\_PTR(self) = f;
  return self;
}
mrb\_value set\_foo\_a(mrb\_state\* mrb,mrb\_value self){
  int v=0;
  mrb\_get\_args(mrb,"i",&v);
  struct Foo\* f;
  f = DATA\_GET\_PTR(mrb,self,&foo\_data\_type,struct Foo);
  f->a = v;
  return mrb\_nil\_value();
}
mrb\_value get\_foo\_a(mrb\_state\* mrb,mrb\_value self){
  struct Foo\* f;
  f = DATA\_GET\_PTR(mrb,self,&foo\_data\_type,struct Foo);
  return mrb\_fixnum\_value(f->a);
}

void mrb\_mruby\_c\_extension\_gem\_init(mrb\_state\* mrb) {
  struct RClass\* module\_test = mrb\_define\_module(mrb,"Test");
  struct RClass\* class\_foo = mrb\_define\_class\_under(mrb,module\_test,"Foo",mrb->object\_class);
  MRB\_SET\_INSTANCE\_TT(class\_foo, MRB\_TT\_DATA);
  mrb\_define\_method(mrb,class\_foo,"initialize",new\_foo,MRB\_ARGS\_NONE());
  mrb\_define\_method(mrb,class\_foo,"a",get\_foo\_a,MRB\_ARGS\_NONE());
  mrb\_define\_method(mrb,class\_foo,"a=",set\_foo\_a,MRB\_ARGS\_REQ(1));
}
void mrb\_mruby\_c\_extension\_gem\_final(mrb\_state\* mrb) {
  /\*Do nothing\*/
}

这部分的代码主要参考mruby-time这个gem的代码。首先来看一下new\_foo

首先应该指出的一点就是这里的initialize是一个实例方法,所以说传给new\_fooselfFoo.new生成的是实例自身而不是Foo这个Class类的实例常量

Ruby中内建的类型有一种DATA原型,该原型有一个DATA指针用来储存数据内容,所以说我们可以通过使用该DATA指针来储存struct。不过在此之前,先通过MRB\_SET\_INSTANCE\_TT(class\_foo, MRB\_TT\_DATA)将Foo类的所有实例设为DATA原型。

然后我们就可以通过DATA\_PTR(self)获取实例的DATA指针。注意:DATA\_PTR(self)宏实际上等于((struct RData \*)mrb\_ptr(self))->data,并不是一个字面值常量,所以对其进行赋值是可行的。

在取得DATA指针以后要对其进行释放,然后再将其指向自己创建的新内存中,这部分的代码全部都在new\_foo函数中。关于mrb\_free,目前从源码来看其与free没有区别,但是不保证以后会有什么修改,所以我个人还是倾向Ruby的东西用mrb\_free,自己定义的东西用free。

关于mrb\_data\_type,在这里Matz本人阐述了其作用,主要是Debug,以及定义了一个Data要如何被释放掉。正如代码所示,该struct由一段任意的字符串作为名字以及一个函数指针作为释放时使用的函数组成。

当然,为了让mRuby了解到该实例的类型,也要通过DATA\_TYPE(self) = &foo\_data\_type指定一下实例的类型。

编译后,在mirb下使用如下代码测试

> s = Test::Foo.new
 => #<Test::Foo:0x6d3d30>
> s.a
 => 0
> s.a = 10
 => 10
> s.a
 => 10
> s = 20
 => 20
> GC.start
Freed
 => nil

用实例变量包装

#include "mruby.h"
#include "mruby/compile.h"
#include "mruby/data.h"
#include "mruby/class.h"
#include "mruby/variable.h"
#include <stdlib.h>
#include <stdio.h>
struct Foo {
  int a;
};
static void foo\_free(mrb\_state\* mrb,void\* p){
  free(p);
  printf("Freed\n");
}
static struct mrb\_data\_type foo\_data\_type = {
  "foo", foo\_free
};
mrb\_value new\_foo(mrb\_state\* mrb,mrb\_value self){
  struct Foo\* f;
  f  = (struct Foo\*)mrb\_malloc(mrb,sizeof(struct Foo));
  f->a = 0;
  mrb\_iv\_set(mrb,self,mrb\_intern\_cstr(mrb,"@data"),
  mrb\_obj\_value(Data\_Wrap\_Struct(mrb,mrb->object\_class,&foo\_data\_type,(void \*)f)));
  return self;
}
mrb\_value set\_foo\_a(mrb\_state\* mrb,mrb\_value self){
  int v=0;
  mrb\_get\_args(mrb,"i",&v);
  struct Foo\* f;
  Data\_Get\_Struct(mrb,mrb\_iv\_get(mrb,self,mrb\_intern\_cstr(mrb,"@data")),&foo\_data\_type,f);
  f = (struct Foo \*)f;
  f->a = v;
  return mrb\_nil\_value();
}
mrb\_value get\_foo\_a(mrb\_state\* mrb,mrb\_value self){
  struct Foo\* f;
  Data\_Get\_Struct(mrb,mrb\_iv\_get(mrb,self,mrb\_intern\_cstr(mrb,"@data")),&foo\_data\_type,f);
  f = (struct Foo \*)f;
  return mrb\_fixnum\_value(f->a);
}

void mrb\_mruby\_c\_extension\_gem\_init(mrb\_state\* mrb) {
  struct RClass\* module\_test = mrb\_define\_module(mrb,"Test");
  struct RClass\* class\_foo = mrb\_define\_class\_under(mrb,module\_test,"Foo",mrb->object\_class);
  mrb\_define\_method(mrb,class\_foo,"initialize",new\_foo,MRB\_ARGS\_NONE());
  mrb\_define\_method(mrb,class\_foo,"a",get\_foo\_a,MRB\_ARGS\_NONE());
  mrb\_define\_method(mrb,class\_foo,"a=",set\_foo\_a,MRB\_ARGS\_REQ(1));
}
void mrb\_mruby\_c\_extension\_gem\_final(mrb\_state\* mrb) {
  /\*Do nothing\*/
}

在这里,我们定义了一个实例变量@data,用其存储struct数据。该变量通过Data\_Wrap\_Struct(mrb,mrb->object\_class,&foo\_data\_type,(void \*)f)中的mrb->object\_class被指定为了Object的实例。

我们使用了两个宏,Data\_Wrap\_Struct以及Data\_Get\_Struct,前者返回一个指定类的Data原型的实例,另一个则是从指定的对象中取得数据指针,它与DATAGETPTR是一模一样的,而与DATA\_PTR相比多了一个对类型的检测。

__Data\_Get\_Struct已经废弃,请使用DATA\_GET\_PTR替代__

mrb\_intern\_cstr会返回一个可供Ruby使用的标识符,其参数应该不用我多说。

mrb\_iv\_setmrb\_iv\_get的声明如下:

void mrb\_vm\_iv\_set(mrb\_state\*, mrb\_sym, mrb\_value);

mrb\_value mrb\_iv\_get(mrb\_state \*mrb, mrb\_value obj, mrb\_sym sym);

应该比较容易理解吧?

其他好像也没什么需要具体讲解的内容了,直接编译试试效果吧。

> s = Test::Foo.new
 => #<Test::Foo:0x903d30 @data=#<Object:0x903d18>>
> s.instance\_variables
 => [:@data]
> s.instance\_eval{@data}.class
 => Object
> s.instance\_eval{@data}.methods - Object.methods
 => []
> s.a = 10
 => 10
> s
 => #<Test::Foo:0x903d30 @data=#<Object:0x903d18>>
> s.a
 => 10
> s.instance\_eval{@data = 0}
 => 0
> s.a
(mirb):1: wrong argument type Fixnum (expected Data) (TypeError)
> s.a=102
(mirb):1: wrong argument type Fixnum (expected Data) (TypeError)
> s = 3
 => 3
> GC.start
Freed
 => nil

可以看出GC的确在好好工作。顺便如果不想让@data被修改的话可以把@data命名为data,这样它就不会被访问到了。

总结

这两种方法虽然实现方式不同,但是原理上是差不多的,都是通过DATA原型提供的DATA指针来存储数据,将struct用Ruby对象包装起来使用。不同的只是包装用的Ruby对象是什么、属于哪个类的实例而已而已。顺带一提,如果你想的话,你也可以把Data\_Wrap\_Struct中的mrb->object\_class改成其他的类,甚至是Foo类自身都可以。

997ce480778bfeb83280b09d594a73c3
LelandSew says:
301 Moved Permanently <a href=https://www.viagrapascherfr.com/>Show more...</a>
E75827ee682cc46491fde8921e990ada
Caseyjoync says:
<a href=https://www.viagrapascherfr.com/>Show more>>></a>
162ac220a7ba66ab378417384101a99e
AngeloPhymn says:
Do you feel like you have tried everything possible in order to lose weight? You are not alone--many people have the same problem. The following article is designed to give you tips that you may not have even known existed. By following these tips, you will reach your weight loss goal in no time.
E75827ee682cc46491fde8921e990ada
Caseyjoync says:
Some people, especially those running on busy daily schedules tend to use the pills to help maintain weight since they can not afford to follow all the diet programs. This is not advised. It is recommended that one seek advice from a professional in this field before using the pills. This can save one from many dangers associated with the misuse. The diet pills should always be taken whole. Some people tend to divide the pills to serve a longer period of time. This is not advised and can lead to ineffectiveness. If it is required that one takes a complete tablet, it means that a certain amount of the ingredients are required to achieve the desired goal. It is also recommended that one does not crush the pill and dissolve it in beverages. Chemicals found in beverages have the potential of neutralizing the desired nutrients in the pill thereby leading to ineffectiveness. The best way to take the tablets is swallowing them whole with a glass of water. The diet pills speed up the metabolic processes. This is the key factor that leads to the burning of all the fats in the body. This means that one passes out lots of urine, which subsequently leads to dehydration. It is imperative that the user take lots of water round the clock. This will help curb dehydration, which can lead to health problems. In addition to that, water offers the required medium for the function of the nutrients and elimination of the fats. When buying the review of diet pills, it is imperative that one gets the most recommended dose. People tend to compromise the quality and effectiveness of the tablets due to the variation in cost. The low priced pills depict poor quality, which means their effectiveness is not reliable. Some have also been found to cause health problems. The dose should also be taken as recommended. Over dose will not speed up the process but rather lead to complication. This will increase risk of side effects. If the taking of the pill is forgotten, do not take more to compensate for the lost time. The diet plan enclosed with the diet pills has also to be followed. According to the requirements, the termination of the diet must be done even with no results. This means your body is irresponsive.
B72b0a2c6f13f93575cff759359aa3ec
Felixtub says:
Writing a medical thesis or dissertation is a task done by almost all postgraduate and master's medical students. Dissertation is derived from the Latin word disserto which means discuss. It is essential to write successful medical papers such as medicine essays and medical thesis papers. There are several reasons as to why students write medicine essays. One of the reasons is to promote enhancement of critical judgment, research skills as well as analytical skills. Moreover, medicine essay writing produce students with the ability to 4evaluate and analyze data critically. The initial step for writing medicine essays is to choose a topic. A writer should have at least three topics to choose from. The topic has to be interesting, feasible and relevant. It is essential to write quality medicine essay. Hence, students need to have analytical skills and perfect writing skills. The writing skills will enable them write outstanding essay papers that can be highly regarded by instructors and professors. Teachers often require a lot and expect a lot from their students in terms of medicine essay writing. for this reason, students find essay writing to be an extremely difficult task and hence resort to buying custom medicine essays. A custom medicine essay has to be written by professional writers who are qualified in the field of nursing. Moreover, the custom medicine essay has to be original and plagiarism free. This means that it has to be written from scratch by experts with many years experience. The many years experience should enable a writer to write any form of medical paper including medical thesis, medicine essay and even medicine research paper. Moreover, experience will enable a writer to write a medicine essay that can guarantee academic success. Students get custom medicine essays from custom writing company. It is essential to choose the best company so that one can get the best custom medicine essay. The best and the most reliable medicine essay writing company should have some unique characteristics such as affordability and the ability to provide original and superior quality medicine essays. The other quality is that the company has to hire expert writers who can write quality medicine essays and other types of medical papers. The essays should not only be quality but also plagiarism free and free of grammatical and spelling mistakes. A custom medicine essay has a similar structure to any other academic essay assignment. It has an introduction that introduces the topic and tells the reader what the essay is all about. The second section is the body that has many paragraphs supporting the main topic. Finally there is the conclusion that briefly summarizes what has been discussed in the body section of the essay. Students should choose reliable writing companies so that they can get quality custom papers on several fields such as technology, sociology and law in addition to medicine field. Our custom writing company is the best company that all clients should rely on when in need of any given type of medicine paper. We provide quality papers that not only plagiarism free but also original. Moreover, our custom papers are affordable and able to guarantee academic excellence at all times. All our medical papers are reliable and sure of satisfying clients at all times.  
6552896a6bfc3ea828258888daaea8fa
RobertAlbus says:
Doctor Who is now considered a British Institute and has come a long way since it first aired on November 23rd 1963. The very first show saw the Doctor travel 100,00 years into the past to help some dim cavemen discover light. After 26 seasons and seven Doctors later the series came off our screens in 1989 much to the disappointment of the huge devoted fanbase. In 1996 an attempt was made to revive Doctor Who but it wasnt until June 2005 when it came back with a vengeance with Christopher Eccleston as the ninth Doctor that put the series back on the map as it were. It then went on for 5 years with David Tenant portraying the Doctor until 2010 when Matt Smith took over the role. Today it is still a great family show and has attracted many new fans. <a href=https://www.cialissansordonnancefr24.com/prix-du-cialis-20-en-pharmacie/>https://www.cialissansordonnancefr24.com/prix-du-cialis-20-en-pharmacie/</a>
Ef6566f02e5af85bbfa35ed114eff8fe
Jessiedaync says:
A Biological Masterpiece, But Subject to Many Ills The human foot is a biological masterpiece. Its strong, flexible, and functional design enables it to do its job well and without complaint—if you take care of it and don't take it for granted. healthThe foot can be compared to a finely tuned race car, or a space shuttle, vehicles whose function dictates their design and structure. And like them, the human foot is complex, containing within its relatively small size 26 bones (the two feet contain a quarter of all the bones in the body), 33 joints, and a network of more than 100 tendons, muscles, and ligaments, to say nothing of blood vessels and nerves. <a href=https://www.cialissansordonnancefr24.com/achat-cialis-pharmacie/>https://www.cialissansordonnancefr24.com/achat-cialis-pharmacie/</a>
Fe422208a5518f621a00f1a1adeda70f
Thomasitels says:
ome people, especially those running on busy daily schedules tend to use the pills to help maintain weight since they can not afford to follow all the diet programs. This is not advised. It is recommended that one seek advice from a professional in this field before using the pills. This can save one from many dangers associated with the misuse. The diet pills should always be taken whole. Some people tend to divide the pills to serve a longer period of time. This is not advised and can lead to ineffectiveness. If it is required that one takes a complete tablet, it means that a certain amount of the ingredients are required to achieve the desired goal. It is also recommended that one does not crush the pill and dissolve it in beverages. Chemicals found in beverages have the potential of neutralizing the desired nutrients in the pill thereby leading to ineffectiveness. The best way to take the tablets is swallowing them whole with a glass of water. <a href=https://www.cialissansordonnancefr24.com/cialis-sans-ordonnance-en-belgique/>https://www.cialissansordonnancefr24.com/cialis-sans-ordonnance-en-belgique/</a>
Main