前回の更新からちょっと時間が空いてしまいました 💦
小ネタです。掲題の通りderiveJsonNoPrefixというパッケージをリリースしました。
地味に有用だと思うので、READMEをやや意訳気味に翻訳して記事にします。
十分に単純なので、仕様が変わることもまさかないでしょうし。
以下、こちらのコミットの時点のREADMEの翻訳です。
Link to
herederiveJsonNoPrefix
プレフィックスに優しいToJSON
とFromJSON
のインスタンスを定義するTemplate Haskellのマクロを提供します。
Link to
here例
こんな感じのJSONを作りたいとしましょう:
きっとToJSON(おそらくそれに加えてFromJSONも)のインスタンスを自動的に定義するための、次のようなレコード型を定義したくなるでしょう。
{-# LANGUAGE TemplateHaskell #-}
import Data.Aeson.TH
data SomeRecord = SomeRecord
{ id :: String
, max :: Double
, min :: Double
} deriving (Eq, Show)
$(deriveToJSON defaultOptions ''SomeRecord)
しかし、こんなレコード型は定義すべきではありません。
id
もmax
もmin
も、Prelude
に定義済みなのですから!
この問題を回避するために、レコードラベルに型の名前をプレフィックスとして加える、ということをわれわれはよくやります。
data SomeRecord = SomeRecord
{ someRecordId :: String
, someRecordMax :: Double
, someRecordMin :: Double
} deriving (Eq, Show)
そして、deriveToJSON
にデフォルトと異なるオプションを渡して実行します。
deriveToJSON Json.defaultOptions { fieldLabelModifier = firstLower . drop (length "SomeRecord") } ''SomeRecord
firstLower :: String -> String
firstLower (x:xs) = toLower x : xs
firstLower _ = error "firstLower: Assertion failed: empty string"
fieldLabelModifier
オプションは文字通り、対象のレコードをJSONに変換するとき、あるいはJSONから対象のレコードの値に変換する時、レコードのラベルを変換する関数を設定するために使います。
👆の場合、プレフィックスであるSomeRecord
の文字数分レコードラベルからdrop
して、先頭の文字(someRecordId
で言えばId
のI
に相当します)を小文字に変換しているのがわかるでしょうか?
そう、これがderiveToJsonNoTypeNamePrefix
がやっていることとほぼ同等のことです。
deriveToJsonNoTypeNamePrefix
は、実質次のように定義されています。
deriveToJsonNoTypeNamePrefix :: Name -> Q [Dec]
deriveToJsonNoTypeNamePrefix deriver name =
deriveToJSON Json.defaultOptions { fieldLabelModifier = dropPrefix name } name
dropPrefix :: Name -> String -> String
dropPrefix name = firstLower . drop (length $ nameBase name)
firstLower :: String -> String
firstLower (x:xs) = toLower x : xs
firstLower _ = error "firstLower: Assertion failed: empty string"
結果、これからはfieldLabelModifier
をもう自分で定義する必要がありません!🙌
👆 のderiveJsonNoTypeNamePrefix
は deriveJSONと同様に、ToJSON
とFromJSON
のインスタンス、両方を生成します。
もちろん、FromJSON
のインスタンスを生成するときのオプションとしても、プレフィックスを削除するためのfieldLabelModifier
を渡してくれます!
Link to
here同じ問題を解決するほかのライブラリー
- extensible.
- など、
ToJSON
・FromJSON
のインスタンスが定義されたextensible recordを提供するライブラリー
なので、そうしたextensible recordを提供するライブラリーが学習コストや依存関係などの事情で「重たい」と感じたときにこのパッケージを使ってください。