こんにちは!Crevo開発メンバーの井上です。
Crevoでは毎週テーマを決めて技術的な勉強会を開催しています。
今回は「 Rubyのプライベートなgem作成 」をテーマに実施しましたので、利用した資料になぞらえて共有したいと思います。
具体的な導入手順まで紹介していますので、この機会に今後の開発環境を改善できるgem作りに挑戦していただければ幸いです!
社内勉強会のハンズオン内容(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リポジトリも無料で利用可能なため、 BitBucket やGitLab なども候補になるかと思います。
個人でプライベートな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を使ってプロダクトを開発しています。
エンジニアを絶賛募集していますので、お気軽にご連絡ください!