From: Stefano Crocco Date: 2008-03-08T00:11:43+09:00 Subject: Re: Dynamic class thingies? (Okay, not sure how to title this one) Alle Friday 07 March 2008, coigner ha scritto: > Asking for ideas here but let me preface... > > There's an application with a sqlite3 database that I'm building Ruby > classes and methods for accessing. ActiveRecord was close but no cigar > because I have no control over the database and there are quirks in there > I want to "hide". Besides, I'm still newish to Ruby and want the exercise > of doing it myself even at the risk of re-inventing the wheel. > > Okay so tables are objects and rows are objects. I have a table class and > a row class and specific tables and rows inherit from them. At the end, > you get nice little methods like: > > table.find(some_search_criteria) > > that returns an array of row objects. > > Over time, as I've worked on this and picked up more on Ruby, I've been > moving more things up into the table superclass. Noticing as I've gone > along that a great deal of code was identical in the subclasses. I'm > actually down to something fairly simple that takes the array of records > (an array of hashes actually) sqlite returns and "packages" them into row > objects then returns them. > > This code is pretty much identical in all cases *except* that the row > objects are different. That is, something like this in the subclass: > > def find(criteria) > results = [] > do_find(criteria).each { |res| > results << Transaction.new(res) > } > return results > end > > "do_find" being inherited and containing all the contortions and hoop > jumping that results in a SQL statement from the "criteria". > > The only difference now between the different subclasses is the line: > > results << Transaction.new(res) > > Such as, say there's a table for "accounts" then the line is: > > results << Account.new(res) > > The table classes are plural (rather Railsish I guess ) of the row > classes. Transaction being the row class, Transactions being the table > class, etc. > > So it occurs to me that deriving the row class from the name of the table > class is trivial. So I could generalize this all even further if I could > figure out a way to create a new row object of the class that is singular > of the table class. > > Having bopped about Ruby a while now, I have a sneaking suspicion there's > a way to do this. If I "self.class" in the superclass' code, I'm getting > the name of the table instance ("Transactions" for instance). I can... > what's the word... "singularize" (?) it and have "Transaction" so I know > the name of the row class I need to instantiate. > > But there I'm stuck. I have the name of the class as a string but that > doesn't do me any good. I keep thinking (and have been digging through > several Ruby books but I'm not tumbling to this yet) that there's some > way to do something sort of: > > results << magical_thing_here.new(res) > > Where "magical_thing_here" takes that string and lets Ruby know I mean > "this is a name of a class". > > What am I missing? > > I mean, besides a lot more experience with Ruby. You want Kernel.const_get. As the name suggests, it takes a string and returns the value of the constant with that name. For instance: class C end Kernel.const_get('C').new => # If your classes are defined top-level, that's all you need. If they're defined inside a module, you need to call const_get for that module: module M class C end end M.const_get('C').new I hope this helps Stefano