Today's the day

向软件大牛炫耀我会焊单片机,向硬件大牛炫耀我会写 Rails,向软硬件大牛炫耀我生物,向软硬件生物大牛炫耀我会折腾期货 -_-bbb

带文件浏览器边栏的 Macvim

Vim 默认并没有文件浏览器的功能,所以如果需要同时浏览项目内多个文件,或是要在某个文件夹下创建新文件、重命名文件的时候,就有点麻烦,虽然有诸如 NERDTree 的插件,但是显然效果和使用上都不是那么直观,而且我需要的功能无非就是浏览和创建文件而已。

于是,终于找到了这个带文件浏览器边栏的 Macvim 修改版:

https://github.com/alloy/macvim

功能不多不少,正好满足要求,显示的效果非常直观,简单易用~

这样暂时也不用去折腾 TextMate、Sublime Text 什么的了,Macvim 还可以撑一段时间~

第二次服务器迁移

终于在周日把服务器迁移到 Linode 上去了,这是 is-programmer 上线以来的第二次迁移,第一次是从墙内的托管主机迁移到 Godaddy,第二次就是这次从 Godaddy 迁移到 Linode。

比较意外的是,虽然在 Godaddy 使用的是独立服务器,但是测试后发现还是 Linode 的 VPS 性能要稍好一些,看来那台独立服务器的配置确实是太老了。

价格比 Godaddy 便宜一些,不过要是算上 Godaddy 打折就和原来差不多了。

这样看来,唯一的缺点就是硬盘比原来小了不少,还好并不会有很大影响,而且 VPS 基本都是如此吧。

 

回顾主机类型的变化也很有趣:第一次是自己组装的 1U 服务器,第二次是 Godaddy 的独立服务器,这一次是 Linode 的 VPS。

配置和管理越来越容易,性能越来越好,价格还越来越低。

不得不说现在要想架个网站,服务器方面的门槛是越来越低了,不仅体现在价格上,最主要的还是管理上,再也不用跑机房了。而且有 Linode 这种虚拟化的主机,还可以轻松把服务器架到全球各地去~

回顾迁移的原因,第一次是因为服务器被拔线,这一次是因为间歇被墙,看来都和天朝和谐的网络环境脱不了关系,不过也因此被强迫着学习了不少东西。

 

is-programmer 的迁移的过程相当顺利,只花了 20 分钟,大部分时间花在在两台服务器间传输数据上。不过服务器的准备方面花了两天才搞定,vsftp、postfix、crontab、apache、mysql…… 基本上把那些配置又重新复习了一边,顺便玩了玩 Octpress 给旧的服务器做了个迁移提醒页面

新的服务器没有了被墙的问题(也许是暂时的?),速度也快了不少,Linode 的确如传言所说的那样好使,强烈推荐~

 

 

 

Psych、Syck、YAML 和编码

这次 is-programmer 升级碰到了一个很棘手的问题,花了好长时间才把大致的原因搞明白,这里记录一下经过。

背景

在 Ruby 1.9.2 之前,YAML 的解析使用的是 Syck 这个引擎,而从 1.9.3 之后,默认的引擎变成了 Psych。Psych 相比 Syck 有以下优点:

  • 可以正确处理 UTF-8 字符。
  • 基于的底层库是 YAML 标准组所写的 libyaml。
  • 支持 YAML 1.1。
  • Syck 已经不再维护了。

UTF-8 字符串的处理是 Psych 和 Syck 之间最主要的一个区别:

Syck 因为无法直接处理 UTF-8 字符,所以如果导出的值中含有 UTF-8 字符串的话,Syck 会把它 Base64 编码,然后保存为 binary 格式:

# Syck
$ YAML.dump(:title => "标签云")
=>
 ---
 :title: !binary |-
  5qCH562+5LqR

Psych 可以正确序列化 UTF-8 字符,所以 YAML 中保存的就是原始字符:

# Psych 
$ YAML.dump(:title => "标签云")
=>
 ---
 :title: 标签云

当然 Syck 这个引擎在 ruby 1.9.3 里面还是存在的,可以通过设置 YAML:ENGINE 来在程序中切换:

$ YAML::ENGINE.yamler = 'syck'    # 使用 Syck 引擎
$ YAML::ENGINE.yamler = 'psych'   # 使用 Psych 引擎

问题

is-programmer 早在 ruby 1.8.x 的时代就开始使用 YAML 来保存设置,自然 UTF-8 字符串都是 Syck 的 binary 格式,这次升级将 ruby 从 1.9.2 升级到了1.9.3,YAML 的默认引擎也就切换到了 Psych,因为本地测试都是使用全新的数据,因此并没有发现问题。

结果上线之后,发现大量的中文设置出现类似

æ ‡ç­¾äº‘æ ‡ç­¾äº‘æ ‡ç­¾äº‘

的乱码。

不用说,问题肯定出在 Psych 上。

原因

既然出现乱码的都是含有中文字符串的设置,那么问题就比较明朗了,那就是:

Psych 似乎不能正确解析在 Syck 下序列化的 binary 格式的字符串。

我猜测是因为 Psych 不知道 binary 字符串原来的编码,也可能是 Psych 的 bug 或是标准不兼容。总之,如果使用 Psych 来读取 Syck 下保存的 UTF-8 字符串,会出现很诡异的结果:

$ YAML::ENGINE.yamler = 'psych'
$ YAML.load("---\n:title: !binary |-\n5qCH562+5LqR")
=>
 {:title=>"\xE6\xA0\x87\xE7\xAD\xBE\xE4\xBA\x91"}

然后,在网页上显示的就是更加诡异的诸如以下的字符:

æ ‡ç­¾äº‘

解决

本来,要解决这个问题很简单,只需要把 YAML 引擎切换回 Syck 就行了:

 YAML::ENGINE.yamler = 'syck'

这样虽然无法使用新引擎,但是至少显示不会出现问题。

不过,由于上线之后,一些用户又重新保存了设置,问题一下就复杂化了。

把引擎切换回 Syck 已经来不及了,因为 Syck 也不能正确解析 Psych 下保存过得 YAML。

不仅仅是如此,更加郁闷的是,现在 YAML 中不仅有老的 binary 格式字符串,还有被 Psych 保存过的乱码字符串,而且还有保存正确的 Psych 格式的中文 UTF-8 字符串……

这可肿么办呐 

经过一番 之后,决定还是先想想怎么把乱码恢复成正确的中文字符串。

之后又经过了一番 ……终于发现,Psych 似乎在解析了 binary 字符串之后,并没有把字符串标示为 UTF-8,而是标示为 ISO-5589-1(也就是 LATIN-1),之后由于 ruby 内部的编码被设成成了 UTF-8,所以字符串又被按照 ISO-8859-1 的过程转换了一番,于是就得到了网页上显示的那样诡异的字符。

这样的话,如果想把乱码转换回中文,那么就需要:

"xxx乱码xxx".force_encoding("UTF-8")\    # 先强制标示为 UTF-8
            .encode("ISO-8859-1")\      # 再转换成 ISO-8859-1 
            .force_encoding("UTF-8")    # 再强制标示为 UTF-8

这样正确的字符串就回来啦~

不过,YAML 还有已经被 Psych 正确保存的中文字符串,还有一些非中文的英文设置,怎么把乱码和这些正确的字符串区分呢?

幸运的是,如果是英文字符串,在这个过程中内容并不会改变(英文没有编码问题就是爽),而如果是已经正确保存的中文字符串,那么在 encode("ISO-8859-1") 的时候,会 raise 一个 Encoding::UndefinedConversionError 异常,这样只要捕捉这个异常并保留原值就行了。

于是,如果想把混乱的 old_hash 修复的话,就要:

    def fix_yaml_hash(old_hash)
        new_hash = {}
        old_hash.each do |key, value|
            if value.is_a?(String)
                begin
                    new_value = value.clone.force_encoding("UTF-8").encode("ISO-8859-1").force_encoding("UTF-8")
                rescue
                    new_value = value
                end
            else
                new_value = value
            end
            new_hash[key] = new_value
        end
        return new_hash
    end

这样的话,问题就全面解决了~

结论

  • 如果你已经使用上了 Psych 并且一切正常,那么就用吧,Psych 在今后应该可以成为 ruby 处理 YAML 的标准。
  • 如果你还在使用 Syck,还是先 YAML::ENGINE.yamler = 'syck' 用着吧。
  • 如果还没有开始使用 YAML,那么强烈建议趁着这个机会去转向更加流行的 JSON

重新审视 Vim

虽然号称使用 Vim 多年,但是实际上一直没有仔细研究过,平常用的也就是 Vim 的基本快捷键而已,虽然经常写 Rails 代码,但是除了自己定义了一个在 erb 文件中输入 <%= %> 代码的快捷键之外,就没有任何其他配置了,插件也只是偶尔用用 NERDCommenter 之类。

最丢人的是,目前还不习惯用 hjkl 移动,因为平常也经常用其他的普通编辑器,所以即使在 Vim 下,每次也都是用着用着就去摸箭头键了,至今没有调整过来。

不过前天看到一篇非常好的 Vim 文章:

Coming Home to Vim / Steve Losh

受其影响,开始重新审视 Vim。

文章中提到的一些 Tips 比较有启发性,比如对于不知不觉去摸箭头键而不使用 hjkl 的问题,可以用下面的配置代码,将箭头键屏蔽:

nnoremap <up> <nop>
nnoremap <down> <nop>
nnoremap <left> <nop>
nnoremap <right> <nop>
inoremap <up> <nop>
inoremap <down> <nop>
inoremap <left> <nop>
inoremap <right> <nop>

这样每次就会被强迫去用 hjkl 了,对于 Vim 初学者来说尤其实用。

此外,对于回到命令模式用的 Esc 太远的问题,除了通过某种方法把无用的 CapsLock 键映射为 Esc 之外,还可以使用“jj”:

inoremap jj <ESC>

因为单词中很少有输入 jj 的情况,所以并不会干扰输入。映射为“,,”也可以,当然也可以使用脚踏板 :)。

此外还知道了一个可以像 TextMate 那样智能打开文件的插件 PeepOpen

虽然要收费,但是效果比 Command-T 之类的要好多了,所以等有了资金就去买一个用。有了这个东西,NERDTree 之类的就不需要了~ :)

最后,就是再定义一些快捷键了,Vim 的快捷键定义语法 nnoremap 和 inoremap 非常直观,一直都想不出应该定义什么真是不应该啊。

Nginx + Passenger 也不错

最开始把 Chito 切换到 Rails3.0 之后,发现新建项目并没有自动生成 dispatch.fcgi 文件,拿 Rails2.x 的文件来用,却不知道怎么的失败了,上网搜了一圈,没搜到什么解决办法,倒是搜到一大堆“fastcgi 的 Rails 部署模式已经过时”云云的评论,郁闷之余心想这也是个尝试新部署方法的好机会。

于是就采用了 Nginx + Passenger 这个时髦的方案。不得不说这个方案的配置方法实在是太轻松了,运行一个 passenger-install-nginx-module 命令,就可以自动帮你下载 nginx,然后自动编译进 Passenger 模块,再自动写好配置文件,只需要改一下自己的 Rails 程序的目录位置,然后就可以跑了~

什么附加的参数也不用写,默认的配置下运行的状况就非常良好。开始总觉得相比以前的 Lighttpd,响应速度有点慢,不过运行了两天下来,发现也没有那么严重。除此之外,都是优点。

首先最意外的就是内存占用了:

对比很强烈,凌晨 1 点做了切换。左边是 Lighttpd + fastcgi + ruby1.8.7 + Rails2.3.8,右边的就是 Nginx + Passenger + ruby1.9.2 + Rails3.0,打开了同样的进程数,但是后者的内存占用(绿色 apps 部分)降低了一半多。不过我估计大部分的原因是 ruby1.9.2 和 ruby 1.8.7 的差别造成的,具体的原因是什么也懒得研究了,总之感觉很爽。

使用 Passenger 的另一个好处就是有两个命令:passenger-status 和 passenger-memory-stats,可以用来查看当前 Passenger 服务的运行状况和内存占用状况,配合 Munin,可以像上面监控系统资源那样,监控 Passenger 服务的运行状况:

相比 fastcgi 要方便一些。关于 Munin 的 Passenger 监控配置,可以参考这里

从这次切换的结果来看,ruby1.9 很稳定,尤其是前两天的 1.9.2 已经非常好用了,在新 mysql2 的配合下,所谓的字符编码问题也基本没有碰到。

Rails 3.0 似乎也没什么大问题,刚上线的时候确实出现了一些诡异的问题,不过后来都发现是第三方的 Rails 插件造成的。虽然 3.0 相对 2.x 很多的 API 写法都要改变,但是改过来后基本不会出现什么问题,对于 3.0 诸多的新特性(目前最爱的就是 ARel  Query API 了)来说,这种改动非常值得,新项目也可以直接就用 3.0 了。


话说经常有人问哪里可以下载到 Chito 的源代码,目前在 Github 上:

http://github.com/galeki/chito

现在的 master 分支就是最新的 Rails3 版本,如果想使用 Rails2.x 的版本,可以用 v1.1.7-for-rails-2.x 这个 Tag。

chitolog.org  一直没管结果域名挂了,过阵子再把它恢复吧…… -_-;