James Coglan
3/20/2009 6:52:00 PM
[Note: parts of this message were removed to make it a legal post.]
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 = Whizz.new
w.foo #=> "foo!"
w.bar #=> error: SubclassResponsibility