それマグで!

知識はカップより、マグでゆっくり頂きます。 takuya_1stのブログ

習慣に早くから配慮した者は、 おそらく人生の実りも大きい。

自分のライブラリをgem にして自分で使う、自作gem install

書いたソースコードをgem にして自分で使いたい。

自分で書いたソースコードを再利用するために gem の仕組みを活用し、再利用する。

目標

自分の git ライブラリを読み込み活用する。

必要なもの

  • 自分のライブラリ
  • bundler
  • ruby

手順

  • 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

# /Users/takuya/.rbenv/versions/2.7.1/lib/ruby/2.7.0
# /Users/takuya/.rbenv/versions/2.7.1/lib/ruby/site_ruby
# (中略)
# /Users/takuya/Desktop/my_libs

$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

# frozen_string_literal: true

require_relative "my_libs/version"

module MyLibs
  class Error < StandardError; end
  def self.greetings
     puts "hello from my libs"
  end
end

なにか関数を作っておきます。

git に保存して、レポジトリへ

ライブラリの動作を確認を終えたら、git commitgit 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

# frozen_string_literal: true

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
    • LOAD_PATH.push
    • gem 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 タスク