最近开始玩Sublime Text,目前还在Evaluate阶段,逐步尝试用它替换掉原来Vim。期间实时语法检查用到了Sublime Linter这个插件,感觉还是蛮不错的。但是用于用了RVM管理Ruby版本,因此不能让Sublime Linter使用系统级的Ruby了。对此其实Sublime Linter是做了准备的,在它的README中就有这样一句:

If you are using rvm or rbenv, you will probably have to specify the full path to the ruby you are using in the "sublimelinter_executable_map" setting. See "Configuring" below for more info.

一般是要求修改sublimelinter_executable_map使之为$HOME/.rvm/bin/rvm-auto-ruby,这么做得话,显然就可以用RVM默认的Ruby版本了。但是这样对我而言还是不够的,由于工作的原因,我不同的项目都使用不同的ruby版本,而默认则是Ruby 1.8.7,当我在编写Ruby 1.9.3的代码时,老是按照Ruby 1.8.7来做语法检查,显然会出现大把大把的错误。(这个不是SublimeLinter的工作不到位,要知道以前用Vim的时候根本没得选。。)

对我这种Case而言,最好的方法是根据文件所在项目目录里的.rvmrc文件来判断这个文件该使用哪个Ruby版本。为此我写了一个shell脚本(起名叫rvm_use):

#!/usr/bin/env bash

[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"
for i in "${@:2}"; do
    if [[ ! "$i" =~ ^- ]]; then
        cd `dirname $i`
        break
    fi
done
$@

这个脚本接受一行完整的Shell命令,比如"ruby -wc ...",然后从第二个参数开始(第一个参数往往是ruby或是rspec这样的可执行文件),如果检测到第一个首字母不是 '-' 的参数,认为这个参数就是项目文件所在位置,用cd命令进入到这个文件所在的目录(rvm已经hack了cd命令,只要进入的目录有.rvmrc就会切换到它指定的Ruby版本),然后执行用户送入的命令。

刚才这个脚本已经适用于Sublime Build之类同样涉及到Ruby的功能,但是要给SublimeLinter用的话,还要额外加一个脚本,这是因为SublimeLinter认为解释器命令一定只有一个参数,如果我把解释器设为 'rvm_use ruby' 的话将会出错。因此额外增加一个rvm_use_ruby脚本:

#!/usr/bin/env bash

`dirname $0`/rvm_use ruby $@

让Sublime Linter使用这个脚本就行了。

本来以为这么做就足够了,但是后来发现依然不够。调试发现Sublime Linter依然没有使用到正确的Ruby版本,阅读插件的Python源码发现(感谢不久前的Python Training,多少掌握了一些Python),Sublime Linter为了尽可能实现实时检测,提供了三种检查策略,通过文件检查,通过临时文件检查,通过STDIN检查。对于C语言这样比较死板的语言来说,文件必须先被保存,然后让检查工具去检查这个被保存的文件的语法才能得到正确的结果。Java则稍微高级一点,无需等到保存,而是在检查前将当前还未保存的文件偷偷写入到一个临时文件,然后检查那个临时文件的语法。至于Ruby由于是脚本语言,支持直接用STDIN将代码输入进去,这样同样无需保存文件即可实现实时检查。但是这个做法显然就无法应用我之前的办法了。因为rvm_use命令参数中将没有一个文件名,也就无从知晓应该用的Ruby版本了。

对于这种情况,一种可行的办法是修改SublimeLinter/sublimelinter/modules/ruby.py,修改它的CONFIG中的"input_method"参数(抱歉,没找到针对User目录的修改方法,只能改源文件了),但是这并不是一种理想的办法。因为这样就彻底失去了实时检查的功能,我并不想做这样的妥协。因此既然要改SublimeLinter/sublimelinter/modules/ruby.py文件,何不改的再彻底点,针对Ruby彻底重写executable_check方法?修改后的文件是这样的:(再次感谢Python Training)

# -*- coding: utf-8 -*-
# ruby.py - sublimelint package for checking ruby files

import re
import os
import subprocess

from base_linter import BaseLinter

CONFIG = {
    'language': 'Ruby',
    'executable': 'ruby',
    'lint_args': '-wc'
}


class Linter(BaseLinter):
    def parse_errors(self, view, errors, lines, errorUnderlines, violationUnderlines, warningUnderlines, errorMessages, violationMessages, warningMessages):
        for line in errors.splitlines():
            match = re.match(r'^.+:(?P<line>\d+):\s+(?P<error>.+)', line)

            if match:
                error, line = match.group('error'), match.group('line')
                self.add_message(int(line), lines, error, errorMessages)

    def executable_check(self, view, code, filename):
        args = [self.executable]
        args.extend(self._get_lint_args(view, code, filename))
        dirname = os.path.dirname(filename)

        process = subprocess.Popen(['bash', '-c',
                               'source $HOME/.rvm/scripts/rvm && \
                                cd ' + dirname + ' && '\
                                + '  '.join(args)],
                               stdin=subprocess.PIPE,
                               stdout=subprocess.PIPE,
                               stderr=subprocess.STDOUT,
                               startupinfo=self.get_startupinfo())
        process.stdin.write(code)
        result = process.communicate()[0]

        return result.strip()

这里用bash -c启动一个独立环境,在这个环境里执行source命令后用被rvm hack过的cd命令进入项目文件所在文件夹,然后再执行检查命令。这样就可以完美解决问题了。

注意Sublime的配置文件一定要被git托管,否则一旦源码因为升级而还原的话所有修改就都丢失了。

本文记录如何使用RVM,而不是Yum和APT,安装最新版本Ruby on Rails。之所以不用Yum和APT,是因为Fedora的Yum源,Debian的deb源都没有Ruby 1.9.2。

首先,浏览:https://rvm.beginrescueend.com/ 获取Quich install内的安装RVM的方法,这个安装方法可能随着时间的推移而改变,目前安装方法是:

bash < <(curl -s https://rvm.beginrescueend.com/install/rvm)

在运行安装命令之前,请确定务必满足这三个要求:

bash >= 3.2 is required
curl is required
git is required (>= 1.7 recommended)

如果没有满足,可以运行:

yum install -y bash curl git

你还需要安装这些以满足Ruby on Rails的要求,如果不安装,编译后的rubygems可能会有问题。

yum install -y gcc-c++ patch readline readline-devel zlib zlib-devel libyaml-devel libffi-devel openssl-devel
apt-get install build-essential bison openssl libreadline6 libreadline6-dev curl git-core zlib1g zlib1g-dev libssl-dev libyaml-dev libsqlite3-0 libsqlite3-dev sqlite3 libxml2-dev libxslt-dev autoconf libc6-dev ncurses-dev

运行并确保这句语句存在于.bashrc和.bash_profile的最后

[[ -s "$HOME/.rvm/scripts/rvm" ]] && source "$HOME/.rvm/scripts/rvm"

确保这个语句存在于.rvmrc的最后

export rvm_pretty_print_flag=1

用RVM安装Ruby最新版本(1.9.2)(如果遭遇网络问题请自行解决)

rvm install 1.9.2

查看RVM目前管理的所有的Ruby版本

rvm list

命令RVM使用Ruby的最新版本(ruby-1.9.2-p290)

rvm use ruby-1.9.2-p290

完成后,检查version

ruby -v

如果能显示出版本,表示ruby安装已经成功,下面开始准备安装rails,我们将使用rubygems来安装

首先,创建一个gemset

rvm --create use 1.9.2@rails3

默认使得这个gemset

rvm --default use 1.9.2@rails3

下面安装rails,建议先升级gem,可能可以避免一些错误出现

gem update --system
gem update
gem install rails

安装完成后,检查version

rails -v

如果能显示出版本,表示rails已经安装成功,赶紧创建一个项目,体现了Ruby on Rails的快感吧!

本文根据 http://www.wretch.cc/blog/yschu7/13353264 整理并精简部分不必要的内容

如果是Ubuntu / Debian 用户,还可以阅读 http://coding.smashingmagazine.com/2011/06/21/set-up-an-ubuntu-local-development-machine-for-ruby-on-rails/,写得比我更详细些。