First, I am likely doing something very wrong and simply
misunderstanding how class variables work. I’m a Perl guy by default so
this is my first big project in Ruby.
I’m trying to store another (unrelated) instantiated class in them so
that each time I instantiate a subclass I don’t have to repeatedly
instantiate the unrelated classes. Not sure how else to say it, but
that certainly sounds like that sentence got away from me. Here is my
example (stripped down pseudo code so hopefully it still compiles…)
Here is what I WAS trying:
(it blows up)
class Importer
def initialize()
@@config = Config.new() if @@config.nil?
@@api = API.new() if @@api.nil?
@@util = Util.new() if @@util.nil?
@@db = DB.new() if @@db.nil?
@@dbh = @@db.dbh if @@dbh.nil?
end
def import()
raise "this is abstract"
end
end
Then I have multiple sub classes such as:
class ItemDataImporter < Importer
def import()
# do stuff
end
end
I’ve tried this:
(It works but instantiates Config/API/Util and DB for every subclass I
instantiate)
def initialize()
@@config = Config.new() if @@config.nil?
@@api = API.new() if @@api.nil?
@@util = Util.new() if @@util.nil?
@@db = DB.new() if @@db.nil?
@@dbh = @@db.dbh if @@dbh.nil?
end
def import()
raise "this is abstract"
end
end
I’ve tried this as well (also blows up)
class Importer
@@config = Config.new() if @@config.nil?
@@api = API.new() if @@api.nil?
@@util = Util.new() if @@util.nil?
@@db = DB.new() if @@db.nil?
@@dbh = @@db.dbh if @@dbh.nil?
def import()
raise "this is abstract"
end
end
Again, I’m certain it is just me either me misunderstanding the purpose
of class variables or misunderstanding something else entirely.
Any help would be mucho appreciated. Thanks in advance for fixing my
dumb.
class Importer
def initialize()
@@config = Config.new() if @@config.nil?
@@api = API.new() if @@api.nil?
@@util = Util.new() if @@util.nil?
@@db = DB.new() if @@db.nil?
@@dbh = @@db.dbh if @@dbh.nil?
end
def import()
raise "this is abstract"
end
end
Then I have multiple sub classes such as:
class ItemDataImporter < Importer
def import()
@@dbh[:items].insert(:item_id => 6, :name => ‘Item Name’);
end
end
class PriceImporter < Importer
def import()
@@dbh[:prices].insert(:price => 3.99, :item_id = 6 );
end
end
Imagine there being another 10 *Importer classes.
I was hoping to have @@dbh to be shared by both item_data_importer and
price_importer so I didn’t have to have a ton of DB connections. Or so
I didn’t have to have my @@config loaded into memory multiple times.
If I didn’t care about that, I could easily just use a single @ and it
would be just fine. I was just trying to be clever and more efficient
with resources. That and learn something new in the process.
The problem is, it appears when I instantiate ItemDataImporter it
properly sets @@db, @@dbh, etc but when PriceImporter gets instantiated
it resets @@db and @@dbh (thus making a second connection to the db). I
was hoping that the first *Importer class that got instantiated would
set up the db connection and then the following *Importer classes that
got instantiated would be able to share it.
I spent quite a bit of time searching the web and couldn’t find how to
do this specific thing which was leading me to believe I am simply being
dumb.
I was hoping to have @@dbh to be shared by both item_data_importer and
price_importer so I didn’t have to have a ton of DB connections. Or so
I didn’t have to have my @@config loaded into memory multiple times.
Did you try to have your importer as this:
class Importer
@@config=Config.new()
@@api=API.new()
@@util=Util.new()
@@db=DB.new()
@@dbh=@@db.dbh
def import()
raise “this is abstract”
end
end
Note that, in this case, the class variables are created when the file
is first parsed (i.e. at the time when ‘require lib/importer’ is
executed), not when the first object is created.
I was hoping to have @@dbh to be shared by both item_data_importer and
price_importer so I didn’t have to have a ton of DB connections. Or so
I didn’t have to have my @@config loaded into memory multiple times.
If I didn’t care about that, I could easily just use a single @ and it
would be just fine. I was just trying to be clever and more efficient
with resources. That and learn something new in the process.
If this is the real goal, I wouldn’t solve it using class variables or
class instance variables, I’d solve it using dependency injection.
Take the resources that your class depend on, and make responsibility
of other class the instantiation and handling of them to the
appropriate instances. In practice:
class Importer
def initialize(db) @db = db
end
def import()
raise "this is abstract"
end
end
class ItemDataImporter < Importer
def import() @db[:items].insert(:item_id => 6, :name => ‘Item Name’);
end
end