From: Tanaka Akira Date: 2006-10-15T05:12:08+09:00 Subject: [ruby-dev:29666] Re: Digest'ifying OpenSSL::Digest In article <86bqofkz9t.knu@iDaemons.org>, "Akinori MUSHA" writes: >  今いろいろ悩んでいるのは、キーやハッシュ長などのパラメータを > 取るアルゴリズムをどう扱うかです。 > > >  たとえば、あるメソッドがハッシュアルゴリズムの指定を受けると > したときを考えます。 > >  まず、 > > check_auth(cookie, "MD5") > > と名称を文字列で渡す方法では、パラメータの指定が困難です。 > > check_auth(cookie, "HMAC;hash=MD5;key=blahblahblah") > > と DBI みたいな感じにしたのでは、指定もパースも面倒なので論外。 > >  また、 > > check_auth(cookie, Digest::MD5) > > のようにクラスオブジェクトを渡す方法がありますが、パラメータ付き > アルゴリズムの場合、パラメータ(の組合せ)ごとに固有のクラスを作る > のかというと躊躇します。(digest/hmac で一度やってみました) > >  かといって、 > > check_auth(cookie, Digest::Tiger, 160) > > のようにパラメータを並べて渡すのでは「計算器」をひとまとまりで > 指定できていないので美しくない。 > >  計算器を渡す、という意味では > > check_auth(cookie, Digest::Tiger.new(160)) > > というのがひとつの解決策であり、現時点の digest はこのような形を > 想定していますが、いくつか問題もあります。 > > ・同時に複数の計算器インスタンスを必要とする場合、 clone() して > もらうのか? > ・状態のあるものをやりとりするのは気持ち悪い。使用前・使用後に > reset() する責任の有無などが気になる。 > >  つまり、渡すべきなのは計算器そのものではなくて、計算器の生成 > 方法であるということになります。 > >  ということは、先ほどのクラスオブジェクトを渡す方法がいちばん > 近そうです。あるべき姿は > > ・Digest 実装クラスは new() でパラメータを受け取り、 factory > オブジェクトを生成する。 > ・factory オブジェクトは自身の生成時に指定されたアルゴリズムと > パラメータに沿った「計算器」を生成する能力(メソッド)を持つ。 そのメソッドひとつに関して多態であればいいのであれば、そのメ ソッドの名前を call にして、factory の生成には引数のない lambda を使えばいいのでは? パラメータをとらないアルゴリズムに対応するクラスについてはク ラスオブジェクト自身が call を持つことにすればクラスオブジェ クト自身が factory とも振る舞えますし。 > といった形でしょうか。でも、まじめにそうしてしまうとあんまり > 使いやすい感じはしないですね。 > > tiger160 = Digest::Tiger.new(160) > hash = tiger160.create() > hash.update(data) > digest = hash.digest > > JCE の Mac クラスなどはこんな感じのインターフェースですが、 > 果たして Ruby にマッチするのかどうか。 class << Digest::SHA256; alias call new; end class << Digest::SHA512; alias call new; end ... としておいて、 p Digest::Tiger.new(160).update(data).digest p Digest::SHA256.new.update(data).digest と直接使ってもいいし、 p lambda { Digest::Tiger.new(160) }.call.update(data).digest p Digest::SHA256.call.update(data).digest と call で呼べる factory 経由でやってもいいということで、 check_auth(cookie, lambda { Digest::Tiger.new(160) }) check_auth(cookie, Digest::SHA256) というようにアルゴリズムを受け取るメソッドには lambda ないし クラスを指定し、場合によっては check_auth(cookie) { Digest::Tiger.new(160) } check_auth(cookie) { Digest::SHA256.new } とブロックを使いたくなるかもしれない、とか。 -- [田中 哲][たなか あきら][Tanaka Akira]