3
1

More than 3 years have passed since last update.

Ruby|csv_box を使ってもっと楽に CSV をつくりたい

Last updated at Posted at 2021-09-13

やりたいこと

CSV 出力は案件ごとに手製で作ることが多いと思います。業務で関わるサービスだと列数も多く、並び替えや条件による列の追加・削除でバグが起きやすいですよね。

問題はデータ部の出力と列の並びが直結しているので、それを分けてやると管理しやすいと考えました :smile:

require 'csv'

Book = Struct.new(:id, :title, :price)
books = [Book.new(1, 'How to cook delicious meals', 1500), Book.new(2, '10 tips to lose weight', 250)]

table = CSV::Table.new([])

headers = [
  'id',
  'title',
  ...
  'price'
]

# メンテナが代わることによる無理な列名の追加...
headers << 'tax price' if ....

books.each do |book|
  # ヘッダ部をみながらデータ部の並びを整えるのが大変...
  table << CSV::Row.new(headers, [book.id, book.title, ..., book.price])
end

puts table.to_csv

やってみたこと

数年前ですが、csv_box を作ってみました。Rails で使われることを想定していて、いまのところカラムの内容をそのまま出力します。

CSVBox.add で出力したい列を定義します。ここでは並びは関係なく、何を出力したいかです。引数にはモデル名など対象がわかるようにすると良いと思います。

CSVBox.add 'book' do
  field 'id'
  field 'title'
  field 'price'
end

CSVBox.layoutsCSVBox.add で登録した対象にどの順番で出力したいかを決めることができます。レイアウトに layout で名前をつけることができて CSV の作成時に使います。

CSVBox.layouts 'book' do
  layout 'shuffled layout' do |box|
    box.price
    box.id
    box.title
  end

 layout 'simple layout' do |box|
    box.title
    box.price
  end
end

CSVBox.take で対象の名前とレイアウト名を指定して、何をどうやって出力するかを決めます。<<CSV::Table を使って行を追加してたように追加することができます。

box = CSVBox.take 'book', 'shuffled layout'

books.each do |book|
  box << book
end

puts box.to_csv

__END__
price,id,title
1500,1,How to cook delicious meals
250,2,10 tips to lose weight

レイアウトの変更も楽で条件によって変えるのであれば次のようになります。

box = if ...
        CSVBox.take 'book', 'shuffled layout'
      else
        CSVBox.take 'book', 'simple layout'
      end

books.each do |book|
  box << book
end

puts box.to_csv

CSV 出力と分けて、対象の何を出力するのか、カラムの順番や条件をレイアウト毎に変えてやることによってかなりスッキリしたのではないでしょうか?今後ですが、例えば税込価格を表示したいなどその時だけの計算もあると思いますデコレータで逃げてもいいと思いますが、計算も組み込めるようになるのが今後の展望です。

3
1
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1