On 11.08.2009 21:23, Daniel W. wrote:
Hi. Consider the ruby-hmac gem:
http://pastie.org/580360
Line 81 makes the following call:
hmac = self.new(key)
But, insofar as I understand Ruby’s wonderful world context switching,
self, in the instance in which it is called, is both unnecessary
On first inspection, yes. But not if you look closer:
(because the method in which it is being called is already part of the
class) and incorrect (because the only initialize method available
requires more than one argument).
The method invoked is #new and not #initialize! This means that
argument lists of new and initialize need not be identical. You can
create a class whose Method.new has different arguments than
#initialize:
class Foo
def self.new(x)
o = allocate
o.send(:initialize, x, 1, 2)
o
end
def initialize(a, b, c)
# …
end
end
In this case it works differently though:
The file works (in some instances…), so I’ll assume my understanding
of Ruby is still poor. Which sucks because I thought I knew it fairly
well.
I’ve tried printing out self in each new context, and I get the expected
result (HMAC::Base). Except, that is, inside a Rails application running
on Ruby 1.9.1, in which case I get HMAC::SHA1 within the Base.digest
method. Awesome.
Any ideas?
The fact that the class is called “Base” indicates that it is intended
for inheritance. I don’t have a Ruby interpreter at hand right now to
cook up a tested example, but considering inheritance and the fact that
class methods are inherited by subclasses the whole thing actually makes
sense:
class SHA1 < Base
def initialize(key)
super(SHA1, 1024, 4096, key)
end
end
Now line 99 makes sense in combination with 81 / 91: Base.new is private
which will make self.new() trigger an exception and thus prevent
invocation of Base.digest() and Base.hexdigest(). But, you can invoke
SHA1.digest() and it will work.
Arguments algorithm, block_size and output_length to Base.initialize are
actually class dependent, i.e. every subclass likely defines their own
values.
Kind regards
robert