Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RubyGemsの内部構造を徹底解説!gemの仕組みと自作方法

皆さん、お集まりください。おじいさんが昔話をしてあげましょう。gemのインストールが頭痛の種で、髪を掻きむしり、歯を食いしばるような苦行だった時代の話です。

私がRubyを始めたばかりの頃は、まだBundlerは存在せず、gemは手作業でインストールするしかありませんでした。Railsでは、rake gems:install を何度も実行しては、途中で発生するバグを修正し、エラーなしでコマンドが通るまで繰り返す——そんなのが日常でした。今回は、gemとは何か、そしてどのように動作しているのかを見てから、あえて「古式ゆかりの」方法でgemを作ってみます。

gemとは何か?

RubyGemsは、他の人が書いた機能を使って自分のコードを簡単に拡張するための仕組みです。例えば、認証・認可のコードを一から書く代わりにDeviseを使ったり、アップロードされた画像のリサイズにCarrierWaveを使ったりできます。これにより、再利用可能なコードを書き、他の人と共有することができるのです。

では、どうやって動いているのか?

最もシンプルな形で言えば、gemとはコードと <name>.gemspec ファイルを含んだ、zip圧縮されたディレクトリにすぎません。この .gemspec ファイルには、gemの名前、読み込むべきファイル、依存関係といったメタデータが記述されています。

gem installbundle コマンドは、ソースからzipファイルをダウンロードし、ハードディスク上に展開します。gemがどこにあるかを調べるには bundle info <gem名> を実行するか、bundle open <gem名> で直接gemのディレクトリを開きましょう。

アプリケーションにgemを読み込む際、RubyGemsは Kernel クラスの require メソッドをモンキーパッチしています。まずディスクからファイルを読み込もうとし、それが失敗すると、システムにインストールされている各gemの中から該当ファイルを探します。gem内にファイルが見つかると、そのgemをロードパスに追加して「アクティベート」するのです。

Bundlerを使用している場合は、setup の呼び出し時に各gemをロードパスへ追加します。これにより、RubyGemsがパスを解決する手間が省けるだけでなく、Gemfile(.lock)で指定されたものとは異なるバージョンのgemが読み込まれるのを防ぐことができます。

どうやって作ればいいの?

独自のgemを作成する最も簡単な方法は、Bundlerを使ってgemのスキャフォールド(雛形)を生成することです。これには、適切なディレクトリ構造、ライセンス、行動規範、テスト環境まで一式そろっています。

しかし今回は、コード本体のファイルとメタデータを記述した gemspec ファイルの、わずか2つのファイルだけでミニマルなgemを自作してみます。このgemは、呼び出されるとユーザーに挨拶をするというシンプルなものです。まずはgem用のディレクトリを作成しましょう。

mkdir howdy
cd howdy

このディレクトリ内に、コードを格納する lib フォルダと、メタデータを格納する howdy.gemspec ファイルを作成します。構成は以下のようになります。

tree
.
├── howdy.gemspec
└── lib
    └── howdy.rb

howdy gemのコードは以下の通りです。

lib/howdy.rb

class Howdy
  def greet
    "howdy!"
  end
end

最小限の howdy.gemspec ファイルには、バージョンや作者などの情報を記述します。さらに、gemをビルドする際に同梱するファイルも指定します。これにより、gemの利用者がテストなど、gemのコード実行に不要なファイルまでダウンロードせずに済むようになります。

Gem::Specification.new do |spec|
  spec.name          = "howdy"
  spec.version       = "0.0.1"
  spec.authors       = ["Robert Beekman"]
  spec.email         = ["robert@example.com"]

  spec.summary       = %(Greets the user)
  spec.description   = %(Howdy is a gem that greets the user when called)
  spec.license       = "MIT"

  spec.files         = ["lib/howdy.rb"]
end

gemをビルドするには、gem build howdy.gemspec コマンドを実行します。これにより、コードを含む howdy-0.0.1.gem ファイルが生成されます。作成したgemを他の人に使ってもらうには、gem push howdy-0.0.1.gem コマンドでrubygems.orgへ公開しましょう。

まとめ

以上が、非常に基本的なgemを作成して公開するまでの手順です。gemの考古学への探検と、古式ゆかりの作り方を楽しんでいただけたなら幸いです。繰り返しになりますが、これはあくまで学習目的の内容であり、現在の開発ではBundlerでスキャフォールドを生成する方法をお勧めします。

それでは、若者諸君、また会おう!ご意見、ご質問、コメントなどがあれば、お気軽にお知らせください。

  1. VCR Gem × WebMockでRubyのテストスイートを高速化する方法

    Rubyアプリケーションが外部APIを利用しているなら、テストが遅い・APIのレート制限に引っかかるといった問題に直面したことがあるのではないでしょうか。 解決策は何があるでしょう? クライアントライブラリのHTTPメソッドを手動でスタブ化し、事前に用意したレスポンスを返す方法もあります。 しかし、これは手間がかかる上に、コードも読みにくくなってしまいます。 より良い解決策は、WebMock + VCRという強力なGemの組み合わせを使うことです。 WebMockは、主要なHTTPライブラリからのHTTPリクエストを横取り(インターセプト)します。対応しているのは例えば: net/http

  2. AASM Gemで学ぶRubyステートマシン入門|Stateデザインパターンから実践的な使い方まで

    今回は、ステートマシン(状態遷移マシン)の仕組みと、RubyプロジェクトでAASM gemを使ってステートマシンを活用する方法を解説します。 まずは身近な例から考えてみましょう。 信号機を想像してください。信号機は「赤」「黄」「青」のいずれかの状態を取ります。 そして、色が変わるとき、次に何色になるかは現在の色によって決まっています。 ここでは、視覚障害のある方が渡れるタイミングを音で知らせるタイプの信号機だとしましょう。 さて、ここからが本題です。 あなたがこの信号機のソフトウェアを開発することになったとします。 毎回どの音を鳴らすべきか、次はどの色に変わるべきか——それをどう判断すればよ