From: Dave Thomas Date: 2001-12-04T06:44:01+09:00 Subject: [ruby-talk:27377] Re: Selecting class based on external information Jeff Putsch writes: > Howdy, > > I'm trying to select the class for an instance variable based on external > information and cannot figure out how. For example: > > class Host > # variables and routines common to all hosts, default values for > # OS specific things > end > > class SunOS < Host > # overrides for OS specific things > end > > # main routine would do this... > > OSname = `/bin/uname -s`.chomp > > myHost = OSname.new # on a Solaris system this should > # be equivalent to doing "myHost = SunOS.new" > > The initialization of "myHost" is where I run into trouble. I can not figure > out how to do this. I'm sure Ruby has some "magic" to get this done, but > it's beyond me ... Well, there are a number of ways: 1. Brute force... Add a factory method somewhere that has def HostFactory(osname) case osname when /SunOS/ return SunOS.new when /Linux/ return Linux.new etc.. 2. Dangerous, but Extract the name of the OS from uname into some cannonical form, and use that as the classname os_name = extract_name_from(`uname -s`) myHost = eval(os_name) 3. MOre complex, but sexier: Have the Host class hierarchy manage itself, and generate the factory method semi-automatically. For example: class Host ## # This is a simple factory system that lets us associate fragement # types (a string) with a subclass of fragment TYPE_MAP = {} def Host.os_name(name) TYPE_MAP[os_name] = self end # Here's the factory method def Host.for(os_name, *args) klass = TYPE_MAP[0s_name] || raise("Unknown host: #{os_name}") return klass.new(*args) end # .. rest of class Host end Then, when you define your subclasses, do class SunOS < Host os_name "SunOS" # ... end class Linus < Host os_name "Linus" # ... end To get the right object given an os_name, you jst call my_host = Host.for(os_name) Regards Dave