0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Money::Currencyをテストのときに初期化する話

Last updated at Posted at 2020-10-13

RubyMoneyを使ってお金の管理をしているプロダクトは多いのではないでしょうか。
RubyMoneyはデフォルトで通貨の設定を提供してくれていますが、要件に応じてその設定を上書きすることもできます。
多くのシステムの場合、アプリのビルド時に一度設定をしてしまえばその後設定を変更することはないと思いますが、ことテストの文脈においては、一度変更してしまった設定を初期化したいことがあるのではないでしょうか。

この記事では、そんなときどうやってRubyMoneyの通貨設定を初期化するかを解説します。

前提として、通貨の設定は下記のように行います。

cad = Money::Currency.find(:cad)

cad.name # => Canadian Dollar

Money::Currency.register(
  :priority            => cad.priority,
  :iso_code            => cad.iso_code,
  :name                => 'Something Different',
  :subunit             => cad.subunit,
  :subunit_to_unit     => cad.subunit_to_unit,
  :thousands_separator => cad.thousands_separator,
  :decimal_mark        => cad.decimal_mark
)

cad = Money::Currency.find(:cad)
cad.name # => Something Different

Money::Currency クラスは @table というインスタンス変数で通貨の設定を管理しています。よってこのインスタンス変数をリセットできればよさそうです。
しかし仕様上直接 @table にアクセスはできないので、下記のようにして初期化を行います。

 Money::Currency.instance_variable_set('@table', nil)
 Money::Currency.table # => reloading the initial setting

簡単ですね。と思いきや上記の初期化を行ってもまだ上書きされた値を受け取ってしまいます。

cad = Money::Currency.find(:cad)
cad.name # => Something Different
Money::Currency.instance_variable_set('@table', nil)
Money::Currency.table
cad = Money::Currency.find(:cad)
cad.name # => Something Different. 初期化されていない!

詳しくライブラリの実装を追うと、その答えが分かります。一度変更された設定は、アプリケーションが起動されてから、つまりRubyプロセスが立ち上がってから、そのプロセスが終了するまで、一貫性を持っている必要があります。
その仕様を実現するため、さらに Money::Currency はインスタンス自体をクラス変数として管理しています。
そうすることで、ライブラリユーザーである我々は、開発中設定について気にする必要がなくなると言うわけです。
ということを踏まえた上で、改良したコードが以下です。

cad.name # => Something Different
Money::Currency.class_variable_set('@@instances', {})
Money::Currency.instance_variable_set('@table', nil)
Money::Currency.table
cad = Money::Currency.find(:cad)
cad.name # => Canadian Dollar

無事初期化されました、このコードをspec_helperなどに書いておけば、テスト中の Money::Currency の設定上書きに依存しないテストを担保することができます。

でもわざわざこの設定を書くのって面倒くさいですよね。
実は最新のRubyMoney::Moneyのmasterはこの初期化を行うAPI Money::Currency.reset! を提供しています。
これがその変更のプルリクエストです。
もしこの機能を使ってみたい方がいれば最新のmasterをインストールしてみてください。
RubyMoney::Money の次のアップデートバージョンが早くリリースされることを願っています。

英語版はこちら

0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?