Hashie::Dashでお手軽validationあるいはリソースを信用できるかどうか問題

intridea/hashie: Hashie is a collection of classes and mixins that make hashes more powerful.

まとめ

  • Ruby で nil を避ける方法は事前に validate する方法と取得時、利用時に気をつける方法がある
  • 事前に validate できる方が安心だしテストも楽(影響範囲が小さい)
  • いくつか validator はあるが Hashie::Dash は validate 機能内蔵していてかなりお手軽でいい感じ
    • 独立した validator を使うのは大袈裟だなと感じるようなカジュアルなシーンにハマりそう

Rubyでnilを避ける方法百選

nil が入るかもしれないところのコードをどうするかにはいくつか方法がある。

  • ActiveSupport の try
  • ぼっち演算子 (&. )
  • 文字列と分かっているなら .to_s
  • 逆に Hash から取り出す時に死んでほしい Hash#fetch
  • 素朴に nil?

などなど。

逆に DBMS 前提なら例えば ActiveRecord で

create_table do |t|
  t.string  :name, null: false
end

とすると name に nil を入れて save することはできない。

ま、扱うオブジェクトによっていろいろある。

事前に弾くのか、取得時に考慮するのか

上に挙げた例はアプローチが正反対である。

  • 前者は値の取得時、利用する際に nil を避ける方法
  • 後者はそもそも nil が入らないようにする方法

今回は後者の nil が入らないようにするということを validation と呼ぶことにしている。

Hashie::Dashの使い方

Hashie::Dash はみんな大好き Hashie::Mash に事前の property 定義が書けるもの。以下のような感じ。

class Model < Hashie::Dash
  property :foo, required: true
end

これで

Model.new(foo: nil)

とすると

ArgumentError: The property 'foo' is required for Model.

というエラーになる。おぉ、これならふいに nil を踏むことはなくなるじゃん。逆に

Model.new(foo: 'nil', bar: 1)

になると

NoMethodError: The property 'bar' is not defined for Model.

で、余計な property を突っ込むこともできない。

m = Model.new(foo: 'nil')
m.bar = 1

だと

NoMethodError: undefined method `bar=' for #<Model foo="nil">

おおおお。初期化時だろうと動的な変更だろうと弾いてくれる。

ということで Dash は以下のようなものらしい。

  • Hashie::Dash は事前に property を定義することができる Mash のようなもの
  • property の validation が自動で行われる
  • required: true の property は必須でかつ nil を与えることはできない
  • 余計な property を追加することもできない

intridea/hashie: Hashie is a collection of classes and mixins that make hashes more powerful.

の例を見ると他の property を参照することもできる。けっこう便利。

まぁ Rails 使ってるなら ActiveModel できっちり固めるという方法もあると思うし、Hanami みたいに dry-validation で schema を書くという方法もあると思うけど、もっとカジュアルに使いたいよねって時に Hashie::Dash で validate しておくと、単なる Hash より

  • いい具合にオブジェクトっぽく振舞ってくれる
  • 事前の定義で比較的安全に扱えるようにできる

ということが分かった。

なるほどな。

More