Ruby 普段特に何も考えずに使っていた require について調べてみた

nifty の mobilebackend の API を Ruby で使う際、require で気づきがあったのでメモ。※結論はふんわりしてます。
mobilebackendAPI を Ruby で便利に使うためのライブラリ ncmb-ruby-client を install 。

[ncmb-ruby-client 0.0.6](https://rubygems.org/gems/ncmb-ruby-client)
[moongift/ncmb-ruby-client](https://github.com/moongift/ncmb-ruby-client)

簡単なテストコードを書いてみる。

```hoge.rb
require 'ncmb-ruby-client'

class NiftyMbaas
  NCMB_APP_KEY = 'hogehoge'
  NCMB_KEY = 'hogehogehoge'

  def initialize
    NCMB.initialize application_key: NCMB_APP_KEY,  client_key: NCMB_KEY
    @client =  NCMB::Client.new application_key: NCMB_APP_KEY,  client_key: NCMB_KEY
  end

  def hogehoge
    p @client
  end
end

nm = NiftyMbaas.new
nm.hogehoge
```

こんなエラーが出る。

```
/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby/2.1.0/rubygems/core_ext/kernel_require.rb:55:in `require': cannot load such file -- ncmb-ruby-client (LoadError)
```
ncmb-ruby-client を load できてないとエラーが出る。
gem install できているか確認してみる。

```
gem list | grep ncmb                                                                                                  
ncmb-ruby-client (0.0.6)
```
できているー。ということでgithubを確認。examples ファイルをよく見てみると ncmb のみで require している。

```data_store.rb
$:.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
$:.unshift(File.dirname(__FILE__))
require 'rubygems'
require 'ncmb'
require 'yaml'
yaml = YAML.load_file(File.join(File.dirname(__FILE__), '..', 'setting.yml'))
NCMB.initialize application_key: yaml['application_key'],  client_key: yaml['client_key']
@todo = NCMB::DataStore.new 'TestClass'
@todo = @todo.limit(20).count(1).skip(0)
# @todo = @todo.where(testKey: "testValue")
# puts "@todo[0] #{@todo[0]}"
puts "@todo[0].name #{@todo[0].message}"
```

[ncmb-ruby-client/examples/data_store.rb](https://github.com/moongift/ncmb-ruby-client/blob/master/examples/data_store.rb)

ということで試しに ncmb で require してみると上手くいく！


```
#<NCMB::Client:hoge @domain="mb.api.cloud.nifty.com", @api_version="2013-09-01",@application_key="hoge", @client_key="hogehoge">
```

ということで調べてみると、require はこんな特徴があるらしい。

1. ロードパスからファイルを探してくる
2. 拡張ライブラリもロードできる
3. 拡張子.rb/.soを省略できる
4. 同じファイルは二度以上ロードしない

[第18章 ロード](http://i.loveruby.net/ja/rhg/book/load.html)

今までは require は gem を require してきているイメージだったが、gem の中にある拡張子.rb/.so 等のファイルを探してきているみたいだ。先ほどの gem を見てみると、 ncmb-ruby-client.rb は無いが、ncmb.rb は lib の中にある。よく使うライブラリの nokogiri を見てもやはり nokogiri.rb がある。だんだんわかってきた。

そこでもう少しきちんと理解するためにロードパスについても調べてみた。

[第18章 ロード インターフェース](http://i.loveruby.net/ja/rhg/book/load.html)
[クエリ:$LOAD_PATH | るりまサーチ - Ruby](Kernel$$LOAD_PATH -> [String])

> Rubyライブラリをロードするときの検索パスです。

どうやら require するとロードパスを順番に探していくらしい。

```hoge.rb
p $LOAD_PATH
p $:
#=>/usr/local/Cellar/rbenv/HEAD/rbenv.d/exec/gem-rehash
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby/2.1.0/x86_64-darwin15.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin15.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/2.1.0/x86_64-darwin15.0
```
とかで確認できる。で、これを順番に探していったのだが、なかなか探しているファイルが見つからない。nokogiri.rb でも ncmb.rb でも見つからない。で、今度はロードパスではなく、gemの場所で検索してみると、gem enviroment コマンドについての記事を見つけた。

[【Ruby】Gemコマンドの使い方まとめ](http://www.task-notes.com/entry/20150113/1421118000)

```
$ gem environment 
RubyGems Environment:
  - RUBYGEMS VERSION: 2.6.2
  - RUBY VERSION: 2.1.4 (2014-10-27 patchlevel 265) [x86_64-darwin15.0]
  - INSTALLATION DIRECTORY: /Users/home/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0
  - USER INSTALLATION DIRECTORY: /Users/home/.gem/ruby/2.1.0
  - RUBY EXECUTABLE: /Users/home/.rbenv/versions/2.1.4/bin/ruby
  - EXECUTABLE DIRECTORY: /Users/home/.rbenv/versions/2.1.4/bin
  - SPEC CACHE DIRECTORY: /Users/home/.gem/specs
  - SYSTEM CONFIGURATION DIRECTORY: /Users/home/.rbenv/versions/2.1.4/etc
  - RUBYGEMS PLATFORMS:
```

ここでハマる。gem environment で出てくる path と $LOAD_PATH で出てくる path が違う。
ぐぐってもわからないのでいろいろいじっていると、require で何かを呼んだときのロードパスとただロードパスを読んだ時に表示されるリストが違うことに気づく。

```hoge.rb
puts $LOAD_PATH
#=>/usr/local/Cellar/rbenv/HEAD/rbenv.d/exec/gem-rehash
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby/2.1.0/x86_64-darwin15.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin15.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/2.1.0/x86_64-darwin15.0
```

```hoge.rb
require 'nokogiri'
puts $LOAD_PATH
#=>/usr/local/Cellar/rbenv/HEAD/rbenv.d/exec/gem-rehash
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/mini_portile2-2.0.0/lib
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/nokogiri-1.6.7.2/lib
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/extensions/x86_64-darwin-15/2.1.0-static/nokogiri-1.6.7.2
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby/2.1.0/x86_64-darwin15.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/site_ruby
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby/2.1.0/x86_64-darwin15.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/vendor_ruby
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/2.1.0
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/2.1.0/x86_64-darwin15.0
```

```hoge.rb
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/mini_portile2-2.0.0/lib
#=>/Users/home/.rbenv/versions/2.1.4/lib/ruby/gems/2.1.0/gems/nokogiri-1.6.7.2/lib
```

なんか増えてるー。で、最終的にある程度しっくり来る記事を見つけた。

[module Kernel](http://docs.ruby-lang.org/en/2.1.0/Kernel.html#method-i-require)

>require(path)
When RubyGems is required, #require is replaced with our own which is capable of loading gems on demand.

>When you call require 'x', this is what happens:

>- If the file can be loaded from the existing Ruby loadpath, it is.

>- Otherwise, installed gems are searched for a file that matches. If it's found in gem 'y', that gem is activated (added to the loadpath).

>The normal require functionality of returning false if that file has already been loaded is preserved.

>Also aliased as: gem_original_require

"the existing Ruby loadpath" からロードできる場合はするが、それ以外は "installed gems are searched for a file that matches. If it's found in gem 'y', that gem is activated (added to the loadpath)." ってことらしい。

納得。