Chefを使う人のための、最低限のRuby関連知識

Chefを使う人のための、最低限のRuby関連知識
===

はじめに
---
Chefで初めてRubyの開発環境に触れる人のために、Chefで使うツールの概要と簡単な使い方を整理してみたいと思います。本家のChefのサイトには、[JustEnoughRubyForChef](http://docs.opscode.com/just_enough_ruby_for_chef.html)というページがありますが、初めてRubyに触れる人にはいろいろ謎なことがありそうです。
　例えば、Chefの開発で使われるGit, Bundler/Gemfile,rbenv, Rake, ruby, rspec について簡単に説明します。知っている箇所は飛ばし読みするといいでしょう。


　インフラ系の人は、アプリケーション開発系の人が何気なく使っているツールに対してもなじみが無いことは注意を払う必要があるでしょう。

1. Git
---
　Gitは、オープンソースの、分散バージョン管理ツールです。Chefを使うと、サーバーのセットアップを手動で実施することなく、プログラム化することができます。

 Chefを使うときは、サーバーのセットアップを実施するためのプログラムや、設定ファイルを記述します。このプログラムや、設定ファイルを管理するために、一般的にはGitもしくは、その派生ツール(Stash等)が使われます。

　Gitに慣れていない人のために、よく使うGitのコマンドを解説したいと思います。本記事は、Gitの管理者がいる前提で、Gitを使う人に必要な知識を記述します。
　
### 1.1. Gitはなぜ便利なのか？

　Gitが初めての皆さんのために、Gitが従来のバージョン管理ツールと比べてどう便利かということを説明したいと思います。合わせてGitの動作イメージも説明していきたいと思います。
　
#### 1.1.1. 従来型のリポジトリのイメージ

従来型のリポジトリは次のようなイメージになっていると思います。

```
 Repository - Workstation
```
プログラムを作成する人は、各自のPC(Workstation)から、リポジトリ(Repository)に接続して、最新のソースコードを取得したり、ローカルで編集したソースコードを、リポジトリのあるサーバーにcommitというコマンドを発行して、リポジトリに反映させたりします。従来はバージョン管理をExcelの帳票とかでやっていましたから、そんなめんどくさいことは、すべてツールが実施してくれるので、これだけでもかなり便利です。

 また、リポジトリを使っていると、ソースコードをある時点に戻したり、自分が書いたソースコードの変更を無かったことにしたりといった操作が簡単になります。またローカルでソースを保存するケースと比べて、他の人とソースの共有が簡単になりますし、他のファイルとの整合性を保ったり、異なるバージョンの管理などを自分でしなくていいので、とても楽です。

リポジトリを使うとずいぶんいい感じですが、単純にリポジトリのサーバーがあるだけの場合、いくつかの問題が発生します。

#####・自分の細かい作業をリポジトリに保存できない 

ソースコードを作っていくときは、小さなステップで作業をしていきます。少しづつ機能追加やテストを書いたりしながらやっと人と共有できるような状態になります。機能がちゃんとできて人様に共有できるようになるためには、しばし時間がかかります。

　しかし、作業をしている側からすると、人様に共有するまでは行かないけど、自分で出来た部分までリポジトリに覚えておいてほしいという状況がよく発生します。

　
　ところが従来型のリポジトリでは、リポジトリが１つしかないので、人様に共有できるレベルになるまでは、ローカルで作業して、一連の固まりの機能が完成するまでは、ローカルで作業するしかありませんでした。ローカルで作業している間は、リポジトリに覚えておいてもらうことが出来ません。
　

ですから、この状態で、PCが死んでしまうと、ローカルでせっかくやっていた作業も一緒にふっとんでしまうことになります。

##### ・競合（コンフリクト時の扱いが面倒）

　機能がきっちり出来るまでリポジトリに変更を反映できませんから、リポジトリからソースを取得してから、ソースを変更して、リポジトリに反映するまでの時間が長くなります。そうなると、同じソースコードを別の人が編集したりする競合（コンフリクト）という状態が発生します。

　コンフリクトが一旦発生すると、後でリポジトリに反映させた人が、リポジトリの中に書いてあるソースコードと、自分のソースコードを比較して、２つのソースコードを自分の目で見て統合（マージ）してあげる必要があります。このマージ作業というのは本当に大変です。

特に、大きな機能を作っているときは、リポジトリに反映させる時間が長くなりがちです。１日がかりで機能を開発したのに、他の人が重複しているコードをいじったので、その２つの変更をマージしてテストして、、、ということで数日かかるなんてことが発生します。これは面倒ですね。

##### ・ネットワークつながっていないとき不便

最後の一点は、従来型のリポジトリのシステムでは、ネットワークにつながっていない時は、リポジトリにアクセスできません。そういう時はすべてローカルの作業になるので、リポジトリの機能はいっさい使えないことになります。自分のした変更をいったんもとに戻したいとかよく発生しますので、これは不便ですね。

#### 1.1.2. Gitのイメージ

Gitの場合は、中央のリポジトリと、自分の手元のPCにもリポジトリを持っているといったイメージです。

```
 RemoteRepository - Workstation(LocalRepository)
```
リポジトリが、中央のリポジトリ（リモートリポジトリ）と、手元のリポジトリ（ローカルリポジトリ）があると、1.1.1.で説明したような、問題が解決します。

Gitでの作業イメージは、次のようなイメージになります。

1. リモートリポジトリからローカルリポジトリを作成する
2. ローカルリポジトリを使って作業を行う
3. ローカルリポジトリをリモートリポジトリに反映する

単に手元のリポジトリが増えただけなのですが、これがどう課題を解決するのかを見てみましょう。

##### ・（課題）自分の細かい作業をリポジトリに保存できない  

手元のリポジトリが出来たので、他の人にはまだ公開できないけど、バージョン管理をしたいといったことが簡単にできます。ある程度の小さな仕事をしたら、まずローカルリポジトリに反映（コミット）します。それによって、ローカルリポジトリ内で、いつでも前のバージョンに戻したりといったようなオペレーションが簡単になります。

##### ・(課題)競合（コンフリクト時の扱いが面倒）

他人が自分の触っている途中のソースコードを変更していて、中央のリポジトリに変更を反映させたときに、マージ作業が大変という問題に関しては、Gitの場合面白い考え方があります。トピックブランチという考え方です。

例えば、リリース後の本番で使われる、リポジトリが、Masterという名前で管理されているとします。このマスターに対して機能追加したいなと思った時、まず作業者は、マスターの内容を引き継いでトピックブランチというブランチ（作業コピーのようなもの）を作成します。例えばfeature/add_order_entryみたいな感じです。

```
Master -> TopicBranch(feature/add_order_entry)
```

そうすると、feature/add_order_entryというあなた専用のリポジトリができます。自分が好きにいじることができます。まず、これを中央のリポジトリ（リモートリポジトリ）に作成します。

```
RemoteRepository:                       LocalRepostiry:
   - Master                                 - Master
     |- feature/add_order_entry
```
そして、リモートにつくった自分用のリポジトリをローカルにコピーします。

```
RemoteRepository:                       LocalRepostiry:
   - Master                                 - Master
     |- feature/add_order_entry               |- feature/add_order_entry
```
そして、普段は、ローカルの自分用のリポジトリで作業をしています。自分用のリポジトリなので、いつでも、変更をリポジトリに登録したり、もとに戻したりができます。また、自分用のリポジトリなので、いつでもローカルの作業を中央のリポジトリに反映することができます。それをしたところで、みんなと共有のMasterは影響をうけません。

さて、他の人が、今あなたがさわっているソースを変更したとして、Masterの内容が下記変わったとします。普通はfeature/add_order_entryで変更したソースをMasterに反映するタイミングで、コンフリクトが発覚しそうなものですが、Gitにはいいメカニズムがあります。もし、Masterに変更が発生したら、そこから分岐した子であるfeature/add_order_entryを使っている人には、Masterで変更が発生したことが通知されます。それを現在いじっているfeature/add_order_entryに反映させるのがとても簡単に実施されます。

　ですので、変更が入った時点でそのコンフリクトに対応できますので、影響の範囲が少ないうちに対応できるというわけです。これが、機能が完全に出来上がってからマージするとなると、さらにそこから変更が入るかもしれないので、相当大変な状況になってしまうでしょう。

##### ・（課題）ネットワークつながっていないとき不便  

ネットワークにつながっていなくてもGitのようにリポジトリがローカルにあれば、リポジトリに対して、反映したり、もとに戻したりということが簡単にできます。たんに中央のリポジトリにつながらないだけです。

#### 1.1.3. まとめ

+ Gitでは、中央のリポジトリ（リモートリポジトリ）の他にローカルリポジトリがあります
+ Gitの開発では、自分用のリポジトリ（トピックブランチ）を気軽につくってそこで作業します
+ マスターの変更は通知されるので、作業中でも、いつでも、トピックブランチとマージできます


```
RemoteRepository:                       LocalRepostiry:
   - Master                                 - Master
     |- feature/add_order_entry               |- feature/add_order_entry
```
　
さて、Gitの雰囲気は感じていただけたでしょうか？Chefのクックブックを管理するための、Gitのオペレーションについて説明をしたいと思います。　
　
### 1.2. リポジトリの取得

最初にGitHubや、Stashのページにあるリモートのリポジトリをローカルに持ってきたい場合は`git clone`コマンドを使います。例えば次のような感じですね。`https://github.com....`の部分はリポジトリ毎にちがいます。GitHubやStashのリポジトリのページに書いてありますのでそれをそのまま使いましょう。

```
$ git clone https://github.com/aaarepos/sample.git
```

尚、リポジトリの取得の仕方ですが、２通りあります。これは、httpsのプロトコルを使う方法です。もう一つの方法が、sshを用いる方法です。例えば上のリポジトリだと

```
$ git clone git@github.com:aaarepos/sample.git
```

という感じになります。その場合、Gitのリポジトリに登録した公開鍵に相当する秘密鍵を取得しておく必要があります。具体的な方法はリポジトリの管理者の方に聞いてみてください。

### 1.3. リポジトリの最新化

一旦取得したリポジトリを最新化させるコマンドは次のとおりです。次のコマンドでリモートリポジトリから、ローカルリポジトリに最新情報をとりこみます。

```
$ git pull
```

### 1.4. ブランチの作成

ソースコードに変更を入れたいときは、自分用のリポジトリを作りましょう。方法は簡単です。GitやStashのWebページから作ることができます。GitHubで説明してみます。例えばMasterというブランチを修正したい場合は、リポジトリのWebページにいって

`branch:Master` と書かれたボタンがあるので、これを押します。もし、他のブランチのソースを編集したい場合であれば、そのブランチを選択してください。

そうすると`Find or create a branch....`という文字がはいった入力ボックスがでてきますので、そこに自分用のブランチの名前をいれてください。例えば`feature/add_order_entry`という名前を入れてエンターを押すと、中央のリモートリポジトリに自分用のブランチ(この機能を追加するためだけの自分用リポジトリ)ができます。

```
RemoteRepository:                       LocalRepostiry:
   - Master                                 - Master
     |- feature/add_order_entry
```

ただ、これだけだと、まだ自分の手元にはきていないので、次のコマンドをうちます。

```
$ git checkout -b feature/add_order_entry origin/feature/add_order_entry
```

これでローカルに、新しいブランチができて、それが選択されます。修正する前は中身はMasterと同じです。
現在`*`がついているものが、選択されているブランチです。

```
$ git branch
  master
* feature/add_order_entry
```
とすると、ローカルのブランチ一覧が見れます。リモートのブランチの一覧を見たい場合は

```
$ git branch -r
```
で一覧を見ることができます。リモートのブランチはoriginという接頭句がついています。

現在選択されているブランチの最新版を取得したいときは、前のコマンド

```
$ git pull
```

を発行してください。

### 1.5. ファイルの修正と確認

あとはファイルを変更します。ファイルを変更したり新規でつくったりしたのち次のコマンドをうってみましょう。

```
$ git status

$ git status
On branch master
Your branch is up-to-date with 'origin/master'.

Changes to be committed:
  (use "git reset HEAD <file>..." to unstage)

	new file:   aaa.xml

Changes not staged for commit:
  (use "git add <file>..." to update what will be committed)
  (use "git checkout -- <file>..." to discard changes in working directory)

	modified:   bbb.ruby

Untracked files:
  (use "git add <file>..." to include in what will be committed)

	ccc.ruby
```

Changes to be committed -> リポジトリに入れる準備環境
Changes not staged for commit -> 変更はあったのはわかってるけど、リポジトリに入れる準備未
Untracked file -> リポジトリがまだ認識していないファイル

### 1.6. 変更の追加

Changes not staged for commit と Untracked fileに関しては、リポジトリに入れるための準備をしてあげる必要があります。上記の例では次のとおりです。

```
$ git add bbb.ruby
$ git add ccc.ruby
```

もう一度`git status`コマンドで確認すると、`git add`コマンドで追加したファイルがすべてChanges to be committedの方に移動したのがわかると思います。しかし、まだ今の状態だと、リポジトリに状態が反映されていません。

### 1.7. 変更のコミット

変更のコミットは次のコマンドです。 `-m`で、コメントをつけることができます。このコメントは、リポジトリに記録されるのでWebで見たり、チケットと呼ばれる作業管理のツールでも確認することができてとても便利なので必ず何のために変更したのかを記録するようにしましょう。

```
$ git commit -m "○○のため、××機能を追加しました"
```

これで、ローカルリポジトリに変更が登録されました。

```
RemoteRepository:                       LocalRepostiry:
   - Master                                 - Master
     |- feature/add_order_entry               |- feature/add_order_entry (○)
```


ただ、この状態だと、ローカルに反映させただけなので、次にリモートリポジトリにある自分用リポジトリに
反映させる方法を学びましょう。


### 1.8. リモートリポジトリへの反映

リモートリポジトリの自分のブランチに反映させたいときは

``` 
$ git push
```
コマンドを使いましょう。このコマンドを発行すると

```
RemoteRepository:                       LocalRepostiry:
   - Master                                 - Master
     |- feature/add_order_entry(○)            |- feature/add_order_entry (○)
```

という状態になります。

### 1.9. Masterへのマージ

機能が完成したいので、Masterへ変更内容を反映させたいとします。まず、その前にMasterであった変更内容を自分のローカルに反映させましょう。

```
$ git checkout master
$ git branch
* master
  feature/add_order_entry
```

上記のコマンドで、ローカルのMasterブランチを選択しました。ただ、この状態では、まだ、Masterの変更がローカルには反映されていません。

```
RemoteRepository:                       LocalRepostiry:
   - Master（☆）                              - Master
     |- feature/add_order_entry(○)            |- feature/add_order_entry (○)
```

リモートの内容を取得するコマンドをつかいましょう。

```
$ git pull
```
Masterブランチが選択された状態で、このコマンドを発行すると、マスターブランチが最新化されます

```
RemoteRepository:                       LocalRepostiry:
   - Master（☆）                              - Master（☆）
     |- feature/add_order_entry(○)            |- feature/add_order_entry (○)
```

次に、マスターの変更を自分のリポジトリに取り込みましょう。まず、リポジトリを自分のブランチに戻します。

```
$ git checkout feature/add_order_entry
$ git status
  master
* feature/add_order_entry
```

次のコマンドで、マスターの内容が反映されます

```
$ git merge master
```

```
RemoteRepository:                       LocalRepostiry:
   - Master（☆）                              - Master（☆）
     |- feature/add_order_entry(○)            |- feature/add_order_entry (○☆)
```
一応リモートにも反映させましょう。

```
$ git push
```
```
RemoteRepository:                       LocalRepostiry:
   - Master（☆）                              - Master（☆）
     |- feature/add_order_entry(○☆)            |- feature/add_order_entry (○☆)
```

この状態で普通は動作確認をします。自動テストなどがあればそれを流します。動作が問題ないようでしたら、いよいよマスターに反映させます。まず、マスターのブランチに移動します。


```
$ git checkout master
$ git branch
* master
  feature/add_order_entry
```
その上で、マスターに変更を反映します。

```
$ git merge feature/add_order_entry
```

反映されました。

```
RemoteRepository:                       LocalRepostiry:
   - Master（☆）                              - Master（○☆）
     |- feature/add_order_entry(○☆)            |- feature/add_order_entry (○☆)
```

そして、リモートにも反映します。

```
$ git push
```

できました。

```
RemoteRepository:                       LocalRepostiry:
   - Master（○☆）                              - Master（○☆）
     |- feature/add_order_entry(○☆)            |- feature/add_order_entry (○☆)
```

この手順で実施すると、この作業を行っている短い間の場合にマスターが変更されたとか無い限りはうまくいきます。もし、そういう短い時間の間のマスター変更があったらGitからエラーメッセージが発行されるので、もう一度`git pull`を実行すればいいでしょう。


### 1.10 Gitまとめ

　これで、基本的なGitの説明は終わりです。インターネットにはもっと細かい操作方法についてのっているので、リポジトリの管理者の人に聞いたりしながら調べてみてください。
　
　あと、私が説明したGitのイメージは実は実際のアーキテクチャとは厳密には異なります。ただし、大抵のプロジェクトは上記のようなイメージで操作しても問題がおきません。興味がある人は是非Gitの本を読んでみてください。
　
　[GitHub実践入門](http://www.amazon.co.jp/GitHub%E5%AE%9F%E8%B7%B5%E5%85%A5%E9%96%80-~Pull-Request%E3%81%AB%E3%82%88%E3%82%8B%E9%96%8B%E7%99%BA%E3%81%AE%E5%A4%89%E9%9D%A9-PRESS-plus/dp/477416366X/ref=sr_1_5?ie=UTF8&qid=1404969407&sr=8-5&keywords=Git)


2. Bundler/Gemfile
---
[Bundler](http://bundler.io/)とは、Rubyのプロジェクト毎に、必要なバージョンのライブラリとその関連ライブラリを管理/インストールしてくれる便利ツールです。

### 2.1. Rubygems

Rubyのライブラリは、gemと呼ばれています。このgemは、[Rubygems](https://rubygems.org/)というサイトで管理されています。ライブラリ開発者は、自分で開発したライブラリをこのサイトに登録することができ、利用者は、このサイトに登録されたライブラリを自由に使うことができます。

### 2.2. ライブラリのインストール

この、ライブラリを利用するためには、次のようなコマンドでライブラリをインストールする必要があります。例えばrailsというライブラリをインストールしたい場合は次のようにします。

```
$ gem install rails
```
バージョンを指定したい場合は次の通り

```
$ gem install rails -v 4.1.1
```

また、使えるライブラリを調べたいときは次の通り

```
$ gem search -r <keyword>
```
### 2.3. ライブラリの使用

実際にrubyのソースコード内で、インストールしたライブラリを使うためには、次のようにします。requireは、rubyのソースコードで、他のファイルに記述されたrubyのファイルを取り込むときに使われるコマンドです。

```
require "rails"
```
### 2.4. gemでできること

他のコマンドは[このサイト](http://www.asterisk-works.jp/wiki/index.php/Rubygems%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%83%A1%E3%83%A2)が参考になります。



このコマンドで、rubyのライブラリだけではなく、rubyのライブラリで使われる、ネイティブライブラリもインストールされることもあります。

### 2.5. Bunlderの意義

ところが、沢山のrubyプロジェクトを１台のマシンで管理していると、ライブラリのバージョンが、プロジェクト毎に違っていたり、競合したりします。そのため、プロジェクト毎に、ライブラリを管理/インストールしてくれるツールが、Bundlerです。英語でBundleというのは、「束」という意味です。

### 2.6. Bundlerのインストール

Bundlerは、はじめからrubyに入っていませんので、インストールする必要があります。インストールは次の通りです。

```
$ gem install bundler
```

### 2.7. Gemfileを記述する

そのプロジェクトで使いたいライブラリや、そのバージョンを記述するのは、Gemfileと呼ばれるファイルです。例えば次のような感じです。このプロジェクトで使いたいライブラリを記述します。バージョンをしたい場合は、バージョンを指定することも出来ます。

```
source 'https://rubygems.org'

gem 'chef'
gem 'berkshelf'
gem 'knife-solo'
gem 'serverspec'
gem 'test-kitchen'
gem 'i18n', '0.6.9'
```

### 2.8. Builderによる、ライブラリのインストール

Gemfileを書いたら、Bundlerを使ってライブラリをインストールしてみます。次のようにタイプすると、Gemfileに記述したライブラリがインストールされます。ライブラリに依存したライブラリも自動で取得されます。

```
$ bundle install
```

インストールすると、一旦インストールしたライブラリのバージョンは固定されます。どのライブラリがインストールされるか？という内容が、Gemfile.lockというファイルに記述されます。既にGemfile.lockがある場合は、そのバージョンのライブラリがインストールされます。

```
GEM
  remote: https://rubygems.org/
  specs:
    activesupport (3.2.17)
      i18n (~> 0.6, >= 0.6.4)
      multi_json (~> 1.0)
    addressable (2.3.6)
    akami (1.2.1)
      gyoku (>= 0.4.0)
      nokogiri
    berkshelf (2.0.14)
      activesupport (~> 3.2.0)
      addressable (~> 2.3.4)
      buff-shell_out (~> 0.1)
        :
```

Gemfileの内容を変更した場合は、再度`bundle update`を実施しましょう。

### 2.9. インストールしたライブラリの利用

bunlderでインストールしたライブラリを使って、rubyのプログラムを実行したい場合は、`bundle exec`をあなたが実行したいコマンドに追加して記述します。例えばchefで使われる`knife solo cook...`コマンドを使いたい場合は

```
$ bundle exec knife cook ...
```

という形式でコマンドを発行するといいです。


3. rbenv
---
rbenvは、１台のマシンで複数のバージョンのRubyを管理したいときに使うツールです。本記事では、インストール方法に関しては割愛しますが、rbenvを使ってインストールされている前提で、その使い方とメカニズムを説明いたします。

### 3.1. rbenvの仕組み

[rbenv](https://github.com/sstephenson/rbenv)がRubyのバージョンを切り替える仕組みは単純です。rbenvの管理下にあるRubyは`~/.rbenv/versions`の下にインストールされます。私の環境では、複数のrubyがインストールされていませんので、次のようなイメージになります。バージョンが複数あったら、複数のバージョンのディレクトリができます。

```
$ ls -l ~/.rbenv/versions/
total 0
drwxr-xr-x  6 ushio  staff  204 Jun 13 16:38 2.1.2

```
自分が使いたいバージョンのrubyを使いたい場合は次のようなコマンドを実行します。

```
$ rbenv versions
  system
* 2.1.2 (set by /Users/ushio/.ruby-version)
```
上記のコマンドで使用できるRubyのバージョンが表示されます。
実際に特定のバージョンのRubyを使うためには次のようにします。

```
$ rbenv local 2.1.2
```
Terminalを立ち上げ直して、確認してみてくださ。

```
$ ruby -v
ruby 2.1.2p95 (2014-05-08 revision 45877) [x86_64-darwin13.0]
```

ちゃんとセットされているようですね。マシン全体でrubyのバージョンを決めたいときは次のコマンドです。

```
$ rbenv global 2.1.2
```

これも同じでTerminalを立ち上げ直して確認してみましょう。


尚、rbenvを使うときは `bundl install`や`gem`を使うたびに、次のコマンドが必要です。gemは`~/.rbenv/versions`の下にあるrubyを`~/.rbenv/shims`の下にコピーします。

```
$ rbenv rehash
```


4. Rake
---
[Rake](https://rubygems.org/gems/rake)は、RubyにおけるMakeのようなものです。Rubyの文法で、タスクや、依存性を定義できます。よく使われる用途としては、開発中に使える便利なコマンド等が定義されていることが多いです。例えば、Chef関連ですと、[serverspec](http://serverspec.org/)とよばれるインフラのテストに使われることが多くあります。

Chef関連で、使うのに十分だけの知識でいくと次の知識を知っていればよいでしょう。

### 4.1. Rakeで使えるコマンド
rakeで使えるコマンドを調べるためには一般的に下記のコマンドです。bundlerを使っている場合は、`bundle exec rake -T -A`ですね。

```
$ rake -T -A 
```

### 4.2. Rakeの設定ファイル
rakeで使えるコマンドは、Rakefileというファイルに定義されています。中身は、rakeで使うコマンドの定義になっています。細かく知りたい人は[Rake tutorial](http://jasonseifer.com/2010/04/06/rake-tutorial)が便利でしょう。

```
  task :turn_off_alarm do
    puts "Turned off alarm. Would have liked 5 more minutes, though."
  end
 
  task :groom_myself do
    puts "Brushed teeth."
    puts "Showered."
    puts "Shaved."
  end
 
  task :make_coffee do
    cups = ENV["COFFEE_CUPS"] || 2
    puts "Made #{cups} cups of coffee. Shakes are gone."
  end
 
  task :walk_dog do
    puts "Dog walked."
  end
 
  task :ready_for_the_day => [:turn_off_alarm, :groom_myself, :make_coffee, :walk_dog] do
    puts "Ready for the day!"
  end
```

上記のコマンドを実行すると下記のイメージです。このように、依存性をもったコマンドを簡単に定義できるツールなのです。

```
$ rake ready_for_the_day
  (in /Users/jason/src)
  Turned off alarm. Would have liked 5 more minutes, though.
  Brushed teeth.
  Showered.
  Shaved.
  Made 5 cups of coffee. Shakes are gone.
  Dog walked.
  Ready for the day!
```

上記のRakefileを持ったコマンドで、`rake -T -A`を実行すると次の通り。使えるコマンドが一覧されます。

```
$ rake -T -A
rake groom_myself       # 
rake make_coffee        # 
rake ready_for_the_day  # 
rake turn_off_alarm     # 
rake walk_dog           # 
```

5. Rubyの基本文法
---
Rubyの基本的な文法を学ぶには下記のチュートリアルがよいでしょう。

[Ruby Basic Tutorial](http://www.troubleshooters.com/codecorn/ruby/basictutorial.htm)
[Ruby チュートリアル](http://www.ruby.or.jp/ja/tech/development/ruby/tutorial/)

ちなみにchefのサイトにも[Just enough ruby](http://docs.opscode.com/just_enough_ruby_for_chef.html)というページがあります。


Rubyでやりたいことを逆引きしたい場合は次の本が便利です。

[Rubyレシピブック](http://www.amazon.co.jp/Rubyレシピブック-第3版-303の技-青木-峰郎-ebook/dp/B00E4FW2W6/ref=sr_1_3?ie=UTF8&qid=1404373113&sr=8-3&keywords=ruby+逆引き)

英語なら

[Ruby cookbook](http://www.amazon.com/Cookbook-Cookbooks-OReilly-Lucas-Carlson/dp/0596523696/ref=pd_sim_sbs_b_3?ie=UTF8&refRID=096Y8287KS9Z04P1526K)

6. Rubyのコーディング規約
---

[Japanese : cookpad / styleguide](https://github.com/cookpad/styleguide/blob/master/ruby.ja.md)

[English : A community-driven Ruby coding style guide](https://github.com/bbatsov/ruby-style-guide)

7. Rspec
---
[Rspec](http://rspec.info/)は、rubyでテストコードを書くためのライブラリです。Chefの文脈では、serverspecと呼ばれるインフラテストコードを書くときにつかわれるライブラリが基本的にrspecを利用しています。

### 7.1. Rspecのディレクトリ

Rspec関係のディレクトリ/ファイル構造は次の通り。テストプログラムは、慣習的に`xxxx_spec.rb`というファイル名になり、specディレクトリ配下におかれます。

```
- spec
 |- xxxx_spec.rb
  - spec_helper.rb
Rakefile
```

他の重要なファイルとして`spec/spec_helper.rb`というファイルがあります。これは、rubyで書かれたspecの共通ライブラリのようなもので、このファイルをspecファイルはインクルードして使います。ですので、よく、このファイルの変更をする機会が多くあります。テストの挙動がおかしいときは、よくこのファイルを再確認します。 下記のように記述されている、普通のrubyファイルになっています。

```
# -*- coding: utf-8 -*-

require 'serverspec'
require 'pathname'
require 'net/ssh'

include SpecInfra::Helper::Ssh
include SpecInfra::Helper::DetectOS

RSpec.configure do |c|
  if ENV['ASK_SUDO_PASSWORD']
    require 'highline/import'
    c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
  else
    c.sudo_password = ENV['SUDO_PASSWORD']
  end
  c.before :all do
    block = self.class.metadata[:example_group_block]
    :
```

最後にRakefileです。これは、先にご紹介したとおり、rubyの便利コマンド等が定義されるファイルですが、スペック実行を担当してくれる場合があり、Rakefileの中にspecを使うためのコードがかかれることがあります。

### 7.2. Rspecの実行方法

Rspecの実行方法は伝統的に２つの方法があります。 xxx_spec.rbのテストを流したいときは下記の通り。bundlerを使っているときは`bundle exec rspec ...`で実行してください。

```
$ rspec spec/xxx_spec.rb
```
他には、Rakefileでサポートされている場合があります。下記のコマンドで全スペックを流すような、スペックが実行されるケースがあります。

```
$ rake spec
```


### 7.3. Rspecの書き方

### 7.4. 参考

Rspecのよい書き方としては[Better specs](http://betterspecs.org/) [Better specs日本語訳](http://betterspecs.org/jp/)を参照にしましょう。

以上です