apple_health_export 出力の整形

前回
iPhone のヘルスケア apple_health_export - hs9587’s diary
iPhone に入れたヘルスケア情報を csv に出来た。
そうするとこんな感じになる

20200418053000+0900,35.9,degC,HKQuantityTypeIdentifierBodyTemperature
20200417211100+0900,36,degC,HKQuantityTypeIdentifierBodyTemperature
20200417155800+0900,36.1,degC,HKQuantityTypeIdentifierBodyTemperature
20200417055000+0900,36.2,degC,HKQuantityTypeIdentifierBodyTemperature
20200416221500+0900,36,degC,HKQuantityTypeIdentifierBodyTemperature
20200416054000+0900,35.9,degC,HKQuantityTypeIdentifierBodyTemperature
20200415052400+0900,35.9,degC,HKQuantityTypeIdentifierBodyTemperature

十分わかり易い形だが、コンピューターで読むのではなく、人が見るならもう少し整形しても良い。

format_cda.rb

require 'csv'
require 'time'

CSV::Converters.merge!( {
  row3: ->(cell, info){ info.index != 3 ? cell : cell[24..-1]   },
  row1: ->(cell, info){ info.index != 1 ? cell : '%2.1f' % cell },
  row0: ->(cell, info){ info.index != 0 ? cell : \
          Time.parse(cell).strftime('%Y-%m-%d %H:%M %z')[2..-3] },
} )

CSV.filter(out_col_sep: "\t", converters: [:row0, :row1, :row3]) {}

そうするとこんな感じ

20-04-18 05:30 +09      35.9    degC    BodyTemperature
20-04-17 21:11 +09      36.0    degC    BodyTemperature
20-04-17 15:58 +09      36.1    degC    BodyTemperature
20-04-17 05:50 +09      36.2    degC    BodyTemperature
20-04-16 22:15 +09      36.0    degC    BodyTemperature
20-04-16 05:40 +09      35.9    degC    BodyTemperature
20-04-15 05:24 +09      35.9    degC    BodyTemperature

CSV(library csv (Ruby 2.7.0 リファレンスマニュアル)) の普段僕が余り使わない機能を使ったので少しコードの説明。

普段 CSV.parse とか CSV.read で読むと配列の配列になるのでいろいろしていた。
今回は入力を少し整形してすぐ出力するフィルターが良いと思った、 CSV.filter
https://docs.ruby-lang.org/ja/latest/class/CSV.html#S_FILTER があった。

カンマ区切りはコンピュータとのやり取りには良いのだけど、人が見るにはちょっとうるさいかな、出力はタブにしましょう、オプションに「out_col_sep: "\t"」。
入出力オプションほかのはこの辺
class CSV (Ruby 2.7.0 リファレンスマニュアル) を参考に、出力なので頭に「out_」か「output_」を付けるとのこと。

書式の変換には converters: オプションと CSV::Converters
https://docs.ruby-lang.org/ja/latest/class/CSV.html#C_-CONVERTERS を使ってみる。
コンヴァーターの実装

  row3: ->(cell, info){ info.index != 3 ? cell : cell[24..-1]   },
  row1: ->(cell, info){ info.index != 1 ? cell : '%2.1f' % cell },
  row0: ->(cell, info){ info.index != 0 ? cell : \
          Time.parse(cell).strftime('%Y-%m-%d %H:%M %z')[2..-3] },

その適用時、列数の指定とかはないみたい。どの列にもみんな適用されるので第二引数から列数を確認する。「?」三項演算子(
https://docs.ruby-lang.org/ja/latest/doc/spec=2foperator.html#cond
)、本当は否定の条件は避けるべきなんだが、可変部を後ろにした方が分かり易いかとそうした。二列目 row2 は儘なので書かない。

コンヴァーターを使うことにしたら、CSV.filter のブロックでやることが無くなったので空っぽのブロックを付ける「 {} 」

CSV.filter(out_col_sep: "\t", converters: [:row0, :row1, :row3]) {}

空っぽのブロックって、他になんか書き方無いのかな。