首页 分类 关于我
ruby
Nginx 配置示例 工程师的产品观 理理File/Dir/Pathname(一) TracePoint介绍 ruby中的return 如何动态改变某个class的祖先链 ObjectSpace介绍 Rails日志实现探索(3) Rails日志实现探索(2) Rails日志实现探索(1) Rails中的request rescue exception in ruby 设计模式之观察者模式 require 的故事 ruby中的编码 研究ruby的一些小技巧 Rails中间件 ruby对象的序列化 ActiveSupport宝藏之MessageVerifier 如何写rakefile Ruby on Rails 环境及准备 基于Rack的项目初始化
git
如何移除某次提交之前的版本历史 Git 不常用的好用的命令 Git高级技巧之忽略文件
database
Mysql数据库编码 从mongodb向mysql迁移数据
工具
搭建ipsec服务
linux
Linux 常用查看命令

require 的故事

引子

关于require,一般我们接受到的知识是这样的:

在ruby中,require是位于Kernel模块中的一个方法。其方法参数接受一个文件名,如果文件名不是绝对路径,则会依次加入$LOAD_PATH中的路径依次查找,只到找到为止。如果没有找到文件,则会报一个LoadError错误。

下面我们来做个试验:

require 'a'

LoadError: cannot load such file -- a
from /Users/qin/.rbenv/versions/2.1.5/lib/ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require'

可是这个报错信息是怎么回事?

require并没有调用系统默认的Kernel#require,而是调用了位于rubygems中core/ext/kernel_require.rb中的Kernel#require函数。RubyGem用自己的require替代了系统默认的版本,并藉此实现了它自己的逻辑。

gem中的require

那gem中的require到底都做了些什么呢?当我们调用require 'a'的时候,如果能够在$LOAD_PATH 中找到这个文件,那require的任务就完成了。如果没有找到,require就会调用gem 'a',如果能够找到a这个gem,则将其加入$LOAD_PATH 中。

gem中的require源码中关于调用gem的部分:

def require path
  RUBYGEMS_ACTIVATION_MONITOR.enter

  path = path.to_path if path.respond_to? :to_path

  spec = Gem.find_unresolved_default_spec(path)
  if spec
    Gem.remove_unresolved_default_spec(spec)
    gem(spec.name)  # 在这里调用了gem这个方法
  end

  # ……后续代码省略
end

gem中的require源码中,当gem方法把当前gem的路径加入到$LOAD_PATH后,继续调用原始require方法的部分:

def require path
  # ……省略代码
  return gem_original_require(path)  # 本方法中有多处这样的调用,gem_original_require 是gem定义的原生的 require 方法的别名方法
  # ……省略代码
end

gem中的gem方法

代码胜千言。我们在调用gem方法之前看下$LOAD_PATH 都有啥:

# 进入irb
puts $:

# 返回结果如下
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/site_ruby/2.1.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/site_ruby/2.1.0/x86_64-darwin14.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/site_ruby
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/vendor_ruby/2.1.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin14.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/vendor_ruby
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/2.1.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/2.1.0/x86_64-darwin14.0

接下来我们调用一下 gem ‘rails’

gem 'rails'
# => true

然后我们再看看$LOAD_PATH 发生了什么变化

/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/i18n-0.7.0.beta1/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/thread_safe-0.3.4/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/tzinfo-1.2.2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activesupport-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rack-1.6.0.beta/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rack-test-0.6.2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/mini_portile-0.6.0/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/extensions/x86_64-darwin-14/2.1.0-static/nokogiri-1.6.3.1
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/nokogiri-1.6.3.1/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/loofah-2.0.1/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rails-html-sanitizer-1.0.1/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rails-deprecated_sanitizer-1.0.3/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rails-dom-testing-1.0.3/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/builder-3.2.2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/erubis-2.7.0/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/actionview-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/actionpack-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activemodel-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/arel-6.0.0.beta1/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activerecord-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/globalid-0.3.0/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/activejob-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/actionmailer-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/thor-0.19.1/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/railties-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/bundler-1.7.7/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/sprockets-rails-3.0.0.beta1/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/gems/2.1.0/gems/rails-4.2.0.beta2/lib
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/site_ruby/2.1.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/site_ruby/2.1.0/x86_64-darwin14.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/site_ruby
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/vendor_ruby/2.1.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin14.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/vendor_ruby
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/2.1.0
/Users/qin/.rbenv/versions/2.1.5/lib/ruby/2.1.0/x86_64-darwin14.0

多了好多内容,不仅把rails本身加入到了$LOAD_PATH中,还加入了rails依赖的其他gem,这下就可以愉快的使用 require 了。

© 2018 www.xinshengyin.com All rights reserved.

版权所有