Crevo Developer’s Blog

クレボ開発者ブログ

Rubyのプライベートなgemを作成・共有する方法【Crevo社内勉強会レポート】

こんにちは!Crevo開発メンバーの井上です。

Crevoでは毎週テーマを決めて技術的な勉強会を開催しています。

今回は「 Rubyのプライベートなgem作成 」をテーマに実施しましたので、利用した資料になぞらえて共有したいと思います。

具体的な導入手順まで紹介していますので、この機会に今後の開発環境を改善できるgem作りに挑戦していただければ幸いです!

mtg_image2

社内勉強会のハンズオン内容(Rubyのgem作成の方法)

それでは早速、ミニマムなgem作成を通してどのようにgemを作るのか一連の流れを見ていきます。

1. どこでPrivateなgemをつくるか決める

gemは公開されているものが多いですが、自社アプリなどでは公開しづらい処理も多々あります。

今回はプライベートなgemとして作っていく想定です。

まずリポジトリの置き場所について考えておきましょう。

候補(1): 新しいリポジトリをつくる。

GitHubにアプリを管理している企業アカウントがあれば、そちらに別途リポジトリを作成して置かせてもらうのも良いでしょう。

その場合は環境変数に以下のものを用意して、

export BUNDLE_GITHUB__COM=<username>:<personal access token>

後はGemfileに以下のように書くだけです。

gem 'your_private_gem_name', git: "https://github.com/crevo-inc/your_private_gem_name"

参考:GitHubのプライベートリポジトリのgemをbundle installする

候補(2): Bitbucket等を使う

Privateリポジトリも無料で利用可能なため、 BitBucketGitLab なども候補になるかと思います。

個人でプライベートなgemを作成したい場合はこちらで良いでしょう。

2. コードで分離できる処理を探す

今回の勉強会では プライベートリポジトリ 作成がテーマとなるため、

もしすでに開発しているアプリがあれば既存のコードからgem化できそうなところを検討するのが一番実用的かと思われます。

メンバーも各自gem化できそうなコードを探しました。

(画像アップロードのために作っているモジュールなどなどそれぞれgem化できそうな内容を抽出して取り組みました)

gem化するには concerns ディレクトリ下に置いてあるような共通処理がgem化しやすそうです。

サンプルとして、ここでは下記のようなModuleをgem化してみます。

# 例:app/models/concerns/tax_support.rb
module TaxSupport
  extend ActiveSupport::Concern

  included do
    private

    def include_tax(num)
        (num * (1 + Settings.tax_rate)).to_i
    end
  end
end

3. gemの雛形を作成する

それでは早速gemの土台を作っていきましょう。

まずは $ bundle gem [gemの名前] のコマンドを実行してgemのテンプレートを作成します。

$ bundle gem tax_support

  create  tax_support/Gemfile
  create  tax_support/lib/tax_support.rb
  create  tax_support/lib/tax_support/version.rb
  create  tax_support/tax_support.gemspec
  create  tax_support/Rakefile
  create  tax_support/README.md
  create  tax_support/bin/console
  create  tax_support/bin/setup
  create  tax_support/.gitignore
  create  tax_support/.travis.yml
  create  tax_support/.rspec
  create  tax_support/spec/spec_helper.rb
  create  tax_support/spec/tax_support_spec.rb
  create  tax_support/LICENSE.txt
  create  tax_support/CODE_OF_CONDUCT.md

様々なファイルができますが、編集が必須のところだけ見ていきましょう。

4. gemの基本的な情報を記載する

まずは tax_support.gemspec (gem名がファイル名に含まれる)を以下のように修正します。

このファイルにはgemの基本情報を書いていきます。

初期値として TODO のコメントが入っていますが、これが残っていると動かないので書換えておきましょう

今回はシンプルに以下のようにしておきます。

lib = File.expand_path("../lib", __FILE__)
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
require "tax_support/version"

Gem::Specification.new do |spec|
  spec.name          = "tax_support"
  spec.version       = TaxSupport::VERSION
  spec.authors       = ["crevo"]
  spec.email         = ["example@crevo.jp"]

  spec.summary       = %q{税金の計算を楽にします}
  spec.description   = %q{方法論としてはfloatクラスを使います}
  spec.homepage      = "https://github.com/crevo"
  spec.license       = "MIT"

  spec.files         = `git ls-files -z`.split("\x0").reject do |f|
    f.match(%r{^(test|spec|features)/})
  end
  spec.bindir        = "exe"
  spec.executables   = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
  spec.require_paths = ["lib"]

  spec.add_development_dependency "bundler", "~> 1.16"
  spec.add_development_dependency "rake", "~> 10.0"
  spec.add_development_dependency "rspec", "~> 3.0"
end

実際に社内のgemを作成している時は、うっかりパブリックなリポジトリにpushしないように、以下のようにpushを許可するリポジトリの記述も追加しておきましょう!

  spec.metadata["allowed_push_host"] = "https://github.com/crevo-inc"

なお、製作中のgemで利用するgemがあれば、その内容もこのファイルに書いておきます。

例えば、 "natto" というgemを使う場合、

  spec.add_runtime_dependency "natto"

と追記します。

add_runtime_dependency で作成中のgem内の処理で使用する他の依存gemを指定できます。

add_development_dependency はpryなど開発用のgemを指定するためのものです。

なお、依存gemはGemfileに記述するわけではないので注意しましょう。

記述したら、

$ bundle install

を実行しておきましょう。

5. 実装したいコードを書く

今回はFloatモジュールに税金を含めた金額を計算出来る新しいメソッド include_eval を追加してみます。

# 例:lib/tax_support.rb
require "tax_support/version"

module TaxSupport
  class << self
    def hello
      "hello"
    end
  end

  Float.module_eval {
    def include_tax
      self * (1 + 0.08)
    end
  }
end

実際のコードは lib/tax_support.rb のようにgem名のファイル内に書いていきます。

6. テストコードを書く

gemもアプリと同様に、そのプロジェクト内にテストコードを追加しておきます。

Rspecで今回は次のように追加しておきました。

RSpec.describe TaxSupport do
  it "has a version number" do
    expect(TaxSupport::VERSION).not_to be nil
  end

  it ".hello" do
    actual = TaxSupport.hello
    expected = "hello"
    expect(expected).to eq actual
  end

  it "#include_tax" do
    actual = 100.0.include_tax
    expected = 108.0
    expect(expected).to eq actual
  end
end

テストを書いたら通るか確認しておきましょう。

$ bundle exec rspec

なんと、これだけでgemは完成です。

\簡単/ \素敵/

次に、作成したgemを実際に企業内の各プロジェクト等で使う方法にも触れていきましょう。

7. cloneしてGemfileのパスをローカルに指定して使う

公開されているGemの場合はGemfileから vendor/bundle/ 等に自動配置されますが、プライベートでgemを作っている場合は自分で配置して参照してあげる必要があります。

具体的には、cloneでローカルに配置してから、直接パスを指定します。

$ git clone git@github.com:crevo/tax_support.git

Gemfile

  gem "tax_support", path: "./tax_support"

パスを指定したら bundle install します。

$ bundle install

社内アプリで切り出せそうな処理はgem化して、 他のプロジェクトのアプリでも使用 したいですよね!

ひとまずgemの作成方法に関してはここまでです。

社内アプリの一部をgem化するコツ

勉強会の中で自社アプリの特定の機能をgem化したい場合の知見として、 app/lib/gem などのディレクトリにモジュールを置いておき、そこである程度育ったらgem化すると良いとの知見も出ていました。

また、公開する前にRailsのGemfileの中で gem "my_gem", path: "./lib/gem/my_gem" のように ローカルのgemとして参照させる というような使い方も可能です。

中途半端にgem化してもメンテナンスコストが高いので、ある程度育ててから、まずはしっかり使える形にすると良いです。

Crevoの開発での活用法の検討

Crevoの Collet の開発では、様々な処理をモジュール化して使用しています。

今回の勉強会では具体的にShrineのgemを使用して、S3への非同期なファイルアップロードを簡潔に書けるgem等の作成に取り組んでいただいていました。

Crevoチームでは1割の時間は『改善』に当てようという『10%ルール』というものが有るので、今後も汎用的な処理として使えるgem化作業なども期待されています。

一緒に改善してくれる仲間を募集しています…!

まとめ

本日はgemの作り方を見ていきました。

特にプライベートなgemは自分が作るアプリなどから気軽に作成可能です。

複数のプロジェクトで使えそうな汎用的な処理は、是非この機会にgem化して便利に使えないか検討してみてはいかがでしょうか。

We are Hiring!

CrevoではRubyを使ってプロダクトを開発しています。

エンジニアを絶賛募集していますので、お気軽にご連絡ください!

© Crevo Inc.