Ruby 基础篇之如何山寨 require 和 load

 

Shanzhai

前几天被一个初学 Ruby 的同学问及 require 和 load 有什么区别。后来想想这个问题虽然答案并不难,但是还可以引申出不少可以探讨的内容。所以我打算通过山寨一个 require 和 load 的方法的形式,来阐述一些内容。

在开始之前我们首先假设我们有一个 person.rb 文件,内容如下:

class Person

  attr_reader :name, :age

  def initialize(name, age)
    @name = name
    @age = age
  end

  def to_s
    "My name is #{name} and I'm #{age} years old!"
  end

end

person = Person.new("金将军", 30)
puts person.to_s

先来山寨 load

先让我们来做做试验。

# -*- coding: utf-8 -*-
# try_load_require.rb

load './person.rb'
load './person.rb'

$ ruby try_load_require.rb
My name is 金将军 and I'm 30 years old!
My name is 金将军 and I'm 30 years old!

我们这里调用了 两次 load ,发现 person.rb 被调用了两次。这说明 load 是不会判断文件是否已经加载,只是简单的加载并运行了内容。

换言之我们可以自己山寨一个 load 方法来达到同样的目的:

# -*- coding: utf-8 -*-
# try_load_require.rb

def load(file_with_path)
  puts "这是山寨load()"
  eval File.read(file_with_path)
end

load './person.rb'
load './person.rb'

其实如果你细心看过 load 方法的文档的话你会发现 load 实际上是可以接受第二个参数的,并且这个方法的返回值恒定为 true

load(filename, wrap=false) #=> true

wrap 参数到底有什么用?我们需要重新来做一个试验:

# -*- coding: utf-8 -*-
# try_load_require.rb

def check_person_defined
  begin
    puts "Person class is defined" if Person
  rescue NameError
    puts  "Person class is not defined"
  end
end

load './person.rb', true
check_person_defined

load './person.rb'
check_person_defined

而输出结果是:

ruby try_load_require.rb
My name is 金将军 and I'm 30 years old!
Person class is not defined
My name is 金将军 and I'm 30 years old!
Person class is defined

这说明当我们调用 load 时把第二个参数设为 true,虽然执行了 person.rb 的代码,但是 Person 的定义并不能在当前作用域起作用。那可以通过在一个匿名的作用域来执行person就可以达到相同效果了。所以我们可以继续做更完整的做如下山寨:

def load(file_with_path, warp = false)
  puts "这是山寨load()"
  if warp
    Module.new.module_eval(File.read(file_with_path))
  else
    eval File.read(file_with_path)
  end
  true
end

接下来山寨 require

用同样的方法我们来测试一下 require

# -*- coding: utf-8 -*-
# try_load_require.rb

require './person.rb' #=> true
require './person.rb' #=> false

而输出结果是:

$ ruby try_load_require.rb
My name is 金将军 and I'm 30 years old!

这说明 require 是会判断文件是否已经被加载,如果被加载的话是不会再进行重复加载的。并且第一次加载成功会返回 true,如果判断为重复加载会返回 false。

知道这个简单的规则后,我们就可以做如下山寨了并且会用到我们刚刚的山寨 load 哟 🙂

$required_files = []

def require(file_with_path)
  puts "这是山寨require()"
  full_path = File.expand_path(file_with_path)
  if $required_files.include?(full_path)
    return false
  else
    $required_files << full_path
    load(full_path)
    return true
  end
end

怎么样, 简单吧? 希望通过这个简单的山寨能让初学的朋友能更好的理解和记忆 require 和 load 的区别。

那什么时候用 load 什么时候用 require 呢?在大多数情况下我们都是使用 require 的。但是有些时候需要多次加载一个变化的文件,比如像 Rails 的 development 模式的 server 启起来以后,需要再次加载改变的源文件那么就需要用到 load (或者 autoload, 以后会谈到)。

以后我还会写一系列的针对 Ruby 基础知识的文章,敬请期待哟. 🙂

BTW, 最近我建立了一个 Ruby/Rails 学习QQ群 231618869,学习 Ruby/Rails 的同学可以在这里交流经验和你遇到的问题哟。

Buy It

在我人生中我不幸的失去过很多软件。

比如当年的仙剑奇侠传(最初的狂徒工作室,因为仙剑销量不佳解散):

又比如后来的 QuickSilver(以前是收费的,由于购买正版的用户并不多,作者将其开源了。)

然后是即将逝去的Google Reader.

这不经会让我想到这是为什么?下一个又是谁呢?每次想到这种问题,我总是会不寒而栗。我能不能阻止我喜欢的软件就在我面前这样死掉?

思来想去我得出了两个结论:

  1. Choose a right one
  2. Buy it

Choose a right one

选择一个正确的软件,我相信每个人一定有自己不同的标准。我在此只想从软件的商业模式上来考虑一下软件的选择的问题。

什么?作为用户居然要思考软件的商业模式?

是的,为了避免惨剧的再次发生,你必须要思考这个问题。

我这里就以Google Reader为例,其实我想你和我一样知道,Google Reader基本是没有什么盈利模式的。首先它不收钱,其次它偶尔有段时间放了点几乎没人点的广告在不显眼的地方。归根结底,它是一个靠其他项目养着的项目。如果这种项目出自一个Google这样的上市大型公司,那么它迟早都会被关掉。

为什么?大公司不是不缺钱吗?Google运营个Reader怎么了?

我已经不止一次的听到过Google不缺钱,Google是个有着理想主义色彩的公司的论调了。其实我想说,一个上市公司的唯一理想就是(也应该是)让股东利益最大化。一切和这个背道而驰的理想都应该砍掉。和你现在公司缺不缺钱根本就不应该有关系。所以Google砍掉Reader理所当然,要怪只能怪我们当时没选对,或者说他没给我们机会付他钱。

那么我们假设一下,如果是一个3-5个人的精英小团队在运营Reader呢?或许他们的唯一理想就是让这个服务每天更好用一些,每天更稳定一些(而不是要去搞一个和Facebook一样的社交网络)。但是作为代价,他们必须每月向你收取少许的费用。如果这样你会使用这个服务吗?真若如此,会不会避免今天的惨剧?

在我看来盈利模式清晰的软件才是值得使用的,如果你都能想到你打算使用的软件没法赚钱,那么你应该重新考虑你是否做出了一个正确的选择。(公益和部分开源软件除外)

什么才叫盈利模式清晰?

我听过一句很经典的话,一切商业的本质就是 “Buy for a dollar, sell for two.”

其他任何形式的盈利模式都逃不过这个本质,而很多眼花缭乱的其他模式听起来总是让人头痛。

所以其实在我看来最清晰的商业模式就是最贴近本质的模式,他们给你软件,你付他们钱。

Buy it

如果我们使用Google Reader真是我们选择不当,活该我们伤心,那么仙剑和QuickSilver的例子怎么解释?

盈利模式清晰的软件也有可能挂掉。没有什么一定可行的方法可以让一个软件永远长青。

但是我知道一个相对朴素,直接且很有效的方法那么就是 “Buy it”!

在人们进入共产主义社会之前,我不认为有比这个更好的方法。:)

如果你喜欢一个软件或者服务,那么你能做的最好的事情就是买他。

如果你喜欢一个开源或者免费的项目,你可以试着给他们捐钱。

最后祝愿你喜欢的软件长青。