前回の更新からちょっと時間が空いてしまいました 💦
小ネタです。掲題の通りderiveJsonNoPrefixというパッケージをリリースしました。
地味に有用だと思うので、READMEをやや意訳気味に翻訳して記事にします。
十分に単純なので、仕様が変わることもまさかないでしょうし。
以下、こちらのコミットの時点のREADMEの翻訳です。
Link to
herederiveJsonNoPrefix
プレフィックスに優しいToJSONとFromJSONのインスタンスを定義するTemplate Haskellのマクロを提供します。
Link to
here例
こんな感じのJSONを作りたいとしましょう:
{
"id": "ID STRING",
"max": 0.789,
"min": 0.123
}きっと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をもう自分で定義する必要がありません!🙌
import Data.Aeson.DeriveNoPrefix
$(deriveJsonNoTypeNamePrefix ''SomeRecord)👆 のderiveJsonNoTypeNamePrefix は deriveJSONと同様に、ToJSONとFromJSONのインスタンス、両方を生成します。
もちろん、FromJSONのインスタンスを生成するときのオプションとしても、プレフィックスを削除するためのfieldLabelModifierを渡してくれます!
Link to
here同じ問題を解決するほかのライブラリー
- extensible.
- など、
ToJSON・FromJSONのインスタンスが定義されたextensible recordを提供するライブラリー
なので、そうしたextensible recordを提供するライブラリーが学習コストや依存関係などの事情で「重たい」と感じたときにこのパッケージを使ってください。