• linkedu视频
  • 平面设计
  • 电脑入门
  • 操作系统
  • 办公应用
  • 电脑硬件
  • 动画设计
  • 3D设计
  • 网页设计
  • CAD设计
  • 影音处理
  • 数据库
  • 程序设计
  • 认证考试
  • 信息管理
  • 信息安全
菜单
linkedu.com
  • 网页制作
  • 数据库
  • 程序设计
  • 操作系统
  • CMS教程
  • 游戏攻略
  • 脚本语言
  • 平面设计
  • 软件教程
  • 网络安全
  • 电脑知识
  • 服务器
  • 视频教程
  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell
您的位置:首页 > 脚本语言 >ruby > 使用C++来编写Ruby程序扩展的教程

使用C++来编写Ruby程序扩展的教程

作者:goldensun 字体:[增加 减小] 来源:互联网

goldensun 通过本文主要向大家介绍了ruby程序,ruby小程序,ruby,ruby碧玺,ruby woo口红等相关知识,希望对您有所帮助,也希望大家支持linkedu.com www.linkedu.com

Ruby 最酷的功能之一就是使用 C/C++ 定义的应用程序编程接口 (API) 扩展它。Ruby 提供了 C 头文件 ruby.h,它随附提供了许多功能,可使用这些功能创建 Ruby 类、模块和更多内容。除了头文件,Ruby 还提供了其他几个高层抽象来扩展基于本地 ruby.h 构建的 Ruby,本文要介绍的是 Ruby Interface for C++ Extensions 或 Rice。
创建 Ruby 扩展

在进行任何 Ruby 的 C API 或 Rice 扩展前,我想明确地介绍一下创建扩展的标准过程:

  •     您具有一个或多个 C/C++ 源代码,可使用它们构建共享库。
  •     如果您使用 Rice 创建扩展,则需要将代码链接到 libruby.a 和 librice.a。
  •     将共享库复制到同一文件夹,并将该文件夹作为 RUBYLIB 环境变量的一部分。
  •     在 Interactive Ruby (irb) prompt/ruby 脚本中使用常见的基于 require 的加载。如果共享库名为 rubytest.so,只需键入 require 'rubytest' 即可加载共享库。

假设头文件 ruby.h 位于 /usr/lib/ruby/1.8/include 中,Rice 头文件位于 /usr/local/include/rice/include 中,并且扩展代码位于文件 rubytest.cpp 中。 清单 1 显示了如何编译和加载代码。
清单 1. 编译和加载 Ruby 扩展

bash# g++ -c rubytest.cpp –g –Wall -I/usr/lib/ruby/1.8/include \
  -I/usr/local/include/rice/include
bash# g++ -shared –o rubytest.so rubytest.o -L/usr/lib/ruby/1.8/lib \
  -L/usr/local/lib/rice/lib -lruby –lrice –ldl -lpthread
bash# cp rubytest.so /opt/test
bash# export RUBYLIB=$RUBYLIB:/opt/test
bash# irb
irb> require 'rubytest'
=> true

</div>

Hello World 程序

现在,您已经准备好使用 Rice 创建自己的首个 Hello World 程序。您使用名为 Test 的 Rice API 和名为 hello 的方法创建了一个类,用它来显示字符串 "Hello, World!"。当 Ruby 解释器加载扩展时,会调用函数 Init_<shared library name>。对于 清单 1 的 rubytest 扩展,此调用意味着 rubytest.cpp 已定义了函数 Init_rubytest。Rice 支持您使用 API define_class 创建自己的类。清单 2 显示了相关代码。
清单 2. 使用 Rice API 创建类

#include "rice/Class.hpp"
extern "C"
void Init_rubytest( ) { 
 Class tmp_ = define_class("Test");
}

</div>

当您在 irb 中编译和加载清单 2 的代码时,应得到 清单 3 所示的输出。
清单 3. 测试使用 Rice 创建的类

irb> require ‘rubytest'
=> true
irb> a = Test.new
=> #<Test:0x1084a3928>
irb> a.methods
=> ["inspect", "tap", "clone", "public_methods", "__send__", 
   "instance_variable_defined?", "equal?", "freeze", …]

</div>

注意,有几个预定义的类方法可供使用,比如 inspect。出现这种情况是因为,定义的 Test 类隐式地衍生自 Object 类(每个 Ruby 类都衍生自 Object;实际上,Ruby 中的所有内容(包括数字)都是基类为 Object 的对象)。

现在,为 Test 类添加一个方法。清单 4 显示了相关代码。
清单 4. 为 Test 类添加方法

void hello() {
  std::cout << "Hello World!";
}
extern "C"
 void Init_rubytest() {
   Class test_ = define_class("Test")
     .define_method("hello", &hello);
}

</div>

清单 4 使用 define_method API 为 Test 类添加方法。注意,define_class 是返回一个类型为 Class 的对象的函数;define_method 是 Module_Impl 类的成员函数,该类是 Class 的基类。下面是 Ruby 测试,验证所有内容是否都运行良好:

irb> require ‘rubytest'
=> true
irb> Test.new.hello
Hello, World!
=> nil

</div>

将参数从 Ruby 传递到 C/C++ 代码

现在,Hello World 程序已正常运行,尝试将参数从 Ruby 传递到 hello 函数,并让函数显示与标准输出 (sdtout) 相同的输出。最简单的方法是为 hello 函数添加一个字符串参数:

void hello(std::string args) {
  std::cout << args << std::endl;
}
extern "C"
 void Init_rubytest() {
   Class test_ = define_class("Test")
     .define_method("hello", &hello);
}

</div>

在 Ruby 环境中,以下是调用 hello 函数的方式:

irb> a = Test.new
<Test:0x0145e42112>
irb> a.hello "Hello World in Ruby"
Hello World in Ruby
=> nil

</div>

使用 Rice 最出色的一点是,无需进行任何特殊操作将 Ruby 字符串转换为 std::string。

现在,尝试在 hello 函数中使用字符串数组,然后检查如何将信息从 Ruby 传递到 C++ 代码。最简单的方式是使用 Rice 提供的 Array 数据类型。在头文件 rice/Array.hpp 中定义 Rice::Array,使用 Rice::Array 的方式类似于使用 Standard Template Library (STL) 容器。还要将常见的 STL 样式迭代器等内容定义为 Array 接口的一部分。清单 5 显示了 count 例程,该例程使用 Rice Array 作为参数。
清单 5. 显示 Ruby 数组

#include "rice/Array.hpp"

void Array_Print (Array a)  {
   Array::iterator aI = a.begin();
   Array::iterator aE = a.end();
   while (aI != aE) {
    std::cout << "Array has " << *aI << std::endl;
    ++aI;
   }
 }

</div>

现在,下面是此解决方案的魅力所在:假设您拥有 std::vector<std::string> 作为 Array_Print 参数。下面是 Ruby 抛出的错误:

>> t = Test.new
=> #<Test:0x100494688>
>> t.Array_Print ["g", "ggh1", "hh1"]
ArgumentError: Unable to convert Array to std::vector<std::string, 
  std::allocator<std::string> >
 from (irb):3:in `hello'
 from (irb):3

</div>

但是,使用此处显示的 Array_Print 例程,Rice 负责执行从 Ruby 数组到 C++ Array 类型的转换。下面是样例输出:

>> t = Test.new
=> #<Test:0x100494688>
>> t.Array_Print ["hello", "world", "ruby"]
Array has hello
Array has world
Array has ruby
=> nil

</div>

现在,尝试相反的过程,将 C++ 的数组传递到 Ruby 环境。请注意,在 Ruby 中,数组元素不一定是同一类型的。清单 6 显示了相关代码。
清单 6. 将数组从 C++ 传递到 Ruby

#include "rice/String.hpp"
#include "rice/Array.hpp"
using namespace rice; 

Array return_array (Array a) {
   Array tmp_;
   tmp_.push(1);
   tmp_.push(2.3);
   tmp_.push(String("hello"));
   return tmp_;
 }

</div>

清单 6 明确显示了您可以在 C++ 中创建具有不同类型的 Ruby 数组。下面是 Ruby 中的测试代码:

>> x = t.return_array
=> [1, 2.3, "hello"]
>> x[0].class
=> Fixnum
>> x[1].class
=> Float
>> x[2].class
=> String

</div>

如果我没有更改 C++ 参数列表的灵活性,会怎么样?

更常见的情况是具有这样的灵活性,您将发现 Ruby 接口旨在将数据转换为 C++ 函数,该函数的签名无法更改。例如,考虑需要将字符串数组从 Ruby 传递到 C++ 的情形。C++ 函数签名如下所示:

void print_array(std::vector<std::string> args)

</div>

实际上,您在这里寻找的是某种 from_ruby 函数,Ruby 数组使用该函数并将它转换为 std::vector<std::string>。这正是 Rice 提供的内容,具有下列签名的 from_ruby 函数:

template <typename T>
T from_ruby(Object );

</div>

对于需要转换为 C++ 类型的每种 Ruby 数据类型,需要针对模板详细说明 from_ruby 例程。例如,如果将 Ruby 数组传递到上述处理函数,清单 7 显示了应如何定义 from_ruby 函数。
清单 7. 将 ruby 数组转换为 std::vector<std::string>

template<>
std::vector<std::string> from_ruby< std::vector<std::string> > (Object o)  {
  Array a(o);
  std::vector<std::string> v;
  for(Array::iterator aI = a.begin(); aI != a.end(); ++aI)
    v.push_back(((String)*aI).str());
  


 

您可能想查找下面的文章:

  • ruby开发的交互式程序例子
  • ruby 程序的执行顺序
  • Ruby程序中正则表达式的基本使用教程
  • 实例解析Ruby程序中调用REXML来解析XML格式数据的用法
  • Ruby程序中发送基于HTTP协议的请求的简单示例
  • Ruby程序中创建和解析XML文件的方法
  • ruby的程序结构介绍
  • 使用Ruby程序实现web信息抓取的教程
  • 使用C++来编写Ruby程序扩展的教程
  • 使用Ruby编写发送邮件的程序的简单教程

相关文章

  • 举例理解Ruby on Rails的页面缓存机制
  • 你应该知道的Ruby代码风格
  • 简单谈谈Ruby的private和protected
  • Ruby中的return、break、next详解
  • 使用Ruby on Rails快速开发web应用的教程实例
  • 使用ruby部署工具mina快速部署nodejs应用教程
  • 在Ruby on Rails中使用AJAX的教程
  • 在Ruby on Rails中优化ActiveRecord的方法
  • Ruby编程中关于中断和返回的用法教程
  • 收集的多个ruby遍历文件夹代码实例

文章分类

  • vbs
  • DOS/BAT
  • hta/htc
  • python
  • perl
  • VBA
  • ColdFusion
  • ruby
  • PowerShell
  • Lua
  • Golang
  • linux shell

最近更新的内容

    • Ruby中嵌套对象转换成json的方法
    • Ruby进行文件信息输出实例代码
    • 冒泡排序算法及Ruby版的简单实现
    • Ruby中Hash的11个问题解答
    • Ruby的基础语法入门学习教程
    • Ruby中proc和lambda的两个区别
    • Ruby on Rails框架程序连接MongoDB的教程
    • Ruby定义私有方法(private)的两种办法
    • 使用Ruby on Rails快速开发web应用的教程实例
    • Ruby中使用Block、Proc、lambda实现闭包

关于我们 - 联系我们 - 免责声明 - 网站地图

©2020-2025 All Rights Reserved. linkedu.com 版权所有