書いたソースコードをgem にして自分で使いたい。
自分で書いたソースコードを再利用するために gem の仕組みを活用し、再利用する。
目標
自分の git ライブラリを読み込み活用する。
必要なもの
手順
- gemspec を作って、git に設置する。
- 自分のソースコードをgitにおく
- 使う側のGemfileを作る
- bundle installで gitから取得する。
rubygem以外からのインストール方法
ざっと調べた限りでは、使いやすそうな2つの方法が見つかります。path:
でパスを指定する、git:
でgitレポジトリを指定する。この2つです。
方法1 path:で指定
同一サーバー内であれば、これも快適です。git:
を使う前のチェックにも使えます。
gem 'my-libs', path:'/path/to//my-libs'
方法2 git から取得する方法
git 経由(SSH / HTTPS / PATH ) で gitを使って取得します。
gem 'my-libs', git:'ssh://git@gitlab.example.tld:/takuya/my-libs.git
git 経由では、HTTPS/SSHのよく使う指定以外に、PATHで指定も可能です。
gitをローカルパスで指定する例
gem 'my-libs', git:'/home/takuya/my-libs'
それでは自分のソースコードを、ライブラリとして再利用可能にするにはどうすればいいのでしょうか。それはgemspecファイルを使います。
gemspec
から、gems
が作られます。作成されたgemsがbundle install
によって、プロジェクトに取り込まれます。これにより再利用が可能になるわけです。
gemspec の例。
require_relative "lib/version"
Gem::Specification.new do |spec|
spec.name = "my-libs"
spec.version = Takuya::MyLibs::VERSION
spec.authors = ["takuya"]
spec.bindir = "bin"
spec.require_paths = ["lib"]
end
gemspec
を使わずとも、ライブラリを再利用することも可能ですし、gemを作成することも可能。LOAD_PATHをカスタマイズしてもいいです。
ですが、gemspecを使って考えることを減らし、メジャーな方法に倣うことで検索性が向上します。最初にちょっと時間をかけたほうが、最終的には時短になると思います。
gemspec の作成
自分のソースコードをライブラリにするためには、gemspecが必要です。gemspecファイルをゼロから書いていたら大変です。そこで便利なコマンドが用意されています。
bundle gem my_gem_name
名前は、snake_caseで記載するといいでしょう。
snake_case
で記載すると、module SnakeCase
が作られます。
cabab-case
で記載すると、module Cabab::Case
が作られます。
このコマンドでmy_gem_name.gemspec
が作成されます。ファイルには、雛形が書かれています。TODO
箇所はご自身の記入箇所です。
雛形のTODO
は、https://rubygems.org/
に公開に必要な項目です。ライブラリを自分で使うだけなら、記入は不要です。
インポートに、最低限必要な項目は、次のとおりです。
spec.name = "my_libs"
spec.version = '1.0'
spec.summary = 'Example for import personal library'
spec.authors = ["takuya"]
次の設定項目は重要です。(必須ではありませんが、書いたほうがいいでしょう)
spec.require_paths = ["lib"]
これらの最低限の項目がgemspecに記載されていれば bundle install
で使うことができます。ご自身で使うだけなら、最低限の記入でも問題ありません。
もしrubygems.org に公開を目標にしているなら、詳細な記入が必要です。
自作ライブラリを参照する方法
冒頭に述べたとおり、アプリケーションから自分のライブラリを再利用するときは、対象の参照をGemfile
に記入します。
Gemfileサンプル
gem 'my_libs', path:'../my_libs'
Gemfileを書いたら準備完了です。
Gemfile
の内容をbundle install
します。
bundle インストールしたら、Gemfile.lock
へ実際のインストール先が記入されます。
path: でインストールした場合
:path
はちょっと特殊(?)です。Gemfileで、:git
を使わずに :path
で参照した場合はbundleはソースコードのコピーをプロジェクトに作りません。
:path
でインストールしたら、$LOAD_PATH
に該当ディレクトリ
が追加されます。
ruby のLOAD_PATH の確認
puts $LOAD_PATH
$LOAD_PATH
を見ると、:path
で指定したgemspecにPATHが通されているのがわかります。
ライブラリ側のgemspecにspec.require_paths=['lib']
を記入しておくと、spec.require_paths で指定したPATH値(ここでは["lib"]
) がPATHに追加されていることでしょう。
: path
指定はGemfie.lockに
Gemfileの:path
記載で$LOAD_PATH
の書き換え処理が行われますが、bundleインストール後は、Gemfile.lock
に記載されています。
Gemfile.lock のPATH記載の例。
PATH
remote: /Users/takuya/Desktop/my_libs
specs:
my_libs (0.0.1)
path
を使うと上記のように、Gemfile.lock にPATHが記載されます。gem自体はvendorにコピーされない
という点は心に留めておきましょう。
実際にやってみます。
ここまで概要がわかれば、実際にやってみます。
ライブラリ作成する。
bundle gem my_libs
ライブラリ用のパッケージ一式が生成されます。
最低限必要なもの以外を消す。
最低限必要なファイル以外を削除する。動作をわかりやすく。
rm -rf CODE_OF_CONDUCT.md Rakefile bin/ sig/ README.md
gemspec の作成
こちらも、最低限必要なgemspecを書きます。
echo '# frozen_string_literal: true
require_relative "lib/my_libs/version"
Gem::Specification.new do |spec|
spec.name = "my_libs"
spec.version = MyLibs::VERSION
spec.summary = "Example for import personal library"
spec.authors = ["takuya"]
spec.require_paths = ["lib"]
end' > my_libs.gemspec
ライブラリ作成します。
my_libs/lib/my_libs.rb
require_relative "my_libs/version"
module MyLibs
class Error < StandardError; end
def self.greetings
puts "hello from my libs"
end
end
なにか関数を作っておきます。
git に保存して、レポジトリへ
ライブラリの動作を確認を終えたら、git commit
と git push
を実行します。
git remote add origin git@gitlab.example.tld:takuya/my_libs.git
git commit -am initial
git push origin master
git に push してサーバーに保存します。
ライブラリを利用する
ライブラリを使うプロジェクトを生成する。
bundle gem sample_app
cd sample_app
こちらも、最低限の必要なファイル以外を削除し、動作を明確にします。
rm -rf CODE_OF_CONDUCT.md Rakefile bin/ sig/ README.md sample_app.gemspec
gemspec で指定も可能なのですが、今回はGemfileを使います。
PATHを使ってインポートテスト。
一番シンプルなLOAD_PATHを使ったインポートを試しておきます。
echo "# frozen_string_literal: true
source "https://rubygems.org"
gem 'my_libs', path:'../my_libs'
" > GemFile
mylibs のgem をインストールします。
bundle install
ここまが動いたら、準備(gemspec作成)に問題なしと確認できます。
PATHインストールがうまく行ったら、次に備えsample-appのインストール状態を初期化し直します。
rm Gemfile.lock
rm vendor -rf
もしエラーになったら、my_libsのgemspecを見直しましょう。
冒頭に述べたとおり、path:
はLOAD_PATHの追加です。my_libsソースにシンタックス・エラーがあろうとも、path:
を使うと検出が行えません。注意してください。
git を使ったインポート
ライブラリをgitでインストールします。ただし、https:/git:
はまだ使いません。
git をパス参照(ローカルパス)で利用します。
git + path でインストール設定を書きます。
Gemfile
gem 'my_libs', git:'../my_libs'
インストールしてテスト
インストール、動作チェックします。
bundle install
プロジェクトのvendorにコピーされているか、確認します。
ls vendor/bundle/ruby/*/bundler/gems/my_libs*/
もしエラーになる場合は、vendorを一度消してみてください。
rm -rf vendor
それでもエラーに場合は、mylibs 側でコミット忘れかもしれません。commitを確認してください。
cd ../mylibs
git st
gti commit -am update
cd ../sample_app
rm -rf vendor
bundle install
これで、git コマンド経由のインストールの完成です。
インストールができたら、Gemfile.lock を確認してみます。
cat Gemfile.lock
Gemfile.lock
GIT
remote: ../my_libs
revision: 6f50e23037f26f03cbXXXXXX
specs:
Gemfile.lock
にはgit のコミット番号(ハッシュ値)が記載されていることがわかります。
今回はバージョンを指定してないので、デフォルト・ブランチのコミット番号(ハッシュ値)が識別に利用されています。
最後に、http経由のインストールにします。
これで、ライブラリ作成・保存、Gemfileでのgitインストールが出来ました。最後に、ローカル・パス参照を、リモート・サイトのGitレポジトリを参照に切替えます。
完成したmylibs をpush
cd ../mylibs
git add .
git commit -m fix
git push origin master
mylibsをhttp/ssh 経由で参照するようにする。
cd ../sample_app
echo '# frozen_string_literal: true
source "https://rubygems.org"
# Specify your gem's dependencies in sample_app-app.gemspec
gem "my_libs", git:"git+ssh://gitlab.example.tld/takuya/my_libs.git'
' > Gemfile
mylibsをインストールします。
bundle install
これで、自作のソースコードをGemfileで参照できます。
アップデートする場合
自作ライブラリにミスが見つかったら、オリジナルを修正してgit pushをします。そしてアップデートをかけます。
cd mylibs
vim lib/my_libs/my_libs.rb
git commit -am update
git push origin master
最新版を取得し直します。
cd sample_app
bundle update my_libs
バージョンやタグを未指定でGemfileを使うと、デフォルトブランチ(master / main)から取得するので、アップデートは常にレポジトリの最新版を取得なります。なのでシンプルです。
ただし、bundle update my_libs
のたびに、./vendor
に過去コピーが溜まっていくので注意が必要です。
以上でライブラリ作成が完成。
ライブラリ作成をし、gitからインストールすることで、自分のソースコード使い回すことが出来るようになり、よく使う処理や自分の癖をサポートするソース・コードをコピペせずに済みます。
まとめ
自分のソースコードライブラリ化してインストールする方法には、次の2つが選択肢になります。一つは、LOAD_PATH使う、もう一つはGemを使うです。
Gemを使う場合は、pathでLOAD_PATHを使うか、git を使う方法があります。
Gem と git を使う場合は、ローカル・パスか、リモート(https / ssh) を選ぶ事ができます。
つまりこうなります。
- LOAD_PATH
- gem git:
git://path/to/git/dir
git+ssh://git@example.tld:2222/takuya/repo.git
git+https://example.tld/takuya/repo.git
油断すると、少々ややこしいです。LOAD_PATHとgem path / gem git+pathが混乱しそうですが、落ち着いて考えるとすっきりわかる筈です。いちいちgit commit / git push しなくてもライブラリのインポート設定や動作チェックが出来るので知っておくと時短になります。
bundle gem で生成されるファイル
今回は使いませんでしたが、bundle gem が生成するファイルには役割があります。
- CODE_OF_CONDUCT.md このgemのコントリビューターにへのルール
- LICENSE.txt gemは基本的にMIT
- テスト spec RSpec
- bin ロード状態でirb起動
- Rakefile rake タスク