Help us understand the problem. What is going on with this article?

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

More than 3 years have passed since last update.

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

ncmb-ruby-client 0.0.6
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

ということで試しに 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章 ロード

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

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

第18章 ロード インターフェース
クエリ:$LOAD_PATH | るりまサーチ - Ruby

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コマンドの使い方まとめ

$ 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

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)." ってことらしい。

納得。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away