From: Robert Klemme Date: 2007-12-16T21:40:00+09:00 Subject: Re: Abstract -- what's the Ruby way? On 13.12.2007 07:58, Charles Oliver Nutter wrote: > rbaldwin wrote: >> On Dec 12, 5:10 pm, "Tim Rowe" wrote: >>> What's the Ruby way to define a class that shouldn't be instantiated, but >>> with descendants that can be? Other than a comment in the documentation, of >>> course. >>> >>> Thanks! >> Here is one way. Its not very satisfying, as you have no way to access >> the initialize method on any parent classes of the Animal class (such >> as ActiveRecord)... > > You could privatize new and define a new new for inheriting classes that > calls the old new: > > class Animal > class << self > private :new > def inherited(cls) > cls.instance_eval "def new(*args); super; end" > end > end > end > > class Dog < Animal > > puts Dog.new # => # > pust Animal.new => NoMethodError: private method 'new' called for Animal... > > I use instance_eval here because I don't like the semantics of > define_method (or I dislike them more than eval magic); but it would > probably work about the same. > > The downside of this approach is subclasses that want to also define > their own 'new' would have to know to call super. I'd expect that's > pretty rare. This downside can be easily avoided: simply change #inherited to make new public again instead of redefining it. irb(main):001:0> class Animal irb(main):002:1> class < private :new irb(main):004:2> def inherited(cl) irb(main):005:3> class < public :new irb(main):007:4> end irb(main):008:3> end irb(main):009:2> end irb(main):010:1> end => nil irb(main):011:0> class Dog < Animal irb(main):012:1> end => nil irb(main):013:0> Animal.new NoMethodError: private method `new' called for Animal:Class from (irb):13 from :0 irb(main):014:0> Dog.new => # irb(main):015:0> Kind regards robert