RubyistのためのClojure入門

[Puppet](http://puppetlabs.com/)が[RubyからClojureへ乗り換えていく](http://www.infoworld.com/article/2687553/devops/puppet-server-drops-ruby-for-clojure.html)ようです。

そんなRubyistが他にもいるかもしれないので、Rubyist向けにClojureだとどう書くか、みたいなガイドを書いてみます。

## イディオム

jnchitoさんの[Rubyイディオム記事](http://qiita.com/jnchito/items/dedb3b889ab226933ccf)をClojureで書くとどうなるか、まず説明したいと思います。

### 後置if で行数を減らす

```rb:ruby
send_mail_to(user) if user.active?
```

いきなりですが、Clojureには後置記法がありません。

```clj:clojure
(if (:active? user)
  (send-mail-to user))
```

慣例的な書き方では、おしりの括弧は改行入れずにまとめて書くので、他の言語のifブロックよりも1行少なくなります。

### if + notではなく、unlessを使う

```rb:ruby
user.destroy unless user.active?
```

Clojureにはこの目的の、`if-not`と`when-not`があります。

```clj:clojure
(if-not (:active? user)
  (destroy user))
```

どうしても`unless`キーワードじゃなきゃヤダというのであれば、マクロを使って`unless`構文を作ることができます。

```clj:clojure
(defmacro unless [condition success-body & failure-body]
  `(if-not ~condition ~success-body ~failure-body))

(unless (:active? user)
  (destroy user))
```

### 三項演算子を使って行数を減らす

```rb:ruby
user.admin? ? "I appreciate for that." : "Thanks"
```

そもそも多項演算子がデフォなので、「こういう場合は三項演算子を使わない」とかそういう議論が要りません。


```clj:clojure
(if (:admin? user) "I appreciate for that." "Thanks.")
```

if文もただのリストなので、もとより三項演算子っぽいです。


### 代入してからifで存在を確認、をまとめて書く

```rb:ruby
if user = find_user
  send_mail_to(user)
end
```

`if-let`は値が束縛できれば、与えられた式を評価する関数です。まったくもって上記のrubyのコードを同じことが、スマートに実現できます。

```clj:clojure
(if-let [user (find-user)]
  (send-mail-to user))
```

### 子どものオブジェクトが存在する場合にのみ、そのプロパティやメソッドを呼び出して条件を確認する、をひとつのifで書く

```rb:ruby
if parent.children && parent.children.singleton?
  singleton = parent.children.first
  send_mail_to(singleton)
end
```

Clojureのスレッディングマクロ`some->`は与えられた式を順に評価し`nil`になるとそこで停止するものです。Optionalを使ってやりたいであろうことが、このスレッディングマクロを使うとOptionalという概念を持ち込まずとも実現できます。

```clj:clojure
(if (some-> parent (.children) (.singleton?))
  (send-mail-to (.. parent children first)))
```

### メソッドの戻り値を返すときにreturnを使わない

```rb:ruby
def build_message(user)
  message = 'hello'
  message += '!!' if user.admin?
  message
end
```

これはClojureの場合当たり前ですが、`return`という概念がないので使えません。rubyと同じく、関数を評価した結果が返ります。

```clj:clojure
(defn build-message [user]
  (str "hello" (when (:admin? user) "!!")))
```

### 定数はfreezeさせる

```rb:ruby
ADMIN_NAMES = ["Tom", "Alice"].freeze
ADMIN_NAMES << "Taro" # => RuntimeError: can't modify frozen Array
```

これはClojureの強みです。値は決して変更できないので、freezeするという概念がありません。

```clj:clojure
=> (def admin-names ["Tom" "Alice"])
#'user/admin-names
=> (conj admin-names "Taro")
["Tom" "Alice" "Taro"]
=> admin-names
["Tom" "Alice"]
```

このように、`admin-names`に一度束縛した値はCollectionであっても変更はできません。変更しようとすると別の値が作られるだけです。

### 配列を作るとき、[ ]の代わりに%w( )、%i( )を使う

```rb:ruby
actions = %w(index new create)
```

残念ながらClojureにはこの機能はありません。しかしマクロがあります。

```clj:clojure
(defmacro %w [& words]
  (vec (for [w words] (str w))))

(%w hoge fuga piyo)
=> ["hoge" "huga" "piyo"]
```

(あ、これはジョークです)

### 要素の順番に意味がある配列は、同時に別々の変数で受け取る

```rb:ruby
quotient, remainder = 14.divmod(3)
puts "商は#{quotient}"      # => 商は4
puts "あまりは#{remainder}" # => あまりは2
```

Clojureにはこの目的で、デストラクティング構文があります。

```clj:clojure
(let [[quotient remainder] (divmod 14 3)]
  (puts "商は" quotient)
  (puts "あまりは" remainder))
```

これは強力で、複雑なデータ構造でも１回のletでそれぞれの変数に束縛できます。

```clj:clojure
(let [[[x1 y1][x2 y2]] [[1 2] [3 4]]]
  [x1 y1 x2 y2])
 
=>[1 2 3 4]
```

## Webフレームワーク

Railsのようなフルスタックなフレームワークはあまり流行してません。
Sinatra相当の[compojure](https://github.com/weavejester/compojure)と、Rack相当の[ring](https://github.com/ring-clojure/ring)がメジャーです。

compojureに関しては、そこそこ記事もあります。http://qiita.com/search?q=compojure

```clj:compojure
(GET "/user/:id" [id]
  (str "<h1>Hello user " id "</h1>"))
```

## テンプレート

Rubyの主要テンプレートライブラリであるhamlは、とてもS式です。

```rb:haml
!!!
%html{ :xmlns => "http://www.w3.org/1999/xhtml", :lang => "en", "xml:lang" => "en"}
  %head
    %title BoBlog
    %meta{"http-equiv" => "Content-Type", :content => "text/html; charset=utf-8"}
    %link{"rel" => "stylesheet", "href" => "main.css", "type" => "text/css"}
  %body
    #header
      %h1 BoBlog
      %h2 Bob's Blog
    #content
      - @entries.each do |entry|
        .entry
          %h3.title= entry.title
          %p.date= entry.posted.strftime("%A, %B %d, %Y")
          %p.body= entry.body
    #footer
      %p
        All content copyright © Bob
```

これをClojureのもっともメジャーなHTML出力ライブラリである[hiccup](https://github.com/weavejester/hiccup)を使うと、以下のように書けます。

```clj:hiccup
(html5 {:xmlns "http://www.w3.org/199/xhtml" :lang "en" "xml:lang" "en"}
  [:head
    [:title "BoBlog"]
    [:meta {:http-equiv "Content-Type" :content "text/html; charset=utf-8"}]
    [:link {:rel "stylesheet" :href "main.css" :type "text/css"}]]
  [:body
    [:div#header
      [:h1 "BoBlog"]
      [:h2 "Bob's Blog"]]
    [:div#content
      (for [entry entries]
        [:div.entry
          [:h3.title (:title entry)]
          [:p.date   (:posted entry)]
          [:p.body   (strftime "%A, %B %d, %Y" (:body entry]]))]])]
```

同じですね。それでいてhiccupはClojureの式そのものなので思考の切り替えなく、業務ロジックとHTML出力を書くことができます。

## お誘い

さて、少しでもClojureに興味を持っていただけたRubyistのみなさんに、ピッタリのイベントがあります。

10/10 19:00〜 Clojure夜会
http://01e8c979c4e57f83dd63bf3d4a.doorkeeper.jp/events/14626

ライトなClojureの話題が中心ですので、参加してみてください！