Ruby標準ライブラリのDigestでの const_missing の用法
Digestには何があったかなと思って、ruby/ext/digestを見てみたら、lib/digest.rbに以下のようなコードあった。Rubyはハッシュ関数として、MD5、SHA1、SHA2、RDM160というのなんかをサポートしてる。BubbleBabbleというマイナーなものも入ってるらしい。で、これらはCでモジュール化されていて、呼ばれたときに初めてロードされる。というのが、以下のコード。Digetst::Hoge.newなどとすると、libにHogeが入っていれば、require される。
require 'digest.so' module Digest def self.const_missing(name) # :nodoc: case name when :SHA256, :SHA384, :SHA512 lib = 'digest/sha2.so' else lib = File.join('digest', name.to_s.downcase) end begin require lib rescue LoadError raise LoadError, "library not found for class Digest::#{name} -- #{lib}", caller(1) end unless Digest.const_defined?(name) raise NameError, "uninitialized constant Digest::#{name}", caller(1) end Digest.const_get(name) end
なんだか分からなかったのは、::Digest::Class というクラス。
module Digest : class ::Digest::Class # creates a digest object and reads a given file, _name_. # # p Digest::SHA256.file("X11R6.8.2-src.tar.bz2").hexdigest # # => "f02e3c85572dc9ad7cb77c2a638e3be24cc1b5bea9fdbb0b0299c9668475c534" def self.file(name) new.file(name) end # Returns the base64 encoded hash value of a given _string_. The # return value is properly padded with '=' and contains no line # feeds. def self.base64digest(str, *args) [digest(str, *args)].pack('m0') end end
コメントを読んでもピンと来なかったけど、これは、
module Digest class SHA2 < Digest::Class
などと継承が前提の、ほとんど中身のないクラスだった。クラスメソッドとして、Digest.fileを定義して、それをインスタンスメソッドに渡すような役割りをしている。DigestはCとRubyが入り混じっていて、ぼくには読むのが難しい。