--0016e6d999dacab35204659174a5
Content-Type: text/plain; charset=ISO-8859-1
Content-Transfer-Encoding: 7bit

2009/3/20 Ryan Davis <ryand-ruby / zenspider.com>

>
> On Mar 20, 2009, at 09:37 , Robert Klemme wrote:
>
>  On 20.03.2009 17:22, matt neuburg wrote:
>>
>>> Howdy. I am a class. There are certain rules for what you are supposed
>>> to do when you subclass me, so as a sanity check I wish to introspect
>>> your subclass to make sure it's obeying the contract.
>>> However, my problem is that self.inherited is called too early.
>>> class C # this is me
>>> def self.inherited(p)
>>>  #whatever
>>>  super
>>> end
>>> end
>>> class B < C # this is you
>>> # C's self.inherited is called right here
>>> def yourFirstMethod
>>>  # etc.
>>> end
>>> end
>>> So I can't, in my self.inherited, ask about what methods you have
>>> defined, because you haven't defined them yet. This must have come up
>>> before; is there an easy solution? Thx - m.
>>>
>>
>> Even after the class definition methods can be added.  You could catch
>> that with method_added but if you require a minimum set of methods to be
>> defined before class is used (e.g. instantiated) this will be difficult to
>> track.  One option would be to define method initialize in your class and do
>> the check there.  But this is still fragile because it might not be
>> guaranteed that sub classes invoke it from their initialize...
>>
>> Another option would be to override the sub class's method "new" so you
>> can do the check there.  This might be a bit more robust but even "new" can
>> be overridden by subclasses (although it isn't generally).
>>
>> I'd probably just omit the check.  If any of your superclass methods
>> invokes a method that is not defined you'll see this at runtime anyway.
>>
>
> I agree with this in general for Matt's particular problem. The smalltalk
> pattern of defining all contracted methods and having them raise
> SubclassResponsibility is a good one to use in this situation.


So, maybe a little helper:

class Module
  def abstract_methods(*names)
    names.each do |name|
      define_method(name) { raise SubclassResponsibility }
    end
  end
end

For example

class MyClass
  abstract_methods :foo, :bar
end

class Whizz < MyClass
  def foo; "foo!"; end
end

w  hizz.new
w.foo #"foo!"
w.bar #error: SubclassResponsibility

--0016e6d999dacab35204659174a5--