2018年3月15日木曜日

RubyでCSVを読み込む時に各行をPOROで取得出来るようにするGem「ReciteCSV」を作りました

RubyでCSVを読み込む時に各行をオブジェクト(PORO)で取得するGem「ReciteCSV」を作りました。
https://github.com/yujideveloper/recite_csv

どういうもの?

RubyでCSVを読むときに各行を普通のオブジェクト(PORO)で扱いたいことないですか?
僕はあります。

RubyでCSVを読み込む時は↓のような感じでHashっぽいCSV::RowのインスタンスかArrayで扱うことになりますよね。

CSV.foreach("example.csv", headers: true) do |row|
  puts row["col1"]
end

CSV.foreach("example.csv") do |row|
  puts row[0]
end

ReciteCSV使うと↓のような感じで使えるようになります。

class Hoge
  include ReciteCSV::Reader::Builder.new(col1: "COL1", col2: "COL2")
end

Hoge.new("./example.csv").each do |row|
  # 行オブジェクトであるrowはHoge::Rowクラスのインスタンスになります
  puts row.col1
end

特定のカラムの値を決まったルールで変換して処理するみたいなのもできたり。
カラムの変換ロジックを切り出せるのでテスト書きやすくなったりするかもしれません。

class Hoge
  include ReciteCSV::Reader::Builder.new(col1: "COL1", col2: "COL2")

  row_methods do
    # 行オブジェクトに全く新しいメソッドを追加可能
    def col1_ex
      "#{col1}改"
    end

    # 行オブジェクトのカラムにアクセスするメソッドをオーバーライド可能
    def col2
      "#{super} override"
    end
  end
end

Hoge.new("./example.csv").each do |row|
  puts row.col1_ex
  puts row.col2
end

ここまでのサンプルで気付いた方もいるかもしれませんが、これはCSV Readerクラスを作るのをサポートするためのGemです。
今のところWriterをサポートする予定はないです。いい感じのコードが思いついたらやるかもしれません。

こだわり

Module Builderパターンを採用しています。
Module Builderパターンについて知らない人はTechRachoさんの以下の記事が参考になるので読んでみると良いと思います。

Module Builderパターンを使ったおかげでancestorsもきれいになっているはずです。
作成されるReaderクラスやそのRowクラスのancestorsに無名モジュールや無名クラスが現れないように気を配ったりしてます。
無名クラスがあると継承関係を追いにくいとかありますしね。


おわりに

作りましたと言っても2017年末にはもう最初のバージョンをリリースしてました。
まだまだ怪しい挙動をするところなどあるかもしれませんが、良ければ使ってみてください。

ちなみにReciteCSVの名前の「Recite」は「朗読する」とかそういう感じのところから来ています。
CSVを朗読するように良い感じに扱いたいみたいな思いでつけました。

バグ修正とか機能追加とかなにかあれば気軽にPRもらえると嬉しいです。

0 件のコメント:

コメントを投稿