ruby动态创建类和方法

很多人通过Class.new和define_method方法来动态创建类和方法。

怎么创建到执行时才知道类名的类呢,答案是const_set方法,将这个常量和类连接在一起,放在Object下面就可以了。定义方法自然是define_method,以下是示例代码:

 
class_name = 'YourClassName'
method_name = 'test'
Object::const_set(class_name.to_sym, Class::new do
    define_method method_name.to_sym, Proc.new { |x, y|
        puts x
        puts y
    }
end
)
Object::const_get(class_name).new.test(1, 2) 
#1
#2
# => nil
YourClassName.new.test(1, 2) 
#1
#2
# => nil

大致情况就这些,大家可以根据自身情况使用。

使用EventMachine

译自:Playing with eventmachine

最近这几周,我在工作中用了好几次 Ruby EventMachine,虽然它的 RDoc 还不错,但要是真想搞明白这玩意儿恐怕还是要花些功夫,所以我就写了这篇文章。

首先要弄明白的是,究竟什么是EventMachine,在什么场景会用到它。简而言之,EM(EventMachine)是个事件循环监听器(Event loop)。一旦你使用了EventMachine,它便随着ruby的主线程启动,然后去做他自己该做的事情。EM可以监听sockets、监听文件描述符、控制定时器等大量的事情。当你监听的事件触发时,EM会触发你的回调方法,如此一来你便可以处理这些事件,处理完之后再把事件控制权交还给EventMachine。

你也可以让EventMachine执行一大堆和你主要逻辑无关的代码,当这一大堆代码执行完的时候再让回调方法在主要逻辑连接上的任何请求上执行。

我们来用一段代码增进对它的理解:

例1.定时器:

#!/usr/bin/ruby

require 'rubygems'
require 'eventmachine'

EventMachine.run do
    EM.add_periodic_timer(1) { puts "Tick ..." }

    EM.add_timer(3) do
        puts "I waited 3 seconds"
        EM.stop_event_loop
    end
end

puts "All done."

我们来瞧一下这段简单的代码吧。在程序执行之前,需要先安装好 Eventmchine,我们可以通过rubygems来安装(gem install eventmachine),然后我们在程序里引入需要的部分(require ‘eventmachine’)。你可能会奇怪为什么我有的地方用了EventMachine,有的地方用了EM,其实他们是一样的,你可以随意对调。EM写起来比较短,不过我有时候也会用EventMachine。EventMachine#run方法用来开启主事件循环监听,在这段代码块里你可以添加自己希望的各种功能,比如某种服务,或者定时器之类。

继续阅读

ruby调用执行shell命令的方法

ruby执行shell的方法主要有:

1.Exec方法:

Kernel#exec方法通过调用指定的命令取代当前进程:

$ irb
>> exec 'echo "hello $HOSTNAME"'
hello nate.local
$

值得注意的是,exec方法用echo命令来取代了irb进程从而退出了irb。主要的缺点是,你无法从你的ruby脚本里知道这个命令是成功还是失败。

2.System方法。

Kernel#system方法操作命令同上, 但是它是运行一个子shell来避免覆盖当前进程。如果命令执行成功则返回true,否则返回false。

$irb
>> system 'echo "hello $HOSTNAME"' 
hello nate.local 
=> true
>> system 'false'
=> false 
>> puts $? 
256 
=> nil
>>

3.反引号(Backticks,Esc键下面那个键)

$irb
>> today = `date`
=> "Mon Mar 12 18:15:35 PDT 2007n"
>> $?
=> #<Process::Status: pid=25827,exited(0)>
>> $?.to_i
=> 0

这种方法是最普遍的用法了。它也是运行在一个子shell中。

继续阅读

安装command line tools for xcode

其实这个很好找,但是网上很多误导人的文章,很让人不爽。

打开xcode以后,点击菜单栏的:

Xcode -> Preferences… ->  Downloads

这时候你应该就可以看到Command Line tools了,在Components选项卡里。其实ios模拟器也是这里安装的,大家应该可以看到。

Ps.我的Xcode版本:4.6.1。

编译ruby2.0.0后gem报openssl错误的解决方法

mac osx下编译安装完ruby2.0.0的时候,使用gem install命令会报:Could not load OpenSSL之类的错误,本以为是openssl没装,于是

brew install openssl

还有不行⋯⋯终于执行:

brew link openssl --force

然后make clean,重新编译一下,发现gem又可以正常使用了。

ps.貌似也可以在编译的时候添加下面一个选项:

 --with-opt-dir="`brew --prefix openssl`"

这样就可以load额外的openssl库,而不使用系统的。

比如编译时用:

./configure --prefix=/usr/local/ruby2.0.0 --with-opt-dir="`brew --prefix openssl`"

不过这两个方法前提都是你自己编译安装了openssl,或者使用brew等工具编译安装过它。

Ruby Rake任务简介(转)

RakeMakeAnt

Rake的意思是Ruby Make,一个用ruby开发的代码构建工具。Rake的英文意思是耙子,一种很朴实的劳动工具。真的是很贴切,Rake正是一个功能强大、勤勤恳恳的劳动工具。

但是,为什么Ruby需要Rake

Ruby代码不需要编译,为什么需要Rake?其实,与其说Rake是一个代码构建工具,不如说Rake是一个任务管理工具,通过Rake我们可以得到两个好处:

  1. 以任务的方式创建和运行脚本
    当然,你可以用脚本来创建每一个你希望自动运行的任务。但是,对于大型的应用来说,你几乎总是需要为数据库迁移(比如Rails中db:migrate任务)、清空缓存、或者代码维护等等编写脚本。对于每一项任务,你可能都需要写若干脚本,这会让你的管理变得复杂。那么,把它们用任务的方式整理到一起,会让管理变得轻松很多。
  2. 追踪和管理任务之间的依赖
    Rake还提供了轻松管理任务之间依赖的方式。比如,“migrate”任务和“schema:dump”任务都依赖于 “connect_to_database”任务,那么在“migrate”任务调用之前,“connect_to_database”任务都会被执行。

在哪里可以获得Rake

Rake的主页是在http://rake.rubyforge.org/,在这里你可以获得Rake的简单介绍,API以及一些有用文档的链接。可以在http://rubyforge.org/frs/?group_id=50获得最新版的Rake,在作者写作时,最新版本是0.7.3。

Rake脚本编写 一个简单脚本

Rake的脚本相当简单,下面用一个例子进行说明。假设你是一个勤劳的家庭型程序员,在周末你打算为你的家人做一些贡献。所以你为自己制定了三个任务:买菜、做饭和洗衣服。打开你的文本编辑器,创建一个名叫rakefile的文件(Rake会在当前路径下寻找名叫Rakefile、rakefile、RakeFile.rb和rakefile.rb的rake文件),并输入如下内容:

desc "任务1 -- 买菜"
task :purchaseVegetables do
  puts "到沃尔玛去买菜。"
end

desc "任务2 -- 做饭"
task :cook do
  puts "做一顿香喷喷的饭菜。"
end

desc "任务3 -- 洗衣服"
task :laundry do
  puts "把所有衣服扔进洗衣机。"
end

打开命令行工具,进入这个文件所在目录,然后运行下面的命令,大致应该类似如下结果:

$ rake purchaseVegetables
到沃尔玛去买菜。

$ rake cook
做一顿香喷喷的饭菜。

$ rake laundry
把所有衣服扔进洗衣机。

继续阅读

闲话

最近手欠把服务器升级到了ruby2.0.0,个人不是很喜欢passenger这种编译成nginx模块的方式,顺手换成了unicorn,换unicorn而不使用thin的原因是unicorn名字比较好听……然后写unicorn的文件,各种弄,总觉得unicorn部署起来并没有*unix的感觉,于是又换了thin试试,觉得还是这个顺手,只要thin install,修改配置,然后chkconfig就可以了。

又因为自己乱删服务器里面的rails,导致pipeline合并js文件出了问题,自己一顿暴走,最后终于发现是瞎玩给弄的,看来以后要老实点……

目前ruby2.0.0下跑着完全没问题,只等rails4.0 release了。

也许吧

最近上班很无聊,找不到任何吸引自己的东西,更不知道该做点什么。不知道哪里来的奇怪气息,总想离开北京,找个偏僻位置好好生活。其实北京也没什么过错,只是人太多、空气太差。我刚来的时候明明没什么压力的,为什么现在反到多出这么多看不见的东西萦绕着。

说到底应该是担忧,担忧钱;担忧房子;担忧身体……这么多担忧,到现在自己竟然连为了谁活着都搞不清楚了。

js在光标处插入节点

之前做一个编辑器,需要实现在<pre>中按下tab的时候插入四个空格,因为js是半路出家,研究了好久。思路是获取当前的selection,拿到对应的range,对range进行操作后替换掉原来selection对应的range。

下文是从  Kejun’s Blog  转来的  [javascript]在光标处插入正解 ,给大家一个思路:

之前在网上也找过类似的资料,国内网站介绍的都是老掉牙的方法不兼容标准浏览器。正确的方法是正确运用Selection对象和Range对象,实现在光标当前位置插入文本或结点。但是这两个对象在IE和标准的DOM方式的运用方法是不同的。

思路:首先获得用户的选区(光标当前位置可理解成起始和终止位置一样的选区)。然后,从Selection对象转成Range对象。目的是利用Range对象的方法插内容进去。最后,插入动作结束后将光标移到插入内容的后面。

实现:

var sel = window.document.selection;  //IE下的Selection对象
var sel = window.getSelection();  //DOM方式的Selection对象

var range = sel.createRange(); //IE下
var range = sel.getRangeAt(0); //DOM下

//DOM下
if(range.startContainer){

    sel.removeAllRanges(); //删除Selection中的所有Range
    range.deleteContents(); //清除Range中的内容

    //获得Range中的第一个html结点
    var container = range.startContainer;
    //获得Range起点的位移
    var pos = range.startOffset;

    //建一个空Range
    range = document.createRange();

    //插入内容
    var cons = window.document.createTextNode(“,:),”);

    if(container.nodeType == 3){//如是一个TextNode
        container.insertData(pos, cons.nodeValue);

        //改变光标位置
        range.setEnd(container, pos + cons.nodeValue.length);
        range.setStart(container, pos + cons.nodeValue.length);

    }else{    //如果是一个HTML Node
        var afternode = container.childNodes[pos];

        container.insertBefore(cons, afternode);

        range.setEnd(cons, cons.nodeValue.length);
        range.setStart(cons, cons.nodeValue.length);
    }
    sel.addRange(range);

}else{//IE下
    var cnode = range.parentElement();
    while(cnode.tagName.toLowerCase() != “body”){
        cnode = cnode.parentNode;
    }
    if(cnode.id && cnode.id==”rich_txt_editor”){
        range.pasteHTML(“,:),”);
    }

    window.focus();
}