From: Jano Svitok Date: 2008-03-03T17:58:52+09:00 Subject: Re: Understanding ruby classes On Mon, Mar 3, 2008 at 9:07 AM, Damjan Rems wrote: > > This question is all about me not understanding how ruby classes work. > > I have three print classes. myPrint which is abstract class and > implements common methods for other two classes which are myPrint2PDF > and myPrint2HTML. They implement all the troubles of output to PDF or > HTML format. Without too much code, implementation looks like this: > > class myPrint > def printHDR > end > .... > end > > class myPrint2PDF << myPrint > .... > end > > class myPrint2HTML << myPrint > .... > end > > > Then I have fourth class which implements the job which has to be done. > > class myPrint001 << myPrint2PDF > def printHDR > image 'image.jpg' 20, 1 > print 'some header text' 1,5 > ... > end > def doJob > print 'some text' 1,5 > end > end > > Here is my catch 22. I would REALLY like to call my implementation > class like this: > pr = myPrint001 :format => 'HTML' or > pr = myPrint001 :format => 'PDF' > pr.doJob > > I have made statement 'class myPrint001 << myPrint2PDF' intentionaly > wrong and I know it does not provide the real solution, but this is how > it works for now. > > What would be the best (ruby) solution to this problem. 1. Convention is to start class names with a capital letter - it's related to the fact that class is a constant. for method, lowercase_letters_with_underscores are used. It's nice to get used to it, because most of the ruby stuff is written so. 2. if you derive a subclass, use only one '<', i.e. class MyPrint2PDF < MyPrint 3. Now the real problem: You have several possibilities: - one is to create a 'register' somewhere, and register the classes with it (I'm writing out of my head, without running the code!) require 'singleton' class PrintFormatRegister include Singleton def initialize @formats = {} end def register_format(format, klass) @formats[format] = klass end def get_format(format) return @formats[format] end end # now, in your class MyPrint2PDF < MyPrint # call the register: PrintFormatRegister.instance.register_format 'PDF', self # here comes your code ... end You don't need to derive myPrint001 from any of the previous classes, just call their methods. i.e. class MyPrint001 def print_hdr(format) formatter = PrintFormatRegister.instance.get_format(format) || raise 'unknown format' # for the case, when format is unknown ... # do what you need end end 4. Design note: Try to keep classes to one responsibility. In ruby, you don't have to use inheritance as much as you might be used to from other languages. Try to choose names that describe the functionality (MyPrint001 is not such a name, unless there's something missing).Think of looking at your code after several months - would you be able to find out what MyPrint001 does without looking at the actual code?