gem の実行可能ファイルは exe に保存する
作った gem をビルドしていざ実行しようとしても、 Command not found が返された。解決法が分かったのでシェア。
Bundler で作っている。バージョンは1.8.2
。
作った gem の構成
├── Gemfile ├── Gemfile.lock ├── README.md ├── Rakefile ├── sample-gem.gemspec ├── bin │ ├── sample-gem │ ├── console │ └── setup ├── lib │ ├── sample-gem │ │ ├── arguments.rb │ │ ├── client │ │ │ ├── base.rb │ │ │ ├── google.rb │ │ │ └── tumblr.rb │ │ ├── command.rb │ │ ├── command_builder.rb │ │ ├── image.rb │ │ └── version.rb │ └── sample-gem.rb └── pkg └──sample-gem-0.0.1.gem
sample-gem という名前の gem で、実行ファイルは慣習に沿ってbin
ディレクトリに gem と同名で作成している。
あなたの実行ファイルは bin に設置するべき設定ですか
sample-gem.gemspec
を見よう。ここに実行できなかった原因はある。
...... spec.license = "MIT" spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) } spec.bindir = "exe" spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) } spec.require_paths = ["lib"] spec.add_development_dependency "bundler", "~> 1.8" ......
注目してほしいのは spec.bindir
と spec.exectables
である。この設定では、exe
ディレクトリ以下にあるファイルをすべて実行ファイルとして認識する。これは Bundler v1.8.2
ではデフォルトで生成される gemspec だ。
bundler/newgem.gemspec.tt at master · bundler/bundler
作った gem は bin
ディレクトリ に実行ファイルを置いていたため、ここで設定が食い違っているのだ。
というわけで修正
sample-gem.gemspec
...... spec.bindir = "bin" spec.executables = ['sample-gem'] ......
spec.bindir
は bin
を指定し、spec.executables
は実行させたいファイル名を配列で記述する。これで解決した。
なぜデフォルトでは exe を指定しているのか
そのへんの理由はここに書いてある。
move gem bins to exe/ and add console and setup · ab3e217 · bundler/bundler
it's a suggestion for new gems, not a suggestion to move your current binaries. old gems will keep working the way they always have. the reason is that rails, bundler, and the gem itself all want to use bin/ for scripts that are specific to the given repository, and rubygems bins are not usable directly. you could even create a bin/my-command for development if you want, while keeping the command that will ship inside your .gem file in exe/.
rubygems が bin
を見てることはないし、bin
は setup
や console
といった開発の際に使うファイルを置きたい。あなたが作った executables なコマンドは exe で面倒見ようよ。って感じ。spec.executables
を仮に spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
と bin
ディレクトリすべてを見ることにすると setup
や console
までコマンドとしてしまうから困った、ならこうしよう。って感じの改変だと思う。
まとめ
実行できない時はgemspec
の spec.bindir
, spec.executbles
をチェック。
これからは、実行ファイルは exe
に入れるべきですな。