Ruby 板


LINE

一年半前(天啊,有这麽早吗?)曾经介绍过 swig, 一个专门产生各种介於 C/C++ 与其他语言 interface 的产生器。他是利用一个自订的表示法,藉由读取该表示法, 产生出各种不同真正的 binding 程式。其中也有内建不少 STL 的 binding, 所以想用 STL 的东西并不见得需要自己写,只要叫他内部的东西出来即可。 swig 很厉害,不过他有个麻烦。虽然说 DSL 的威力强大,但是对於想要快速上手而言, 其实有时候反而会是种阻碍。另一方面,我 swig 手册翻了翻,要把 C++ port 到 ruby 很容易,但反之不亦然,要在 C++ 中使用 ruby object, 就不是那麽方便。 (虽然也许这样做是奇怪了点...) 所以後来我试了 Rice. http://rice.rubyforge.org/ rice 的官方手册也说了,rice 并不是要来取代 swig 的。swig 有他的不足,而 rice 大抵上又是模仿 boost.python 而作成的,所以两者并不同。他自己也做过不少东西 是同时使用 swig 和 rice. 不过也不能说 rice 是 ruby 版的 boost.python. 因为他的目的也不是完全模仿 boost.python. anyway, 之所以会想试用,是出自於找不太到良好的 C++ yaml parser. 我有看到两个 C 版本的实作,但是真不好意思啊,个人实在不太喜欢纯 C 的东西...。所以想说如果 可以把 ruby 的 yaml 搬过来就太好了。以下就是测试结果: > sudo gem install rice 理论上这样安装是最方便的。要在 C++ 里执行 ruby, 一样会需要 ruby.h. 一般来说,他会在 lib/ruby/1.8/your_architecture/ 里面。 在我的电脑上,他是:/opt/local/lib/ruby/1.8/i686-darwin9.1.0/ 而 rice 呢,则是在 lib/ruby/gems/1.8/gems/rice-x.y.z/, librice.a 则是在 lib/ruby/gems/1.8/gems/rice-x.y.z/rice/ 下。 所以在我的电脑里,g++ options 是这样下: -I/opt/local/lib/ruby/1.8/i686-darwin9.1.0/ \ -I/opt/local/lib/ruby/gems/1.8/gems/rice-1.0.1/ \ -L/opt/local/lib/ruby/gems/1.8/gems/rice-1.0.1/rice/ \ -lrice -lruby -std=c++98 -Wall -w 主程式大概是长这样: int main(){ using Rice::Hash; using Rice::protect; ruby_init(); // 使用 ruby 前一定要呼叫 // 设定 load path, 否则 load path 会是 [] rb_eval_string("$LOAD_PATH << '/opt/local/lib/ruby/1.8'"); rb_eval_string("$LOAD_PATH << '/opt/local/lib/ruby/1.8/i686-darwin9.1.0'"); // require yaml 进来。当然也可以用上面的方式 require. 不过之所以会这样写, // 是因为我不知道 load path 要怎麽直接从 rb_ function 中设定? // 否则我是觉得能用 rb_ 去跑尽量用,evil eval 不是叫假的... rb_require("yaml"); // protect 我猜是把所有的错误都转成 rice 本身的 exception. // Hash, 则是 ruby 的 hash 在 C++ 里的 wrapper, // 所以我是把 YAML 的读取结果存入这份 C++ Hash 中。 Hash h(protect(rb_eval_string, "YAML.load(File.read('database.yml'))")); // 这边,我要做的事只是展现如何使用这份 hash. Extractor e; e.extract(h); std::cout << std::endl; } 虽然我觉得 doxygen 生出来的东西常常很难阅读,不过 rice 的 doxygen 文件还算 不错,有什麽东西都很清楚。就算不够清楚,也能去直接看他的原始档。他原始档的东西 并不多,稍微翻一下,有什麽疑惑我想都可以解决。根据我 C++ 的经验,rice 这份程式 也算是写得非常漂亮的了,应该满有参考价值。 我的 extractor 是把整个 hash 都走过一次,如果不需要这麽复杂的操作,其实也可以很 单纯地这样呼叫: std::cout << static_cast<Hash>(h[String("development")])[String("adapter")]; 这样会输出: sqlite1 这样实在是有点罗唆没错,不过我想这可以靠扩充 rice 解决。他有个 from_ruby 和 to_ruby 的 template, 扩充那个东西,好像就能把很多东西从 explicit 法转成 implicit 法。不过我暂时懒得去做那麽多研究,这应该都是小问题。不过 down cast 就比较麻烦了。他有个 get method, 好像是能做一些 down cast, 但我测试都会有 runtime error, 大概是用法不对吧。有兴趣的人欢迎去研究看看要怎麽做。 extractor 我想就不解释了,就只是单纯把抓出的 yaml 再输出回 yaml. 其实那都已经差不多单纯是 C++ 的问题了。仅列出程式码与附注的一些注解: (不过我没测试过比较复杂的 yaml, 我想一定会有问题,当作业自己试着改好吧 :p) #include <ruby.h> #include <rice/Hash.hpp> #include <rice/Array.hpp> #include <iostream> using Rice::Object; using Rice::Class; using Rice::Hash; using Rice::Array; using Rice::String; // 排版算空格用的 std::string spacer(int depth){ std::string result; for(int i=0; i<depth; ++i) result += " "; return result; } class Extractor{ public: // 他 class 判断法有点麻烦,所以我先把这三个 class instance cache 起来 Extractor(): hash_class_(Hash().class_of()), array_class_(Array().class_of()), string_class_(String().class_of()) {} void extract(Object const& obj, int depth = 0) const{ if(obj.is_instance_of(hash_class_)) extract_hash(obj, depth); else if(obj.is_instance_of(array_class_)) extract_array(obj, depth); else if(obj.is_instance_of(string_class_)) std::cout << spacer(depth) << obj << "\n"; else // 这表示他是 Fixnum or Float? std::cout << spacer(depth) << obj << "\n"; } private: void extract_array(Array const& obj, int depth) const{ for(Array::const_iterator i=obj.begin(), iend=obj.end(); i!=iend; ++i) extract(*i, depth); } void extract_hash(Hash const& obj, int depth) const{ for(Hash::const_iterator i=obj.begin(), iend=obj.end(); i!=iend; ++i){ std::cout << spacer(depth) << i->key << ":"; // i->value 结果会是 ruby 上 C 的 VALUE, 所以要 cast 成 Rice::Object if(static_cast<Object>(i->value).is_instance_of(hash_class_)) std::cout << "\n", extract(i->value, depth+1); else // 单纯的值 std::cout << " ", extract(i->value, 0); } } private: Class hash_class_, array_class_, string_class_; }; -- By Gamers, For Gamers - from the past Interplay --



※ 发信站: 批踢踢实业坊(ptt.cc)
◆ From: 220.135.28.18
1F:推 linjack:推一下 02/19 22:55
2F:推 lhyang:咦?LightyRoR是你的blog吗? 02/23 23:23
3F:→ godfat:no, 只是受邀撰文。(然後我通常都会贴到很多地方) 02/23 23:43







like.gif 您可能会有兴趣的文章
icon.png[问题/行为] 猫晚上进房间会不会有憋尿问题
icon.pngRe: [闲聊] 选了错误的女孩成为魔法少女 XDDDDDDDDDD
icon.png[正妹] 瑞典 一张
icon.png[心得] EMS高领长版毛衣.墨小楼MC1002
icon.png[分享] 丹龙隔热纸GE55+33+22
icon.png[问题] 清洗洗衣机
icon.png[寻物] 窗台下的空间
icon.png[闲聊] 双极の女神1 木魔爵
icon.png[售车] 新竹 1997 march 1297cc 白色 四门
icon.png[讨论] 能从照片感受到摄影者心情吗
icon.png[狂贺] 贺贺贺贺 贺!岛村卯月!总选举NO.1
icon.png[难过] 羡慕白皮肤的女生
icon.png阅读文章
icon.png[黑特]
icon.png[问题] SBK S1安装於安全帽位置
icon.png[分享] 旧woo100绝版开箱!!
icon.pngRe: [无言] 关於小包卫生纸
icon.png[开箱] E5-2683V3 RX480Strix 快睿C1 简单测试
icon.png[心得] 苍の海贼龙 地狱 执行者16PT
icon.png[售车] 1999年Virage iO 1.8EXi
icon.png[心得] 挑战33 LV10 狮子座pt solo
icon.png[闲聊] 手把手教你不被桶之新手主购教学
icon.png[分享] Civic Type R 量产版官方照无预警流出
icon.png[售车] Golf 4 2.0 银色 自排
icon.png[出售] Graco提篮汽座(有底座)2000元诚可议
icon.png[问题] 请问补牙材质掉了还能再补吗?(台中半年内
icon.png[问题] 44th 单曲 生写竟然都给重复的啊啊!
icon.png[心得] 华南红卡/icash 核卡
icon.png[问题] 拔牙矫正这样正常吗
icon.png[赠送] 老莫高业 初业 102年版
icon.png[情报] 三大行动支付 本季掀战火
icon.png[宝宝] 博客来Amos水蜡笔5/1特价五折
icon.pngRe: [心得] 新鲜人一些面试分享
icon.png[心得] 苍の海贼龙 地狱 麒麟25PT
icon.pngRe: [闲聊] (君の名は。雷慎入) 君名二创漫画翻译
icon.pngRe: [闲聊] OGN中场影片:失踪人口局 (英文字幕)
icon.png[问题] 台湾大哥大4G讯号差
icon.png[出售] [全国]全新千寻侘草LED灯, 水草

请输入看板名称,例如:BabyMother站内搜寻

TOP