程序人生

写优雅的程序,做优雅的人

RubyConfChina2012感想

| Comments

昨天参加了 RubyConfChina2012 大会,听了好几个非常精彩的主题演讲,收获良多。

第一个主题演讲是 Ruby 之父 Matz 先生的演讲《Be a lanuage designer》。Matz 的演讲主要有三个部分: 一是如何成为语言的设计师,设计语言没有大家想象中的那么困难,每个开发者平时设计的代码、API和接口其实都是一门“语言”,如果想要设计一门语言,不妨先从DSL写起; 二是Ruby 2.0的最新消息,Ruby 2.0 将会在 Ruby 的20岁生日–2013年2月24日发布,Ruby 2.0 将带来一些非常有意思的特性,比如 Refinement, Module#prepend,Enumerable#lazy 和 Keyword formal Argument等; 三是 mruby 的最新消息,mruby 可以算是 Ruby 的一个子集,它非常小巧精悍(<500K),适用于嵌入式环境,能够运行于小型设备如智能手机,智能网络路由器和机顶盒等等,还介绍了mruby相关的几个项目如MobiRuby——mruby for iOS,mruby_nginx——Nginx mruby Extension 和 mruby-libuv——适用于mruby的异步I/O。

Matz 每次演讲带来的消息都让人振奋。我已经装了 Ruby 2.0 preview 版本,我想接下来可以花些时间做测试,为帮助 Ruby 2.0的发布尽自己一些贡献。

第二个演讲是Jesse Zhang的《How Cloud Foundry Dit it(With Ruby)》, Jesse 主要介绍了 Cloud Foundry 的技术架构。也许是对 Cloud Foundry 了解不多,觉得讲得内容比较抽象,对整个演讲印象不深,会后和 Jesse 聊了一下,了解到他们使用了 EventMachine,所有使用的 Gem 都必须是 EM 版本的,这给开发带来了不少麻烦。

第三个演讲是黄志敏的《OpenFeint迁移到JRuby经验》,主要内容是OpenFeint 通过迁移到 JRuby 带来了接近 40% 的性能提升,迁移过程的原因考虑,实施方法和遇到的问题。从他介绍看,OpenFeint 之前使用的技术堆栈和薄荷非常接近,所以今后可以对 JRuby 做深入的研究,它也许是解决性能问题一个好方法。

第四个演讲是Fred Wu的《如何成为一名更优秀的 Ruby 程序员》,全英文的演讲,讲了很多方面,印象比较深的是要参与到开源项目中,既能贡献力量,也能让自己成长。这点自己以前做得不太好,从开源界得到的帮助很多,但是为之做的贡献很少,以后要改进。

第五个演讲是陈金洲的《Ruby on Rails 创业团队全技术栈指南》,介绍Ruby on rails部署,监控和架构的技术栈选择,他的演讲非常幽默,常引来满场欢乐。演讲的内容我大都非常熟悉,因为自己都亲身经历过,不过还是蛮有收获,特别是他提到要关注应用层的监控,可以使用 New Relic 和 Scout 进行监控,让我有不少启发,之前对应用层的监控重视不够,做得不好。

第六个演讲是王益善的《Ruby Arduino Hacking》,介绍了什么是 Arduino,用 Arduino 和 Ruby 演示一些有意思的操作,比如唱《两只老虎》,控制台灯什么的,非常好玩。之前对所谓开源硬件缺乏了解,通过他的介绍,让我有了直观的认识,觉得蛮有趣的,以后有空也想折腾一番,呵呵。

第七个演讲是马海波的《程序员如何设计》,从程序员的角度探讨如何学习,应用设计,一个很深的体会是他的 ppt 做的很漂亮,非常有设计感。自己向来对设计心存畏惧,从他的演讲找到了一些信心,以后一定要学一学设计。

最后是一个小演讲,王松林介绍他们在嵌入设备上使用 cruby 和 mruby 的一些经验。

RubyConfChina 大会已经举办了 4 届,这 4 届我都有参加,感觉这一届是过往最热闹,最精彩的一届,可以明显感觉到 Ruby 在中国稳步前行,让我为自己作为一名 Ruby 程序员而自豪。感谢辛勤大会组织者,感谢杰出的演讲者,感谢所有为大会贡献的公司和个人,相信 Ruby 的世界会更美好,中国的 Ruby 更美好。

Ruby: block proc and lambda

| Comments

在规则引擎中,Ruby 的闭包使用特别频繁,而且有 block,Proc和 lambda 等后几种形式的用法,很让人困惑。为了深入理解代码,再次认真学习了一下 Ruby 的闭包,特别是 block,proc 和 lambda 几种用法的异同,这次的周记就和大家分享一下心得。

闭包是 Ruby 相对其它语言特别优势之一,很多语言有闭包,但是唯有 Ruby 把闭包的优势发挥得淋漓尽致。Ruby 的哲学之一:同一个问题现实中有多种解决方法,所以 Ruby 中也有多种解法,所以闭包的使用也有多种方法。

先看一个代码的例子: Example 1:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
def foo1
  yield
end

def foo2(&b)
  b.call if b
end

foo1 { puts "foo1 in block" }
foo2 { puts "foo2 in block" }
proc = Proc.new { puts "foo in proc" }
foo1(&proc)
foo2(&proc)
lambda_proc = lambda { puts "foo in lambda" }
foo1(&lambda_proc)
foo2(&lambda_proc)

输出:

1
2
3
4
5
6
》foo1 in block
》foo2 in block
》foo in proc
》foo in proc
》foo in lambda
》foo in lambda

大家是不是有些困惑,首先是方法 foo1 和 foo2 都能接收闭包,它们这两种写法有什么区别,然后是作为参数的三种闭包 block,proc和 lambda有什么区别。

1. yield 和 block call 的区别

yield 和 block call 两种都能实现运行闭包,从实际运行效果来说,区别不大。其区别主要在于:

1.1 闭包的传递和保存

因为闭包已经传递到参数里,所以可以继续传递或保存起来,例如:

Exampl 2:

1
2
3
4
5
6
7
8
9
10
11
12
   class A
      def foo1(&b)
         @proc = b
      end
      def foo2
          @proc.call if @proc
      end
   end

    a = A.new
    a.foo1 { puts "proc from foo1" }
    a.foo2

1.2 性能

yield不是方法调用,而是 Ruby 的关键字,yield 要比 block call 比快 1 倍左右。

2. block 和 proc, lambda 的区别

很简单直接,引入 proc 和 lambda 就是为了复用,避免重复定义,例如在 example 1 中,使用 proc 变量存储闭包,避免重复定义两个 block 。

3. proc 和 lambda 的区别

这大概是最让人困惑的地方,从 Example 1 的行为上看,他们的效果是一致的,为什么要用两种不同的表达方式。

1
2
   proc = Proc.new { puts "foo in proc" }
   lambda_proc = lambda { puts "foo in lambda" }

确实,对于简单的情况,比如 Example 1的情况,他们的行为是一致的,但是主要在两个地方有明显差异:

1.1 参数检查

还是例子说话 Example 3:

1
2
3
4
5
6
7
8
9
10
11
12
13
   def foo
      x = 100
      yield x
   end

   proc = Proc.new { |a, b| puts "a is #{a.inspect} b is #{b.inspect}" }
   foo(&proc)


   lambda_proc1 = lambda { |a| puts "a is #{a.inspect}" }
   foo(&lambda_proc1)
   lambda_proc2 = lambda { |a, b| puts "a is #{a.inspect} b is #{b.inspect}" }
   foo(&lambda_proc2)

输出

1
2
3
4
   》a is 100 b is nil
   》a is 100
   》ArgumentError: wrong number of arguments (1 for 2)


可见,proc 不会对参数进行个数匹配检查,而 lambda 会,如果不匹配还会报异常,所以安全起见,建议优先用 lambda。

1.2 返回上层

还是例子说话 Example 4:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
   def foo
     f = Proc.new { return "return from foo from inside proc" }
     f.call # control leaves foo here
     return "return from foo"
   end


   def bar
     f = lambda { return "return from lambda" }
     puts f.call # control does not leave bar here
     return "return from bar"
   end


   puts foo
   puts bar

输出

1
2
3
   》return from foo from inside proc
   》return from lambda
   》return from bar


可见,proc 中,return 相当于执行了闭包环境里的 return,而 lambda 只是返回call 闭包所在环境。

总结:闭包是 Ruby 的强大特性,它的几种表达方式block,proc 和 lambda有细微差别,要用好它需要对其深入理解。

我们幸福的一家

| Comments

感谢上苍赐予我和爱妻一对健康可爱的儿女。

Photo1

弟弟还小,青禾姐姐要多关心弟弟哦。

Photo2

青禾骑车的姿势很酷吧。

Photo3

直树很醒目的样子。

Photo4

青禾在大声呼喊,啊~~

Ruby 中的 p 和 puts

| Comments

p 和 puts 是 Ruby 中特别常用的方法,很多童鞋可能认为它们是差不多的,使用的时候也不加注意,但是仔细考究起来,它们是有明显差别的。

先举一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
  class Foo
    def inspect
      "foo from inspect"
    end

    def to_s
      "foo from to_s"
    end
  end

  foo = Foo.new
  p foo
  puts foo
  p "p: <#{foo}>"
  puts "p: <#{foo}>"

这段代码的输出是

1
2
3
4
foo from inspect
foo from to_s
p: <foo from to_s>
puts: <foo from to_s>

p obj 相当于 puts obj.inspect,而 puts obj 相当于 puts obj.to_s, 使用的方便是明显区别的,p 是使用 obj 的 inspect 方法,而 puts 是 to_s 方法。

为什么会这样呢?这个我想可以从 to_s 和 inspect 的区别说起,to_s 是对象的字符串表示, 是 puts 和双引号字符使用的方法。inspect 是对象状态的表示,通用用于 debug 中。 Object 中的定义了 to_s 和 inspect 方法,默认都是返回对象的类名和地址。

所以p 和 puts主要是用途的不同,p 是作为 debug 输出,而 puts 作为对象的字符串表示输出。

另外值得一提的是,在 irb console 中,命令行中表达式求值,使用的是 p 对象的 inspect 方法。另外,通常 debug 输出命令,也是使用对象的 inspect 方法。

使用 proxychains 访问远程 svn 服务器

| Comments

有多种方法能让 svn 访问远程内部 svnserv 服务器.

一是使用 svn+ssh://… 形式的 repos url,这种方法简单便捷,缺点是内外网访问使用的 repos url 不一致,需要建立多个 work copy, 而且使用 svn+ssh:// 时,使用的 svn 用户为 ssh 的用户。

二是使用 vpn,缺点在于建立 vpn 比较麻烦,特别是 vpn 需要服务器和路由器的支持,常常会出现无法使用的情况。

三是使用 ssh tunnel 和 proxychains 建立 svn 到远程内部 svn 服务器的通信通道,这种方法可以使 work copy 一致,svn 用户一致,麻烦 的地方在于需要额外安装一个软件 proxychains,使用时必须启用 ssh tunnel 和 wrap svn 命令。

下面详细介绍第三种方法的使用。

1.安装 proxychains 软件。下载 proxychains 代码(目前最新是3.1),如果是 Mac 系统还要对代码加一个补丁 参见:ProxyChains for Mac OS X patch

需要特别注意的是,使用的时候请更改执行脚本 proxychains 中 DYLD_INSERT_LIBRARIES 为正确的路径。

2.启用 ssh tunnel。执行一个命令即可,例如

1
   ssh -Nf <user>@<host> -D 127.0.0.1:9050


为方便使用,可把它放到一个 shell 文件中。

3.wrap svn命令。 使用方法是每个svn命令前加上 proxychains 即可,例如

1
2
   proxychains svn up
   proxychains svn commit

为避免每次使用都敲一次 proxychains,可以建立一个 alias。 在 ~/.bash_profile 中增加一行

1
   `alias psvn="/opt/local/bin/proxychains svn"

这样就可以使用下面简单的命令了:

1
2
3
  psvn up
  psvn commit
  psvn stat -r