RubyGems 笔记之二

gem的结构

1 每一个gem都要有名称、版本、运行环境。以rake 0.8.7 为例,其名称’rake’,版本’1.8.7’,运行平台是ruby,意味着可以运行在任何ruby平台上。

2 运行环境是基于CPU架构、操作系统之上,有时候还会受限于操作系统的版本。

3 在gem中包含以下组件 代码:(包括测试和辅助程序) 文档 gemspec(gem的自述文件)

每一个gem包的代码结构组织都遵循统一的标准

1
2
3
4
5
6
7
8
9
10
11
% tree freewill
freewill/
├── bin/
│   └── freewill
├── lib/
│   └── freewill.rb
├── test/
│   └── test_freewill.rb
├── README
├── Rakefile
└── freewill.gemspec

如上所示,一个gem包含的主要组件有:

lib目录:包含gem的代码

test目录或spec目录,包含测试代码,取决于开发者用的是哪个测试框架。

Rakefile文件:rake程序使用该文件进行自动化测试,生成代码或者执行其他任务。

bin目录:当gem安装好以后,bin目录将添加到用户的环境变量中去。

文档通常在README中或者在代码的注释里面。当gem安装完成的时候,文档也会为你自动生成好,大部分gem包含RDoc文档,也有用YARD的。

gemspec文件,该文件的内容包含了文档相关的信息。

The Gemspec

gemspec文件包含了文档的名称、作者、版本等相关的信息,例如:

1
2
3
4
5
6
7
8
9
10
11
% cat freewill.gemspec
Gem::Specification.new do |s|
  s.name        = 'freewill'
  s.version     = '1.0.0'
  s.summary     = "Freewill!"
  s.description = "I will choose Freewill!"
  s.authors     = ["Nick Quaranto"]
  s.email       = 'nick@quaran.to'
  s.homepage    = 'http://example.com/freewill'
  s.files       = ["lib/freewill.rb", ...]
end

更多gemspec相关内容参看http://guides.rubygems.org/specification-reference/

RubyGems 笔记之一

简介:


  1. ruby的软件包称为 ‘gem’, 类似与java的jar包。ruby的gem包用来拓展或修改ruby应用程序的函数,通常将一些可复用的函数打包成gem,作为库与方便与其他开发者共享。有的gem提供了命令行工具来实现 automate tasks ,提升你的工作效率。

  2. RubyGems是用于管理gem工具,可以方便的下载、安装、使用和卸载gem。

  3. gem 命令用于管理RubyGems。Ruby1.9 以及后来的版本都默认集成了RubyGmes,安装完ruby以后,就可以直接使用 gem 命令。

使用


一、 查找Gems:

search 命令用于查找远程的gem包。

1
2
3
4
5
6
7
8
9
10
╭─# ivan@ubuntu in ~/private/19wu ‹ruby-2.0.0@19wu›  
╰─$ gem searc\^rails  

*** REMOTE GEMS ***

rails (4.0.2)
rails-3-settings (0.1.1)
rails-action-args (0.1.1)
rails-admin (0.0.0)
...

-d 参数可以查看更加详细的信息:

1
2
3
4
5
6
7
8
9
10
╭─# ivan@ubuntu in ~/private/19wu ‹ruby-2.0.0@19wu›  
╰─$ gem search  \^rails\$ -d

*** REMOTE GEMS ***

rails (4.0.2)
    Author: David Heinemeier Hansson
    Homepage: http://www.rubyonrails.org

    Full-stack web application framework.

其他参数, 参考 gem search --help

二、 安装Gems

install 命令用于安装gems。

例如:

1
gem install rails -v= 4.0 --no-rdoc --no-ri

三、Requiring code

RubyGems 修改了Ruby的加载路径,并且控制如何查找require进来的ruby代码。当require一个gem的时候,会将这个gem的路径添加到全局变量$LOAD_PATH中。

在启动irb的时候,通过 -r 参数可以指定要加载的gem:

1
2
3
4
5
6
7
8
9
10
11
12
╭─# ivan@ubuntu in ~/private/19wu ‹ruby-2.0.0@19wu›  
╰─$ irb -rpp 
irb(main):001:0>  pp $LOAD_PATH
["/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby/2.0.0",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby/2.0.0/i686-linux",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/vendor_ruby/2.0.0",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/vendor_ruby/2.0.0/i686-linux",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/vendor_ruby",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/2.0.0",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/2.0.0/i686-linux"]
...

默认只加载几个必要的标准库,如果要加载指定的gem:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
╭─# ivan@ubuntu in ~/private/19wu ‹ruby-2.0.0@19wu›  
╰─$ irb -rpp 
irb(main):001:0> require 'rails'
=> true
irb(main):002:0>  pp $LOAD_PATH
["/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/i18n-0.6.5/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/multi_json-1.7.9/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/tzinfo-0.3.37/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/atomic-1.1.12/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/thread_safe-0.1.2/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/activesupport-4.0.0/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/builder-3.1.4/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/rack-1.5.2/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/rack-test-0.6.2/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/erubis-2.7.0/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/actionpack-4.0.0/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/thor-0.18.1/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/railties-4.0.0/lib",
 "/home/ivan/.rvm/gems/ruby-2.0.0-p353@19wu/gems/json-1.8.0/lib",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby/2.0.0",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby/2.0.0/i686-linux",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/site_ruby",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/vendor_ruby/2.0.0",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/vendor_ruby/2.0.0/i686-linux",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/vendor_ruby",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/2.0.0",
 "/home/ivan/.rvm/rubies/ruby-2.0.0-p353/lib/ruby/2.0.0/i686-linux"]
...

注意: 如果您使用的是 ruby 1.8 版本,在引入任何gem之前,需要先引入 rubygems: require 'rubygems',在某gem所在目录的lib目录下,必须存在一个rb文件和一个目录,要求名称和gem的名称一致。

1
2
3
4
5
6
7
8
% tree freewill/
freewill/
└── lib/
    ├── freewill/
    │   ├── user.rb
    │   ├── widget.rb
    │   └── ...
    └── freewill.rb

四、 列举出所有已经安装好的gem

list 命令可以列举出所有已经安装好个gem

1
2
3
4
5
6
7
8
9
10
11
12
13
14
╭─# ivan@ubuntu in ~/private/19wu ‹ruby-2.0.0›  
╰─$ gem list

*** LOCAL GEMS ***

bigdecimal (1.2.0)
gem-wrappers (1.2.4)
io-console (0.4.2)
json (1.7.7)
minitest (4.3.2)
psych (2.0.0)
rake (0.9.6)
rdoc (4.0.0)
test-unit (2.0.0.0)

五、 卸载Gems

uninstall 命令用于卸载已经安装的gem包。

1
2
$ gem uninstall drip
Successfully uninstalled drip-0.0.2

如果你要卸载一个被其他gem依赖的gem,会要求进行确认:

1
2
3
4
5
6
7
8
9
10
$ gem uninstall rbtree

You have requested to uninstall the gem:
  rbtree-0.4.1

drip-0.0.2 depends on rbtree (>= 0)
If you remove this gem, these dependencies will not be met.
Continue with Uninstall? [yN]  n
ERROR:  While executing gem ... (Gem::DependencyRemovalException)
    Uninstallation aborted due to dependent gem(s)

六、 查看gem文档

ri 命令可以用于查看gem的文档。或者运行 gem server 通过浏览器查看

七、 Fetching and Unpacking Gems

如果你仅仅想获取并查看一个gem的内容,可以通过fetchunpack命令来实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
╭─# ivan@ubuntu in ~/private/temp ‹ruby-1.8.7@rails304›  
╰─$ gem fetch json
Fetching: json-1.1.5-x86-linux.gem (100%)
Downloaded json-1.1.5-x86-linux

╭─# ivan@ubuntu in ~/private/temp ‹ruby-1.8.7@rails304›  
╰─$ ls   
json-1.1.5-x86-linux.gem

╭─# ivan@ubuntu in ~/private/temp ‹ruby-1.8.7@rails304›  
╰─$ gem unpack json-1.1.5-x86-linux.gem 
Unpacked gem: '/home/ivan/private/temp/json-1.1.5-x86-linux'

╭─# ivan@ubuntu in ~/private/temp ‹ruby-1.8.7@rails304›  
╰─$ ls
json-1.1.5-x86-linux  json-1.1.5-x86-linux.gem

以上内容参考:

http://guides.rubygems.org/rubygems-basics/

正确使用label标签

表单中使用 checkbox 的时候,经常见到这样这样的写法:

1
<input type="checkbox"> Click Me!

这种写法选择的时候只能点击复选框,如果要实现点击文字“Click Me!” 也能进行选择操作,应该这么写:

1
<label><input type="checkbox"> Click Me!</label>

或者

1
2
<input type="checkbox" id="ckbx">
<label for=ckbx">Click Me!</label>

我有强迫症,看到项目中不规范的写法就忍不住会给改过来,在一次内部分享中我专门分享了这点,但是还有人这么写,抓狂!

偶然一次发现京东商城的登陆页面有个“自动登录”的checkbox,点击文字的时候就没有选中,每次上京东都会去点一下看改过来没有,即使自动登录了我也会退出重新登陆,持续了快一年了……

Rails 导出CSV

rails项目中经常有生成Excel文件需求,完成这一功能的可选插件也很多,比较常用的有 roo ,spreadsheet 等,如果遇到导出大量数据的场景,这些插件就捉襟见肘了,捉襟见肘 因为速度实在无法忍受。比较好的解决法案是生成csv文件,这样做的好处是文件体积小,生成速度快,不受行数限制,此外csv文件可以用excel打开。

注意点:

1 导出的UTF-8格式的csv直接用excle打开会出现乱码,需要进行转码操作,如果在导出之前转码,速度也很慢,比较好的做法是生成以后再转码(可以用windows的文本编辑器另存为ANSI编码)。

2 尽量避免将大量数据读取到ruby对象中,应该使用find_each方法,:batch_size参数默认是1000,这个值的设置对速度也有很大影响,我笔记本测试350较快,应该和机器配置User对象复杂程度等有关,需要测试。

1
2
3
User.find_each(:start=>5000,:batch_size => 350) do |u|
  # do something
end

3 生成的csv的时候注意设置分隔符,目的是方便用excel直接打开

1
2
3
4
5
6
CSV.generate(file_path, clo_sep = "\t", row_sep = "\r\n") do |data|
  data << ["姓名","电话"]
  Users.find_by_sql(sql).each do |user|
    data << [user.name,user.phone]
  end
end

下面是从网上找到一个现成例子,使用了 fastercsv 生成csv:

在String类中增加一些转换字符集的方法,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
class String
  def utf8_to_gb2321
    encode_convert(self, "gb2321", "UTF-8")
  end

  def gb2321_to_utf8
    encode_convert(self, "UTF-8", "gb2321")
  end

  def utf8_to_utf16
    encode_convert(self, "UTF-16LE", "UTF-8")
  end

  def utf8?
    begin
      utf8_arr = self.unpack('U*')
      true if utf8_arr && utf8_arr.size > 0
    rescue
      false
    end
  end

  private
  def encode_convert(s, to, from)
    require 'iconv'
    begin
      converter = Iconv.new(to, from)
      converter.iconv(s)
    rescue
      s
    end
  end
end
导出CVS,
1
2
3
4
5
6
7
8
9
10
11
12
13
14
def export_csv
  require 'fastercsv'
  records = Amodel.find(:all, :limit => 10)
  csv_string = FasterCSV.generate(:col_sep => "\t", :row_sep => "\r\n") do |csv|
    csv << ['field_name1', 'field_name2', 'field_name3']
    records.each do |r|
      csv << [r.field1, r.field2, r.field3]
    end
  end

  File.open("export.csv","w") do |file|
    file.syswrite "FFFE".gsub(/\s/,'').to_a.pack("H*") + csv_string.utf8_to_utf16
  end
end

railscasts中有两个视频可以供学习:

http://railscasts.com/episodes/362-exporting-csv-and-excel?autoplay=true

http://railscasts.com/episodes/396-importing-csv-and-excel?autoplay=true

其他资料:

http://hlee.iteye.com/blog/356507

如何制作gem包

Rails 支持多种形式的拓展,像plugin、gem或者干脆直接将通用工具类代码放置到lib目录下。plugin已经不推荐使用了,目前来看,最好的方式就是写成gem,本文是我学习gem制作整理的笔记,文中以手动添加一个helper方法为例。

第一步:安装 bundler

首先通过 gem list 命令查看如果已经安装了bundler就可以跳过此步。

安装命令:

1
gem install bundler

第二步:使用 bundler 生成一个基础gem结构

1
bundle gem my_gem

执行以后会看到以下输出:

create  my_gem/Gemfile
create  my_gem/Rakefile
create  my_gem/LICENSE.txt
create  my_gem/README.md
create  my_gem/.gitignore
create  my_gem/my_gem.gemspec
create  my_gem/lib/my_gem.rb
create  my_gem/lib/my_gem/version.rb
Initializating git repo in /home/ivan/private/my_gem

说明:

  1. my_gem.gemspec 文件相当于gem的说明书(specification),其中定义了Gem的内容、作者、描述、主页等信息。将来打包的时候会依赖这个文件。

  2. Gem的代码主要放置在lib目录下。

  3. 整个项目加入了Git版本控制。

  4. 如果gem本身需要引入其他依赖的包,需要在.gemspec文件中指明例如:

    spec.add_development_dependency "rake" 引入开发依赖

    spec.add_development_dependency "rails" 引入运行依赖

  5. 项目中有Gemfile文件,可将其中的 source 替换成淘宝源 “http://ruby.taobao.org”。

  6. 另外,在Gemfile有一行内容是”gemspec”,表明该项目依赖的gem包在.gemspec文件中指出,这就解释了为什么会有上面第4条。

  7. my_gem/lib/my_gem/version.rb 文件中可以填写gem的版本信息。

第三步:编写gem要实现的功能

这里我们实现一个helper方法,在页面输出一段Html代码。

  1. 新建文件 helper.rb , 路径: lib/my_gem/helper.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# coding: utf-8
module MyGem
  module MyHelper
    def my_helper
      time = DateTime.parse(Time.now.to_s).strftime('%H:%M:%S').to_s
      date = DateTime.parse(Time.now.to_s).strftime('%Y-%m-%d').to_s
      html =  []
      html << '<div id="mydiv">'
      html << '<div id="time">' + time + '</div>'
      html << '<div id="date">' + date + '</div>'
      html << '</div>'
      raw html.join("\n")
    end
  end
end
  1. 引入刚才写的helper

修改 lib/my_gem.rb 文件,首行添加:

1
require "my_gem/helper"
  1. 将helper正真拓展到rails中去

修改 lib/my_gem.rb 文件,尾行添加:

1
ActionView::Base.send :include, MyGem::MyHelper

第四步:提交代码

将项目提交到Git仓库,用到的命令:

git add *

git commit -m "finish my gem"

这一步很重要,因为在.gemspec文件中有这么一行:

1
spec.files         = `git ls-files`.split($/)

它调用了 git ls-files 命令来获取需要打包的文件,而这一命令只会返回Git仓库中的所有的文件,如果我们不提交代码那么项目中新建的文件就不会被打包进来。

第五步:打包

在项目下执行命令 gem build my_gem.gemspec

WARNING:  no homepage specified
  Successfully built RubyGem
  Name: my_gem
  Version: 0.0.1
  File: my_gem-0.0.1.gem

这里有一个警告,提醒我们填写homepage,这里只是练习不做理会。

第六步:使用

使用方法和其他gem包一样,需要注意的是我们的gem包并没有发布到rubygems.org,所以 gem install 的时候在my_gem-0.0.1.gem 文件所在的目录执行就ok了。

  1. 安装: gem install my_gem-0.0.1.gem

  2. 在rails项目的Gemfile中添加 gem "my_gem"

  3. 在rails项目下运行命令 ‘bundle’

  4. 在erb页面直接调用: <%= my_helper %>

PostgreSQL 常用函数

一 常用数学操作符

%    模      5 % 4      1
^    幂      2.0 ^ 3.0  8
|/   平方根  |/ 25.0     5
||/  立方根  ||/ 27.0    3
!    阶乘    5 !        120
!!   阶乘    !! 5       120
@    绝对值   @ -5.0     5

二 常用数学函数

取绝对值: abs()

1
select abs(-5); -- 5

求余数: mod(x,y)

1
select mod(5,4); --1

平方根: sqrt()

1
select sqrt(4); -- 2

立方根: cbrt()

1
select cbrt(8); --2

随机数: random(), 0.0 到 1.0 之间

1
select random(); -- 0.527410356327891

不小于参数的最小的整数: cell()

1
select cell(-42.8); -- -42

不大于参数的最大整数: floor()

1
select floor(-42.8); -- -43`

三 字符串函数

字符串连接: string || string

1
select 'ruby' || 'china' ; -- rubychina
Continue reading →

PostgreSQL 字段分割分组

原始: 在import_products中的location_prices字段存储内容:

 id  | location_prices  
-----|---------------------
  1  | 北京:200.0;河南:100.0
  2  | 河南;100.0
1
2
3
4
5
select id ,
  split_part(unnest(string_to_array(location_prices,';')),':',1) area_name,
  split_part(unnest(string_to_array(location_prices,';')),':',2) price
from import_products
where id in (542796,542797)

结果:

 id  | area_name | price  
-----|-----------|-------
  1  |    北京    | 200.0
  1  |    河南    | 100.0
  2  |    河南    | 100.0

知识点:

1. string_to_array

string_to_array函数的作用是将string类型的字符串分割成数组。

1
select string_to_array('i|love|you','|') ;  -- {i,love,you}

2. unnest

unnest 函数的作用是将数组转换成行。

1
select unnest(array['i','love','you']);
unnest  
-------
  i
 love
  you

3. split_part

split_part 函数作用是将字符串按照另一个字符串进行分割,并返回分隔以后的

1
select split_part('i||love||you', '||', 2);` -- love

Rails中操作Sqlite3数据库速度慢的问题

项目中要将数据导出到sqlite数据库中,但是速度太慢了,无法接受:

1
2
3
4
5
6
7
8
9
10
11
(0.1ms)  begin transaction
/home/ivan/work/temp/packagetest/app/models/material_type.rb:7: warning: multiple values for a block parameter (0 for 1)
from /home/ivan/.rvm/gems/ruby-1.8.7-p371@rails304/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:192
(0.4ms)  insert into material_types(id,name,code,parent_id,created_at,updated_at) values ('40', '40_name','code', 40, 'Fri Nov 29 11:08:54 +0800 2013', 'Fri Nov 29 11:08:54 +0800 2013')
(317.6ms)  commit transaction

(0.1ms)  begin transaction
/home/ivan/work/temp/packagetest/app/models/material_type.rb:7: warning: multiple values for a block parameter (0 for 1)
from /home/ivan/.rvm/gems/ruby-1.8.7-p371@rails304/gems/activerecord-3.2.13/lib/active_record/connection_adapters/abstract/database_statements.rb:192
(0.4ms)  insert into material_types(id,name,code,parent_id,created_at,updated_at) values ('41', '41_name','code', 41, 'Fri Nov 29 11:08:54 +0800 2013', 'Fri Nov 29 11:08:54 +0800 2013')
(307.8ms)  commit transaction

每次最耗时的就是这个 commit transaction 了 居然要300ms左右。

网上查找原因:

SQLite 缺省为每个操作启动一个事务,所以成批插入的时候,每个插入操作都会在一个事务中执行:

这样的花1秒钟才能执行6个插入。如果把所有操作都放在一个事务中,速度能达到1秒几万条,完全不在一个数量级,于是寻求解决方法。

主要思路就是让多个插入操作在一个事务中进行,最后的解决方法是直接使用 SQLite3这个gem,而不通过active_record

方法介绍:

1 连接数据库:

1
@db = SQLite3::Database.open(@db_path) # 连接sqlite3数据库

2 配置

1
@db.results_as_hash = true

该项默认为false, 设置成true以后返回的结果集是hash结构的,以字段名称作为key,方便读取数据,否则返回一个数组。

3 执行SQL 语句:

1
2
3
4
sql = "insert into option (release_time, package_type, id, db_name, db_id) ..."
@db.execute sql
sql = "select * from posts where title=? and name=? "
@db.execute(sql, '标题','名称')

4 遍历结果集

1
2
3
@db.execute(sql, '标题','名称').each do |post|
  #...
end

注意:如果没有找到数据会抛出异常,需要自行处理一下。

5 在单个事务中批量操作

1
2
3
4
5
@db.transaction
100.times do |i|
  @db.execute("insert into post where name = 'name_#{i}' ")
end
@db.commit

或者

1
2
3
4
5
@db.transaction do
  100.times do |i|
    @db.execute("insert into post where name = 'name_#{i}' ")
  end
end

Ruby的Range类

Range 是ruby范围对象的类。范围对象是由范围操作符 ..或… 生成的。

.. 生成的范围对象包括终点值。

… 生成的范围对象不包括终点值。

1
2
1..3  # 表示 1、2、3
1...3 # 表示 1、2

Range的实例在内存中只存储了起点和终点,因此比数组更节省空间。

Range 的常用方法:

1.通过 to_a 方法可以将Range对象转换成数组:

1
2
('a'..'c').to_a   =>  ["a", "b", "c"]
(1..3).to_a       =>  [1, 2, 3]

2.迭代Range

1
(1..3).each{ |i| puts i } #依次输出 1、2、3

3.include?

1
('a'..'c').include?('b')

4.end 返回范围终点,与是否包含范围终点无关:

1
2
('a'..'c').end    => "c"
('a'...'c').end   => "c"

5.step(s) 以步长s进行迭代:

1
(1..10).step(2) {|v| p v}     =>  1, 3, 5, 7, 9

6.min 最小值

1
(1..10).min    => 1

7.max 最大值

1
(1..10).max    => 10

Ruby 小技巧之 $:

在一些gem里面经常会有这样一句代码:

1
$:.unshift File.expand_path('..', __FILE__)

这句话是干什么用的呢?

$: 就是ruby的一个全局变量,也叫$LOAD_PATH,功能就是java中的classpath,用来加载类库的,当你require某个文件时,ruby就会从这个变量的值去查找,找不到会报LoadError。这个值其实就是一个包含了类库绝对路径的数组。

__FILE__这个变量代表文件自己的文件名,在foo.rb中puts __FILE__,结果就是foo.rb。

File.expand_path可以把路径转换成绝对路径,假设有这样一个文件/Users/kenshin/foo.rb,里面有File.expand_path('..', __FILE__),返回的结果就是/Users/kenshin。

unshift是数组的一个方法,功能就是把指定的值加到数组的最前面,[3,4].unshift(1,2) => [1,2,3,4]

所以这段代码的意思就是把当前文件所在的目录加到ruby的loadpath的最前面,在require文件时,ruby就会先从当前目录下去查找了。