Ruby で エクセルファイルを扱うインターフェイスを整える（rrxcell gem の宣伝）

# 何がしたかったか？

ruby でエクセルファイルを扱うとき、代表的な gem として　[roo](https://github.com/roo-rb/roo) や [rubyXL](https://github.com/weshatheleopard/rubyXL) などがあります。

ただ、それぞれの gem によって書き込み・読み込み・新規作成が可能かどうかが違っていたり、扱うファイルの形式（「xls」ファイルと「xlsx」）でインターフェイスが違っていたりと、なかなか使いづらいというのが正直な感想です。

それで「それぞれの gem の得意なところを組み合わせて、インターフェイスだけ整えればいいのや」という考えになりました。

# 前提条件

- エクセルファイル中のデータを値として取得する。
- フォントや書式は考慮しない。
- 「xls」形式も「xlsx」形式も統一的に扱う。

# とりあえず gem 化

色々なプロジェクトで使えるように、便利なものは共有した方が良い。
というわけで gem にすることにしました。

[rrxcell](https://github.com/sekizo/rrxcell)

名前は「rrxcell」としました。
由来は「Ruby Reader for eXcel  Cell」・・・だったかな？　忘れてしまいました（笑）。

気持ち的には「らくさせる」と読みたいところですが、「あるあるえっくすせる」でお願いします。


gem の作り方は、他のサイトに譲ります。

- [RubyGemはめっちゃ簡単に作れる！](http://morizyun.github.io/blog/ruby-gem-easy-publish-library-rails/)

- [君がOpsでもRubyで書いたライブラリはGemで配ろう](http://qiita.com/sawanoboly/items/ede7715c605e5822ad22)

など、ネット上で「gem 作り方」で検索をかけると、色々な情報が見つかります。


# インターフェイスを考える

## セルの値の取得
エクセルのワークブック・ワークシート・行・カラムを、メソッドチェーンでアクセスして値が読み出せれば分かりやすいと考えました。

``` ruby:セルの値を読み込むインターフェイス
puts book.sheet(0).row(0).column(0).value
# => "Sheet1!A1"

puts book[0][1][2].value
# => "Sheet1!C2" 

```

プログラマであれば、配列インデックスの開始点は「0」（ゼロ）の方がしっくりくる気がします（偏見）。
ワークシート・行・カラムのいずれも、開始点を「0」からとしました。
２つ目の例では、カラムのインデックスより先に行のインデックスが来ています。

これで、ワークシートの中の値を取得するだけなら Range#each で回すだけで OK です。

## ワークブックの読み込み

ファイルの読み込み時に「xls」ファイルと「xlsx」ファイルの違いを気にしなくていいようにしたいと考えました。

``` ruby:ファイルを読み込むインターフェイス
path = File.expand_path("PATH/TO/FILE.xlsx") # or "PATH/TO/FILE.xls"
book = Rrxcell.load(path)
```

今回作成した rrxcell を作るまでは、加工前のファイルが「xls」形式か「xlsx」形式かで、[roo](https://github.com/roo-rb/roo) や[roo-xls](https://rubygems.org/gems/roo-xls)、場合によっては  [rubyXL](https://github.com/weshatheleopard/rubyXL) を使い分けていました。

それぞれファイルの読み込みや新規作成のインターフェイスが違っていたので、プログラムの改変・修正するたびに利用法を調べ直したりも面倒でした。

## より「直感的な」セルへのアクセス

ワークシート・セルへのアクセスを、配列的に（インデックスで）行なうのとは別に、ワークシートの名前や「A1」形式でのアクセスもできれば簡単だろうと考えました。

``` ruby:より「直感的な」アドレスの利用
puts book.address("Sheet1!B2").value
# => "Sheet1!B2"

puts book.sheet(0).address("B2").value
# => "Sheet1!B2"

puts book.sheet("Sheet1").address("AB3").value
# => "Sheet1!AB3"
```

３番目の例、文字列でワークシートのインデックスを指定する部分は、少し迷いました。
\#sheet の引数を数値限定にして、\#address の引数を文字列限定にする案もあったのですが、プログラム的にはあまり難しいところはないと考え、使いやすさを優先しました（v0.2.0 時点）。

# 今までの成果

エクセルファイルをデータソースとして捉えた時に、データの値が読み込めれば OK という前提で行けば、かなりシンプルなインターフェイスで扱えると思います。

フォントなどの書式へのアクセスや、書き出し・保存のインターフェイスに関しては、バージョンアップするか別の gem にまとめようか現在検討中ですが、何もしない可能性もあります（現状 v0.2.0 で十分なので）。

あとは、ファイルの書式・用途に合わせて専用のリーダークラスを作れば、データの変換が楽になるはずです。

例えば「**毎月**、**数社**の協力業者から送られて来る、それぞれ**別の書式**で書かれたスケジュールの**エクセルファイル**から、必要なスケジュールの日付とタスクを抽出する」など。

# 蛇足

最後の例文を読んで薄々気づいているかと思いますが、実際には「そのため」に作った gem です（笑）。

そもそも「それ用の WEB システム」を作るなり、他の Saas などを使った方が**最終的には**楽なんでしょうが、協力業者の中には PC ・スマホの操作が難しい世代・事情の方々もいるし、システムの開発・操作教育（協力業者含め）にコストをかけるのが難しい企業の事情、既存システムで痒い所に手が届くか（孫の手問題）などもあります。

今の資産・手法を「できる範囲で自動化**していく**」という視点で見ると、システムを持っている側で変換用のサブシステム（孫の手）を作る、いうことの第一歩になったのではないかと思います。

# さらに蛇足

エクセルファイル嫌い。

# 参照

- [rrxcell - https://github.com/sekizo/rrxcell](https://github.com/sekizo/rrxcell)

- [roo - https://github.com/roo-rb/roo](https://github.com/roo-rb/roo) 
- [roo-xls - https://rubygems.org/gems/roo-xls](https://rubygems.org/gems/roo-xls)
- [rubyXL - https://github.com/weshatheleopard/rubyXL](https://github.com/weshatheleopard/rubyXL)

- [RubyGemはめっちゃ簡単に作れる！](http://morizyun.github.io/blog/ruby-gem-easy-publish-library-rails/)

- [君がOpsでもRubyで書いたライブラリはGemで配ろう](http://qiita.com/sawanoboly/items/ede7715c605e5822ad22)

ほか、各種サイト。