Bundlerは、Carl Lerche、Yehuda Katz、André Arko、そして多数の素晴らしい貢献者によって作成された、RubyライブラリのRubygemsの依存関係を管理するためのツールです。Bundler 1.0はRails 3とほぼ同時期にリリースされ、Bundlerが最もよく知られているのはおそらくRailsプロジェクトでの利用でしょう。しかし、BundlerはRails専用ではないことを覚えておいてください!
Bundlerは、gemの依存関係の管理だけでなく、独自のgemを作成するためにも使用できることをご存知ですか?これは非常に簡単で、Bundlerはこの過程で役立ついくつかの機能を提供します。
関連資料
なぜgemを作成する必要があるのでしょうか?コードを他のライブラリに放り込んで代わりにそれを使うことはできないのでしょうか?確かに、それは可能です。しかし、そのコードを他の場所で使用したい場合や、共有したい場合はどうすればよいでしょうか?だからこそgemが最適なのです。ライブラリとgemを別々にコーディングし、ライブラリでgemをrequireするだけで済みます。gemを別のライブラリで使用したい場合は、大量のコピーをするのではなく、わずかな修正で済みます。
また、共有は思いやりです。
このガイドはBundlerのバージョン1.9.0を使用して作成されました。他のバージョンでも同様に進めることができますが、まったく同じ出力が得られない場合があります。現在使用しているBundlerのバージョンを確認するには、次のコマンドを実行してみましょう。
$ bundle -v
Bundler version 1.9.0
に近いものが表示されるはずです。必要に応じて、gem update bundler
を実行してBundlerの最新バージョンに更新できます。
Bundlerを使ってgemを作成し始めるには、次のようにbundle gem
コマンドを使用します。
$ bundle gem foodie
このgemは、食べ物を「おいしい!」または「まずい!」のどちらかで表現するなど、食べ物に関するいくつかの処理を行うため、foodie
という名前にしました。乞うご期待。
gemの命名規則については、RubyGems Webサイトの「Name Your Gem」ガイドをご覧ください。
このコマンドは、新しいgemのスケルトンディレクトリを作成し、Gitがインストールされている場合は、このディレクトリにGitリポジトリを初期化して、すぐにコミットを開始できるようにします。bundle gem
コマンドを初めて実行する場合は、プロジェクトにCODE_OF_CONDUCT.md
ファイルとLICENSE.txt
ファイルを含めるかどうかを尋ねられます。生成されるファイルは次のとおりです。
Gemfile:ライブラリの開発におけるgemの依存関係を管理するために使用されます。このファイルには、gemspec
という行が含まれており、Bundlerはfoodie.gemspecで指定された依存関係も含まれることを意味します。ライブラリが依存するすべてのgemをgemspecで指定するのがベストプラクティスです。
Rakefile:Bundlerを必要とし、Bundler::GemHelper.install_tasks
を呼び出すことによって、build
、install
、およびrelease
のRakeタスクを追加します。build
タスクは、現在のバージョンのgemをビルドし、pkgフォルダーに保存します。install
タスクは、gemをビルドしてシステムにインストールします(gem install
でインストールするのと同様です)。release
は、公開のためにgemをRubygemsにプッシュします。
CODE_OF_CONDUCT.md:gemのすべてのコントリビューターに期待される行動規範を提供します。含めることを選択した場合にのみ含まれます。
LICENSE.txt:MITライセンスが含まれます。含めることを選択した場合にのみ含まれます。
.gitignore:(Gitを使用している場合のみ)。これは、pkgディレクトリ(通常はrake build
によってそこに置かれたファイル)、.gem拡張子を持つファイル、および.bundleディレクトリ内のものをすべて無視します。
foodie.gemspec:Gem Specificationファイル。これは、gemの名前、説明、ホームページなど、Rubygemsが利用するための情報を提供する場所です。これは、gemを実行するために必要な依存関係を指定する場所でもあります。
lib/foodie.rb:gemのコードを定義するためのメインファイル。これは、gemがロードされるときにBundler(または同様のスマートシステム)によってrequireされるファイルです。このファイルは、gemのすべてのコードのネームスペースとして使用できるmodule
を定義します。コードを配置するのはベストプラクティスです。
lib/foodie:ここです。このフォルダーには、gemのすべてのコード(クラスなど)が含まれている必要があります。lib/foodie.rbファイルはgemの環境を設定するためのものであり、そのすべてのパーツはこのフォルダーに入ります。gemに複数の用途がある場合、人が一度に1つのクラス/ファイルをrequireできるように分離すると非常に役立ちます。
lib/foodie/version.rb:Foodie
モジュールとその中のVERSION
定数を定義します。このファイルは、gem仕様のバージョンを指定するためにfoodie.gemspecによってロードされます。gemの新しいバージョンをリリースするときは、このバージョン番号の一部をインクリメントして、新しいバージョンをリリースしていることをRubygemsに示す必要があります。
これがベースとレイアウトです。さあ、開発を始めましょう!
このガイドでは、RSpecを使用してgemをテストします。テストを作成して、すべてが計画どおりに進むことを保証し、将来の自分がタイムマシンを構築して戻ってきて私たちを蹴飛ばすのを防ぎます。
テストの作成を開始するには、mkdir spec
コマンドを使用してgemのルートにspecディレクトリを作成します。次に、foodie.gemspecファイルで、rspec
が開発依存関係であることを、Gem::Specification
ブロック内にこの行を追加して指定します。
spec.add_development_dependency "rspec", "~> 3.2"
Gemfileにgemspec
メソッド呼び出しがあるため、Bundlerは自動的にこのgemを「development」というグループに追加し、その後、次の行を使用してこれらのgemをロードしたいときにいつでも参照できます。
Bundler.require(:default, :development)
Gemfileではなくfoodie.gemspecの中にこの依存関係の指定を記述する利点は、gem install foodie --dev
を実行する人は誰でも、これらの開発依存関係もインストールされるということです。このコマンドは、人々がGitHubからフォークしたりクローンしたりせずにgemをテストしたい場合に使用されます。
bundle install
を実行すると、rspecはこのライブラリとBundlerを使用する他のすべてのライブラリにインストールされますが、システムにはインストールされません。これは重要な区別点です。Bundlerによってインストールされたgemは、gem install
によってインストールされたgemを混乱させることはありません。これは事実上、サンドボックス化された環境です。gemのバージョンの競合を避けるために、Bundlerを使用してgemを管理するのがベストプラクティスです。
bundle install
を実行すると、Bundlerは非常に重要なGemfile.lockファイルを生成します。このファイルは、このライブラリが開発されているすべてのシステムにまったく同じgemがあることを保証する役割を果たすため、常にバージョン管理にチェックインする必要があります。このファイルの詳細については、bundle install
manpageの「THE GEMFILE.LOCK」セクションをお読みください。
さらに、bundle install
の出力には、この行が表示されます。
Using foodie (0.1.0) from source at /path/to/foodie
Bundlerはgemを検出し、gemspecをロードして、他のすべてのgemと同じようにgemをバンドルします。
このフレームワークが整ったので、最初のテストを作成できます。テストのために、まずテストを配置するspecというフォルダーを作成します(mkdir spec
)。次に、specディレクトリのルートでテストするクラスごとに新しいRSpecファイルを作成します。gemに複数の側面がある場合は、spec/facetなどのディレクトリの下にグループ化しますが、これは単純なgemであるため、そうはしません。この新しいファイルをspec/foodie_spec.rb
と呼び、次のように記述します。
describe Foodie::Food do
it "broccoli is gross" do
expect(Foodie::Food.portray("Broccoli")).to eql("Gross!")
end
it "anything else is delicious" do
expect(Foodie::Food.portray("Not Broccoli")).to eql("Delicious!")
end
end
bundle exec rspec spec
を再度実行すると、Foodie::Food
定数が存在しないと表示されます。これは事実であり、lib/foodie/food.rb
に次のように定義する必要があります。
module Foodie
class Food
def self.portray(food)
if food.downcase == "broccoli"
"Gross!"
else
"Delicious!"
end
end
end
end
このファイルをロードするには、lib/foodie.rb
にrequire行を追加する必要があります。
require 'foodie/food'
また、spec/foodie_spec.rb
の先頭でlib/foodie.rb
をrequireする必要があります。
require 'foodie'
bundle exec rspec spec
でスペックを実行すると、このテストはパスします。
2 example, 0 failures
大成功!Git(または他のソース管理システム)を使用している場合は、これがコードをコミットするための最適なチェックポイントです。常に頻繁にコミットすることを忘れないでください!
独自のコードを作成できるのは素晴らしいことですが、別のgemに依存したい場合はどうでしょうか?それも簡単です。
ここでは、Active Supportのpluralize
メソッドを、gemのメソッドを使用して呼び出すことで使用します。
別のgemを使用するには、まずfoodie.gemspecで依存関係として指定する必要があります。foodie.gemspecで、Gem::Specification
オブジェクトの中に次の行を追加して、activesupport
gemの依存関係を指定できます。
spec.add_dependency "activesupport"
特定のバージョンを指定したい場合は、この行を使用できます。
spec.add_dependency "activesupport", "4.2.0"
または、バージョンの制約を指定できます。
spec.add_dependency "activesupport", ">= 4.2.0"
ただし、最新のものよりも大きいバージョンだけに依存すると、後々問題が発生する可能性があります。依存関係を指定するには、常に~>
を使用するようにしてください。
spec.add_dependency "activesupport", "~> 4.2.0"
再度bundle install
を実行すると、activesupport
gemが使用できるようにインストールされます。もちろん、私たちは勤勉なTDD/BDD信者なので、コードを記述する前にpluralize
メソッドをテストします。このテストをspec/food_spec.rbのdescribe Foodie::Food
ブロック内に追加しましょう。
it "pluralizes a word" do
expect(Foodie::Food.pluralize("Tomato")).to eql("Tomatoes")
end
もちろん、bundle exec rspec spec
でこのスペックを実行すると失敗します。
expect(Failure/Error: Foodie::Food.pluralize("Tomato")).to eql("Tomatoes")
undefined method `pluralize' for Foodie::Food:Class
次に、pluralize
メソッドを含むActive Supportの部分を最初にrequireして、このpluralize
メソッドをlib/foodie/food.rbに定義できます。この行は、他のすべての優れたrequire
と同様に、ファイルの先頭に記述する必要があります。
require 'active_support/inflector'
次に、次のようにpluralize
メソッドを定義できます。
def self.pluralize(word)
word.pluralize
end
bundle exec rspec spec
を実行すると、スペックがパスします。
3 examples, 0 failures
これは、これまでの取り組みをコミットするのが良いアイデアである別のチェックポイントをもたらします。
gemのメソッド(その2つすべて!)を呼び出して文字列を返すことができるのは素晴らしいことですが、誰もが、最高のgemにはコマンドラインインターフェイス(以下、「CLI」)が付属していることを知っています。このgemにCLIがないという点で、このgemがどれほどクールでないかがすぐにわかるでしょう?それが必要なのです。それを切望しているのです。
それにはふさわしいのです。
2つのメソッドしかないgemが持つことができる最高のCLIをgemに提供しようと急ぐ前に、まずこれをどのようにテストするかを検討しましょう。私たちは信者です、覚えてますか?もし利用できるツールがあれば良いのですが。もちろん、クールな名前が必要でしょう。
たとえば「Aruba」のように。BAM
David ChelimskyとAslak Hellesøyは、RSpecとCucumberの両方に使用するCLIテストツールであるArubaを作成するために協力しました。今では、私たちもgemのテストに使用できます。ああ、そういえばCucumberは、Arubaテストを定義するために使用するものです。人間がコードクライアントを読めるテストは、未来の道なのです。
Cucumberのものについて、foodie.gemspecに新しい開発依存関係を定義します。
spec.add_development_dependency "cucumber"
spec.add_development_dependency "aruba"
いいね。bundle install
を実行して、これらの素晴らしいツールを設定しましょう。
私たちの CLI は、Foodie::Food
で定義した 2 つのメソッドに対応する 2 つのメソッドを持つ予定です。次に、Aruba を使用して CLI のテストを記述するfeatures ディレクトリを作成します。このディレクトリに、features/food.feature という新しいファイルを作成し、次のコードを記述します。
Feature: Food
In order to portray or pluralize food
As a CLI
I want to be as objective as possible
Scenario: Broccoli is gross
When I run `foodie portray broccoli`
Then the output should contain "Gross!"
Scenario: Tomato, or Tomato?
When I run `foodie pluralize --word Tomato`
Then the output should contain "Tomatoes"
これらのシナリオは、gem が提供する CLI をテストします。When I run
ステップでは、引用符内の最初の単語は実行可能ファイルの名前、2 番目の単語はタスク名、それ以降のテキストは引数またはオプションです。はい、これは私たちのスペックと同じものをテストしているように見えます。あなたはとても観察力がありますね。よくできました! しかし、これは CLI を通じてテストしているので、非常に素晴らしいのです。作為的な例は今年流行しています。
最初のシナリオでは、特定のタスクを呼び出して単一の引数を渡し、それがテキスト出力の一部になることを確認します。2 番目のシナリオでは、事実上同じことを確認しますが、その値を引数ではなくオプションとして渡します。
このフィーチャーを実行するには、cucumber
コマンドを使用しますが、もちろんバンドルコンテキスト内で利用できるため、次のように bundle exec cucumber
を使用します。
$ bundle exec cucumber features/
黄色いものが見えますか?それらは未定義のステップです。
When /^I run "([^"]*)"$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
Then /^the output should contain "([^"]*)"$/ do |arg1|
pending # express the regexp above with the code you wish you had
end
Aruba を require することで定義できます。Cucumber では、features/support ディレクトリ内のすべての .rb ファイルが自動的に require されます。これを証明するために、features/support/setup.rb ファイルを追加し(最初に support ディレクトリを作成)、この 1 行を記述します。
require 'aruba/cucumber'
これにより、Aruba が提供する Cucumber ステップがロードされます。これらは、私たちの Cucumber フィーチャーを素晴らしいものにするために必要なステップと同じです。
次に何が起こるかを確認するために、bundle exec cucumber features
を再実行する必要があります。赤が表示されます。壁から絶え間なく滴る血のような赤です。それには、次のような暗号めいたメッセージが含まれています。
sh: foodie: command not found
まあ、それほど暗号めいてはいません。これは、gem の実行可能ファイルが見つからないことを意味するだけです。心配はいりません。gem のルートに exe ディレクトリを作成し、その中に foodie という名前のファイルを入れることができます。このファイルには、スクリプトではなく実行可能ファイルであるため、拡張子はありません。あちこちで foodie.rb
を呼び回したくないですよね?そうですね、そうしたくないです。このファイルに次のコンテンツを記述します。
#!/usr/bin/env ruby
print "nothing."
このファイルが完全に空の場合、フレンドリーではない Errno::ENOEXEC
エラーが発生します。さて、実行といえば、ターミナルからこのファイルを実行可能にするために chmod
する必要があります。
$ chmod +x exe/foodie
さて、実行可能ファイルを手に入れたわけですが、次はどうすればいいでしょうか?フィーチャーを再実行すると、出力が何も表示されません。文字通り何も表示されません!
got: "nothing."
exe/foodie ファイルが空であるため、このような「何もない」悲劇が発生します。print "nothing."
行を削除し、CLI を実行するために必要なすべてのコードに置き換えます。これは 2 行で構成されます。
require 'foodie/cli'
Foodie::CLI.start
どーん!bundle exec cucumber features
を再度実行すると、require する foodie/cli ファイルがないと文句を言います。このファイルが何をするのかを説明する前に、exe/foodie ファイルのもう一方の行のコードについて説明する必要があります。start
メソッドは、CLI
クラスを起動し、要求したタスクに一致するタスクを探します。
したがって、次のステップはこのファイルを作成することであるのは明らかですが、それは何をするのでしょうか?
この新しい lib/foodie/cli.rb ファイルは、別の gem である Thor
を使用してコマンドラインインターフェイスを定義します。Thor は、Rake ビルドツールの代替として Yehuda Katz (および協力者) によって作成されました。Thor は、使用バナーやヘルプ出力など、CLI を定義するための便利な API を提供します。構文は Rake と非常によく似ています。さらに、Rails と Bundler はどちらも CLI インターフェイスとジェネレーターベースの両方に Thor を使用しています。はい、Thor はジェネレーターも実行します!
今のところ、Thor を使用して CLI を作成する方法を見て、後で、あなたが従順であれば、それを使ってジェネレーターを作成する方法を見ていきます。
この CLI を機能させるには、Foodie::CLI
クラスを作成し、そのクラスに start
メソッドを定義する必要があります。または、ご存知のように、利用できる gem があるでしょう。たとえば、Thor など。北欧神話のイカした稲妻の神にちなんで名付けられたこの gem は、間違いなくイカしているものになるでしょう。この gem は、CLI インターフェイスを構築するために使用し、後でジェネレーターも構築します(従順であれば、覚えてますか?)。
次に、lib/foodie/cli.rb
ファイルを次のように定義してみましょう。
require 'thor'
module Foodie
class CLI < Thor
end
end
Thor
クラスには、exe/foodie
で参照する start
メソッドなど、この CLI を作成するために使用できる一連のメソッドがあります。ちなみに、クラスの名前は CLI
である必要はありません。そうするのが最善の慣例であるということです。この Thor
クラスは魔法のように手に入るわけではありません。以前の add_dependency
の下に次の行を追加して、この gem に依存していることを gemspec に伝える必要があります。
spec.add_dependency "thor"
この新しい依存関係をインストールするには、bundle install
を使用します。bundle exec cucumber features
を再度実行すると、呼び出しているタスクが見つからないと文句を言うことがわかります。
Could not find task "portray"
...
Could not find task "pluralize"
Thor タスクは、わずかなひねりを加えた、普通のメソッドとして定義されます。Foodie::CLI
クラスで portray
タスクを定義するには、Foodie::CLI
クラス内に次のように記述します。
desc "portray ITEM", "Determines if a piece of food is gross or delicious"
def portray(name)
puts Foodie::Food.portray(name)
end
desc
メソッドは、ここでの「わずかなひねり」です。その後に定義されたメソッドは、指定された説明を持つタスクになります。desc
の最初の引数はタスクの使用手順で、2 番目の引数はタスクが実行する内容の簡単な説明です。portray
メソッドは、コマンドラインでこのタスクに渡される最初の引数となる単一の引数で定義されます。portray
メソッド内では、Foodie::Food.portray
を呼び出し、この引数を渡します。
Foodie::CLI
クラスでは、それを定義するファイルを require せずに Foodie::Food
クラスを参照しています。このファイルの先頭にある require 'thor'
の下に、Foodie::Food
を定義するファイルを require するために、この行を記述します。
require 'foodie'
bundle exec cucumber features
を使用してフィーチャーを再実行すると、最初のシナリオがパスします。
2 scenarios (1 failed, 1 passed)
4 steps (1 failed, 3 passed)
2 番目のシナリオは、pluralize
タスクを定義していないため、まだ失敗しています。今回は、引数を取るタスクを定義するのではなく、タスクに渡されたオプションから値を読み取るタスクを定義します。pluralize
タスクを定義するには、Foodie::CLI
で次のコードを使用します。
desc "pluralize", "Pluralizes a word"
method_option :word, aliases: "-w"
def pluralize
puts Foodie::Food.pluralize(options[:word])
end
ここには、メソッドオプションを定義する新しい method_option
メソッドがあります。これは、オプションの詳細をタスクに返す方法を示すハッシュを取ります。有効な型の完全なリストについては、Thor README を参照してください。method_option
に渡される :aliases
オプションを使用して、このメソッドのエイリアスを定義することもできます。タスク内では、options
ハッシュを介してオプションの値を参照し、Foodie::Food.pluralize
を使用して単語を複数形にします。
bundle exec cucumber features
を使用してシナリオを再度実行すると、両方のシナリオがパスします。
2 scenarios (2 passed)
4 steps (4 passed)
bundle exec exe/foodie portray broccoli
を実行して、CLI アプリを実行してみることができます。
後でオプションを追加したい場合は、次のように method_options
ヘルパーを使用して定義できます。
method_options word: :string, uppercase: :boolean
def pluralize
# accessed as options[:word], options[:uppercase]
end
この例では、options[:word]
は String
オブジェクトを返し、options[:uppercase]
は受信した値に応じて true
または false
のいずれかを返します。
この紹介は、Thor についてもっと学びたいというあなたの食欲をそそったはずであり、今すぐ学ぶことをお勧めします。CLI ツールとして Thor を使用する優れた例については、Bundler::CLI
を参照してください。
これで、フィーチャーとスペックがすべてパスしたので、コードをコミットするのに最適なタイミングです。
前述したように、Thor は CLI 以上の用途に使用できます。ジェネレーターを作成するために使用できるということです。それは本当です。ジェネレーターを作成することもできますが、今はあまり調子に乗らず、1 つを作成することに集中しましょう。
そのダジャレが来るのが見えましたよね?ええ、かなり明白です。
少し変化をつけて、gem に新しいフィーチャーを追加します。それは、recipes ディレクトリのジェネレーターです。アイデアは、次のようにジェネレーターを実行できるということです。
foodie recipe dinner steak
これにより、現在の場所に recipes ディレクトリが生成され、その中に dinner ディレクトリが生成され、その中に steak.txt ファイルが生成されます。この steak.txt ファイルには、材料や手順など、レシピの足場が含まれています。
ありがたいことに、Aruba にはジェネレーターがファイルとディレクトリを生成することをテストする方法があります。features/generator.feature という新しいファイルを作成し、次のコンテンツを記述しましょう。
Feature: Generating things
In order to generate many a thing
As a CLI newbie
I want foodie to hold my hand, tightly
Scenario: Recipes
When I run `foodie recipe dinner steak`
Then the following files should exist:
| dinner/steak.txt |
Then the file "dinner/steak.txt" should contain:
"""
##### Ingredients #####
Ingredients for delicious steak go here.
##### Instructions #####
Tips on how to make delicious steak go here.
"""
「delicious」という言葉の後の単語がどちらも「steak」であることに注意することが重要です。これは非常においしいです。これは、実行するコマンドに渡す最後の引数でもあるため、テンプレート内の動的な変数にする必要があります。これを行う方法をすぐに見ていきます。
このフィーチャーを実行すると、ジェネレーターに要求した dinner/steak.txt ファイルが見つからないと伝えられます。なぜでしょうか?
まあ、現在、Foodie::CLI
で定義されているこの処理を行う recipe
タスクがないからです。CLI クラスを定義するのと同じようにジェネレータークラスを定義できます。
desc "recipe", "Generates a recipe scaffold"
def recipe(group, name)
Foodie::Generators::Recipe.start([group, name])
end
このメソッドの最初の引数は、ジェネレーターに渡される引数です。この新しいクラスのファイルも require する必要があります。これは、lib/foodie/cli.rb の先頭にこの行を記述することで実行できます。
require 'foodie/generators/recipe'
このクラスを定義するには、Thor
ではなく Thor::Group
から継承します。また、ファイルやディレクトリを作成できるものなど、ジェネレーターのヘルパーメソッドを定義するために Thor::Actions
モジュールを含める必要もあります。これはジェネレータークラスであるため、「generators」という新しい名前空間に配置し、このファイルの場所を lib/foodie/generators/recipe.rb にします。
require 'thor/group'
module Foodie
module Generators
class Recipe < Thor::Group
include Thor::Actions
argument :group, type: :string
argument :name, type: :string
end
end
end
Thor::Group
から継承することで、CLI ではなくジェネレーターを定義しています。argument
を呼び出すと、ジェネレーターの引数を定義しています。これらは、Foodie::CLI
の recipe
タスクから渡される引数と同じ順序で並んでいます。
このジェネレーターを、ええと、何かを生成するようにするには、クラス内にメソッドを定義するだけです。Thor::Group
の子孫で定義されたすべてのメソッドは、start
が呼び出されたときに実行されます。このクラス内に、渡された名前を使用してディレクトリを作成する create_group
メソッドを定義しましょう。
def create_group
empty_directory(group)
end
このディレクトリにファイルを配置し、私たちの食いしん坊の友達の入力を省くために、template
メソッドを使用します。これにより、事前定義されたソースロケーションからファイルがコピーされ、ERB テンプレートであるかのように評価されます。この処理を行うために、copy_recipe
メソッドを定義します。
def copy_recipe
template("recipe.txt", "#{group}/#{name}.txt")
end
このファイルに ERB 呼び出しがある場合、それらは評価され、その結果が新しいテンプレートファイルに出力されます。
何かを実行してからずいぶんと時間が経ちました。ねえ、アイデアがあります!ジェネレーターを実行しましょう!bundle exec exe/foodie recipe dinner steak
を実行して、Cucumber を使用せずにこれを行うことができますが、今回は 1 回だけです。通常は、Cucumber を通してのみテストします。このコマンドを実行すると、次のすべてが伝えられます。
create dinner
Could not find "recipe.txt" in any of your source paths. Please invoke Foodie::Generators::Recipe.source_root(PATH) with the PATH containing your templates. Currently you have no source paths.
最初の行は、dinner ディレクトリが作成されたことを示しています。特に目立ったものはありません。
ただし、2 行目はもっとエキサイティングです! ジェネレーターの source_root
メソッドを定義するように求めています。簡単です!次のように、Foodie::Generators::Recipe
のクラスメソッドとして定義できます。
def self.source_root
File.dirname(__FILE__) + "/recipe"
end
これにより、ジェネレーターにテンプレートの場所が伝えられます。必要なのはテンプレートを作成することだけであり、これは lib/foodie/generators/recipe/recipe.txt に配置できます。
##### Ingredients #####
Ingredients for delicious <%= name %> go here.
##### Instructions #####
Tips on how to make delicious <%= name %> go here.
template
メソッドを使用すると、テンプレートファイルは、現在の binding
内で評価される ERB テンプレートのように扱われます。これは、それを呼び出すメソッドと同じメソッドと変数にアクセスできることを意味します。
そして、それだけです!bundle exec cucumber features
を実行すると、すべてのフィーチャーがパスします!
3 scenarios (3 passed)
7 steps (7 passed)
素晴らしい内容でしたね?
まだの場合、リポジトリのすべてのファイルをコミットする必要があります。
$ git add .
$ git commit -m "The beginnings of the foodie gem"
これは、foodie.gemspec
ファイルが、gemをリリースする際にどのファイルを追加すべきかを検出するためにgit ls-files
を使用しているためです。
gemをリリースする前の最後のステップは、foodie.gemspecファイルに概要と説明を記述することです。
次に、gemが公開できる状態になっているかを確認します。これを行うには、rake build
を実行してgemのローカルコピーをビルドし、次にgem install pkg/foodie-0.1.0.gem
を実行してインストールします。その後、提供されているコマンドを実行してローカルで試すことができます。すべてが機能していることを確認したら、最初のバージョンをリリースできます。
gemの最初のバージョンをリリースするには、すべてをコミットしていることを前提として、rake release
コマンドを使用できます。このコマンドは、いくつかの処理を実行します。まず、Rubygems.orgへのプッシュに備えて、gemをpkgディレクトリにビルドします。
次に、現在のコミットに対して現在のバージョンを反映したタグを作成し、それをgitリモートにプッシュします。他の人が簡単に見つけられるように、GitHubでコードをホストすることが推奨されます。
このプッシュが成功すると、最後のステップとしてRubygems.orgへのプッシュが行われ、他の人がgemをダウンロードしてインストールできるようになります。
gemの2番目のバージョンをリリースする場合は、変更を加えてGitHubにコミットする必要があります。その後、lib/foodie/version.rbのバージョン番号を適切と思われるものに変更し、「bumped to 0.0.2」などの役立つメッセージとともに別のコミットをGitHubに行い、再度rake release
を実行します。
このプロセスを少し簡単にするために、「gem-release」gemをインストールできます。
$ gem install gem-release
このgemは、一般的なgem開発を支援するためのいくつかのメソッドを提供しますが、最も役立つのは、gemのバージョンを次のパッチレベルに上げるgem bump
コマンドです。このメソッドは、次のことも行うためのオプションも受け付けます。
$ gem bump --version minor # bumps to the next minor version
$ gem bump --version major # bumps to the next major version
$ gem bump --version 1.1.1 # bumps to the specified version
詳細については、「gem-release」GitHubリポジトリのホームページをご覧ください。
これはgem開発に関する網羅的なガイドではありませんが、gem開発に必要な基本を網羅しています。Bundler、Rails、RSpecのソースを、gem開発の良い例として確認することを強くお勧めします。
この例の完全なソースコードをお探しの場合は、こちらにあります。