RubyでExcelファイルを読み込むgem「roo」を使う

## 概要

rubyからスプレッドシート形式のファイルを操作するgem、rooの使用方法。

この記事では、主にExcelファイルを扱う際に使用出来るメソッドなどを調べてみます。
基本的に、READMEから使えそうなものを紹介し、その後実際に簡単な操作をしてみることにします。

[roo-rb/roo: Roo provides an interface to spreadsheets of several sorts.](https://github.com/roo-rb/roo)



## 動作環境

* OS X El Capitan 10.11.6

* ruby 2.2.6

* roo 2.7.1



## 今回使用するExcelファイル

以下のようなデータを持ったExelファイルを操作します。

<img width="384" alt="スクリーンショット 2017-12-07 22.03.38.png" src="https://qiita-image-store.s3.amazonaws.com/0/174052/7da273e5-5332-e16c-b10b-6829ce051fca.png">

## rooのインストール

ターミナルで以下のコマンドを実行してrooのインストールを行います。
ファイル名は`roo_test.xlsx`です。

```sh
$ gem install roo
```



## Excelファイルを読み込んでみる

以下のようなコードで指定したファイルを読み込むことができます。

```ruby:roo_sample.rb
require 'roo'

xlsx = Roo::Excelx.new('./roo_test.xlsx')
```



## 読み込んだファイルに対して操作する

ファイル読み込み&基本情報出力

```ruby
require 'roo'
xlsx = Roo::Excelx.new('./roo_test.xlsx')

puts xlsx.info
# =>
# File: roo_test.xlsx
# Number of sheets: 1
# Sheets: Sheet1
# Sheet 1:
#   First row: 1
#   Last row: 4
#   First column: A
#   Last column: D
```

以下、ファイルはすでに読み込まれているとします。

エクセルシートから行ごとにデータを読み出す。

```ruby
xlsx.each_row_streaming do |row|
  puts row.inspect
end
# 例として1列目のデータを表示
# =>
# [
#   #<Roo::Excelx::Cell::String:0x007fd1298442f0 @link=false, @cell_value="名前", @cell_type=:string, @formula=nil, @style=0, @coordinate=#<Roo::Excelx::Coordinate:0x007fd129845268 @row=1, @column=1>, @type=:string, @value="名前">,
#   #<Roo::Excelx::Cell::String:0x007fd12983fa20 @link=false, @cell_value="国語", @cell_type=:string, @formula=nil, @style=1, @coordinate=#<Roo::Excelx::Coordinate:0x007fd12983ff98 @row=1, @column=2>, @type=:string, @value="国語">,
#   #<Roo::Excelx::Cell::String:0x007fd12983f048 @link=false, @cell_value="算数", @cell_type=:string, @formula=nil, @style=1, @coordinate=#<Roo::Excelx::Coordinate:0x007fd12983f7f0 @row=1, @column=3>, @type=:string, @value="算数">,
#   #<Roo::Excelx::Cell::String:0x007fd12983e5a8 @link=false, @cell_value="理科", @cell_type=:string, @formula=nil, @style=1, @coordinate=#<Roo::Excelx::Coordinate:0x007fd12983ee90 @row=1, @column=4>, @type=:string, @value="理科">
# ]
```

### `each_row_streaming`で使用出来るオプション
デフォルトで空のセルは除外されるが、`pad_cells: true`を指定することでそれらを残すことができます。

```ruby
xlsx.each_row_streaming(pad_cells: true) do |row|
  puts row.inspect
end
```

指定した行だけをストリーミングすることができます。
`offset`で最初に飛ばす行数を指定
`max_rows`でストリーミングする行数を指定

```ruby
xlsx.each_row_streaming(offset: 1, max_rows: 1) do |row|
  puts row.inspect
end
# max_rowsが取り出す行数はmax_rowsで指定した数+1になることに注意
# この場合、飛ばす行数1かつ取り出す行数1+1=2より山田小林の2行で処理が行われる
```

その他`Roo::Excelx`で使えそうなメソッド

```ruby
p xlsx.excelx_type(4, 'A')
# 指定したセルの型を返す
# => :string

p xlsx.cell(3, 'A')
# 指定したセルの値を返す
# => "小林"
```

## エクセルのデータを集計してみる

先ほどのExcelファイルを利用して、それぞれの合計点数を計算してみます。

```ruby:calc_sum.rb
require 'roo'

xlsx = Roo::Excelx.new('./roo_test.xlsx')

xlsx.each_row_streaming(offset: 1) do |row|
  sum = 0
  row.each do |cell|
    next if cell.value.nil? || cell.cell_type[0] != :numeric_or_formula
    sum += cell.value
  end
  puts "#{row[0]}さんの合計点数は#{sum}です。"
end
# =>
# 山田さんの合計点数は190です。
# 小林さんの合計点数は140です。
# 佐藤さんの合計点数は260です。
```


## まとめ

RubyからExcelファイルを操作できるgemであるrooを使ってみました。  
ファイルを読み込み、その数値を利用し集計、出力することができました。

他にも、CSVなど他のデータ形式に変換するなど、できることはまだまだありそうなので、また機会があれば詳しく調べていきたいと思っています。