本文通过在ruby下使用SWIG封装libcurl来简要描述如何通过SWIG来扩展ruby。
关于SWIG的入门使用可参见 使用SWIG扩展ruby性能
关于SWIG:
SWIG全称为 Simplified Wrapper and Interface Generator,通过swig可以方便快捷的使用c/c++扩展php, ruby等语言以提高性能或满足其它用途。
关于libcurl:
libcurl是一个著名的http/ftp库,通过libcurl可能轻松通过http/ftp协议访问网络。
流程:

相关文件:
SWIG的封装文件 curl.i
%module curl
%{
#include <curl/curl.h>
%}
/* type definations */
typedef int CURLoption;
typedef int CURLcode;
/* import constants */
%constant int CURL_GLOBAL_ALL = CURL_GLOBAL_ALL;
%constant int CURLOPT_URL = CURLOPT_URL;
/* import functions */
int curl_global_init(long flags);
void curl_global_cleanup();
CURL* curl_easy_init();
void curl_easy_cleanup(CURL* curl);
CURLcode curl_easy_setopt(CURL* curl, CURLoption opt, int v);
CURLcode curl_easy_setopt(CURL* curl, CURLoption opt, const char* v);
CURLcode curl_easy_perform(CURL* curl);
ruby的extconf.rb文件
require 'mkmf'
%w{stdc++ curl}.each do|lib|
$libs = append_library $libs, lib
end
create_makefile 'curl'
编译build.sh:
#通过curl.i生成封装后的cpp源码
swig -c++ -ruby curl.i &&
#通过extconf.rb生成Makefile
ruby extconf.rb &&
#通过Makefile生成目标扩展
make
测式文件ruby_test.rb
#!/usr/bin/env ruby
require 'curl'
include Curl
url = ARGV[0] || 'http://www.google.com'
p curl_global_init(CURL_GLOBAL_ALL)
p curl = curl_easy_init()
p curl_easy_setopt(curl, CURLOPT_URL, url)
p curl_easy_perform(curl)
p curl_easy_cleanup(curl)
p curl_global_cleanup()
本文相关的完整源码可在github下载: http://github.com/JiangMiao/ruby_swig_curl_demo
git clone git://github.com/JiangMiao/ruby_swig_curl_demo.git
相关链接:
libcurl
SWIG
一、异常
| 名称 |
描述 |
相当于 |
| $! |
捕获的异常 |
Exception |
| $@ |
异常的backtrace |
Exception#backtrace |
例:
begin
raise "err msg"
rescue
p $! # #<RuntimeError: err msg>
p $@ #["(irb):2:in `irb_binding'", "/usr/local/lib/ruby/1.8/irb/workspace.rb:52:in `irb_binding'", ":0"]
end
二、正则
对于 m=str.match(pattern)
| 变量 |
性质 |
描述 |
相当于 |
| $& |
只读,本地 |
匹配的项 |
m[0] |
| $` |
只读,本地 |
匹配的字符串之前未匹配的部分 |
m.pre_match |
| $\’ |
只读,本地 |
匹配的字符串之后未匹配的部分 |
m.post_match |
| $+ |
只读,本地 |
最后一个匹配的项 |
m[m.size-1] |
| $1,$2 |
只读,本地 |
所指定的匹配的项 |
m[n] |
| $~ |
本地 |
匹配的结果 |
m |
例:
"start-111-222-333-444-end" =~ /(\d+)-(\d+)-(\d+)-(\d+)/
p $& #"111-222-333-444"
p $` # "start-"
p $' # "-end"
p $+ # "444"
p $1 # "111"
p $2 # "222"
p $~[3] # "333"
三、IO/String
| 描述 |
默认 |
说明 |
| $_ |
|
gets,readline最后读入的行 |
| $F |
|
$_.split 仅当选项-a为真时 |
| $/ |
“\n” |
用于gets,readline等分割符 |
| $\ |
nil |
print与IO.write的分割符 |
| $, |
nil |
Array#join的分割符 |
| $; |
nil |
String#split的分割符 |
| $. |
|
ARGF.lineno |
| $< |
|
ARGF |
| $* |
|
ARGV |
| $> |
|
$defout |
| $defout |
|
print与printf的输出变量,缺省为$stdio |
| $stdin |
|
当前标准输入 缺省 STDIN |
| $stdout |
|
当前标准输出 缺省 STDOUT |
| $stderr |
|
当前标准错误输出 缺省 STDERR |
四、进程
| 名称 |
描述 |
| $0 |
当前ruby程序名 |
| $$ |
Process.pid |
| $? |
最后执行的外部程序的返回状态 |
四、其它
| 名称 |
描述 |
| $: |
$LOAD_PATH |
| $” |
已require的module,用于避免二次载入 |
| $DEBUG |
是否为DEBUG状态, -d –debug开启则为真 |
| $FILENAME |
$<.filename |
| $SAFE |
安全等级 |
| $VERBOSE |
verbose选项是开启则为真 |
| $-O |
$/ |
| $-a |
-a选项开启则为真 |
| $-d |
$DEBUG |
| $-F |
$; |
| $-I |
$: |
| $-l |
-lis选项开启则为真 |
| $-p |
-pis选项开启则为真 |
目标:通过本文章学习并编写一个gem ‘hello’
一、认识RubyGems
1、什么是RubyGems
RubyGems是ruby下的包管理系统。最著名gem的当属Rails
2、gem的基本文件布局
| 文件名 |
类别 |
描述 |
| gemspec |
文件 |
gem的规范说明。 |
| lib |
文件夹 |
用于lib文件的存放 |
| bin |
文件夹 |
可执行文件 |
| ext |
文件夹 |
c/c++源文件 |
| tests |
文件夹 |
单元测试文件 |
3、gemspec文件规范常用项
| 名称 |
类别 |
缺省 |
描述 |
| *name |
String |
|
gem名称 |
| *version |
String |
|
版本号 |
| *date |
Time |
Time.now |
Gem创建日期 |
| *platform |
String |
Gem::Platform::Ruby |
gems所使用的平台 |
| *summary |
String |
|
gem描述 |
| *require_paths |
Array |
["lib"] |
用于require调用时的默认路径 |
| files |
Array |
|
gems所包含的文件 |
以上为关键的几个选项,其中打*号的为必须的项,若要添加作者,可执行文件等选项可参见Gem规范
3、编译
gem build gemspec文件
4、安装
gem install 生成的gem
二、编写最简gem hello
1、创建文件与文件夹
hello/hello.gemspec
hello/lib/hello.rb
2、编写 hello.gemspec
Gem::Specification.new do |s|
s.name = 'hello'
s.version = '0.1.0'
s.summary = 'hello gems'
s.files = ["lib/hello.rb"]
end
3、编写 lib/hello.rb
def hello
"HELLO"
end
4、编译
gem build hello.gemspec
5、安装
gem install hello
6、测试
require 'rubygems'
require 'hello'
puts hello
—-
输出HELLO 测试成功
三、相关链接
1、RubyGems官方网站
2、Rubyforge
2、Gem规范
3、本文的hello gem源码
Btk 基于 Ruby GTK2 的扩展,大大方便ruby下的gui。
安装:gem install btk
主页:http://btk.rubyforge.org/
Hello World:
require 'rubygems'
require 'btk'
# w will call border_width= or set_border_width with parameter 10
Btk.Window :border_width=>10 do|w|
#alias of signal_connect('delete_event')
w.sig_delete_event do
puts "delete event occurred"
false
end
#alias of signal_connect('destroy')
w.sig_destroy do
puts "destroy event occurred"
Gtk.main_quit
end
# Button will add to w automatically
w.Button "Hello World" do|btn|
btn.sig_clicked do
puts "Hello World"
end
end
w.show_all
end
Gtk.main
从rails回来,重新用起了php,起因还是由于rails render一个63k的view要多花去10ms,这个view就一个erb fragment缓存,,即由原来每个响应20ms下降到30ms,降低了足足50%,很受伤,后然尝试使用merb,但merb不太习惯,正值ruby1.9.1,Rails2.3发页,又尝试ruby1.9.1,可惜很多gems都未能完善,fcgi,mongrel都无法工作,只能用回了1.8.7。最后无奈之下用回了php。用php重写了所有代码后,一模一样的操作那个63k的页面只需10ms。
但rails给我的启发是巨大的,现在我的目录结构也仿rails, 如app,config,public,log,tmp等。我甚至写了个Rakefile用来管理文件的常用操作,使用了ruby的2个月。学到了不少。ruby我还会继续用他,作为我的刀,希望ruby越来越好,早一天让我从php又回到了ruby。
今天发现stable version已从1.8.7升至为1.9.1-p0。一会测试一下兼容性和性能的提升。
相关链接
Ruby官方网站
–2009-02-10补充–
到正式可以用至少还要1个月,许许多多gems都还未能兼容1.9.1。部份版本已出了新版本,但都还在github中。
ruby的脚步太快, 追起来有点吃力,暂时驻足观望一阵。
用c++写ruby模块提升性能效果显著一文让我初尝甜头,但未免连render都用c++也太得不尝失。自从使用了rb_yield,一切问题迎刃而解。
如代码
class Test
def foo
yield
end
end
相对应的c++代码则为
#include "ruby.h"
typedef VALUE(*RUBY_FUNC)(...);
extern "C" VALUE t_foo(VALUE self)
{
//do something by c++
rb_yield();
//do something by c++
}
VALUE cTest = rb_define_class("Test",rb_cObject);
rb_define_method(cTest,"foo",(RUBY_FUNC)t_foo,1);
非常的方便有效。
早听说debian/ubuntu的1.8.6是debug模式,比正常的慢50%,一直没在意,反正是测试服务器不缺这点时间。
前几篇日志提到的600个节点的树递归生成时间与render耗时太长,要近200ms,c++render虽然快但不实用,于是今重写了扩展对erb进行yield,但最终只能优化到70ms(3ms树生成+70ms render),最后发现即使什么都不作进行600次link_to操作也要花掉60-80ms。随抱着试试的心态升到了1.8.7
升级后发现目录也改成像freebsd的/usr/local/…的样子不太熟悉。然后安装gem又折腾了一阵。最后怀着激动的心情安装好一试,!只要20-40ms!又试了试其它页面,原本要花0-6ms的页面全都稳定得变为0-1ms。太爽了!!!
边守岁边测试,看到这满意的结果,能安心的睡个好觉了。
越来越中意ruby了
近期评论