はじめに
Everyday RailsでRSpecの学習をしていたところ、rspec binstubという言葉が出てきました。
$ bundle binstubs rspec-core
上記コマンドにより、bin/rspecファイルが作成され、今までbundle exec rspecというコマンドがbin/rpsecのみで実行できるようになる。
と教材では書かれていたのですが、あまり理解出来なかったので掘り下げようと思います。
bundle execとは
まずは周辺知識から掘り下げたいと思います。
bundle execを使用することにより、Gemfile内のgemのバージョンに基づいてコマンドを実行できる。
bundle execをつけないと、システム共通のライブラリ保存場所にあるgemを使用するため、エラーが起きる場合がある。
bundle installしたgemの保存先
`~/.rbenv/versions/*/lib/ruby/gems/*/gems/インストールしたgem
binstubとは
例えばgem install rspec-coreをした時、Rubygemsは以下のものを用意してくれる。
- rubyバージョン/bin/rspec (RubyGems によって作られた binstub)
- rubyバージョン/lib/ruby/gems/*/gems/rspec-core-XX.YY/exe/rspec (オリジナル)
上記1は、上記2のファイルをラップするために作られたbinstub
そして、rbenvのコマンドであるrspecを実行した時、
shims → binstub → オリジナルの順にパスを探して実行する。
rspecのbinstubを作成
$ bundler binstubs rspec-core
#!/usr/bin/env ruby
# frozen_string_literal: true
#
# This file was generated by Bundler.
#
# The application 'rspec' is installed as part of a gem, and
# this file is here to facilitate running it.
#
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
bundle_binstub = File.expand_path("bundle", __dir__)
if File.file?(bundle_binstub)
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
load(bundle_binstub)
else
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
end
end
require "rubygems"
require "bundler/setup"
load Gem.bin_path("rspec-core", "rspec")
一番下の行のload Gem.bin_path("rspec-core", "rspec")によって、bin/rspecコマンドが呼ばれた際に、rspec-coreディレクトリのrspec実行ファイルが呼び出される?仕組みだと思います。
これにより、今まではbundle exec rspecコマンドでオリジナルのrspec実行ファイルを実行していたが、bin/rspecだけでオリジナルのrspec実行ファイルを呼び出すことができるようになっているのだと思います。
- また、./binのパスを通せば
rspecコマンドのみで実行できます
$ export PATH="./bin:$PATH"