Ruby默認提供了define_method
等工具用於動態定義實例方法,但貌似沒提供動態定義類的方法。sql
所謂動態定義類,不是指動態建立類,而是指類名是用字符串或符號動態給定的。看完《Ruby元編程》後,我嘗試着本身實現一個:數據庫
module Kernel def define_class(name, ancestor = Object) Object.const_set(name, Class.new(ancestor)) Object.const_get(name).class_eval(&Proc.new) if block_given? Object.const_get(name) # return defined class always end end
你可能會困惑,動態定義類有什麼用?我遇到的一個應用場景就是用在ActiveRecord
同時訪問多個數據庫時,須要定義多個ActiveRecord::Base
的子類,以下:編程
def LocalBase < ActiveRecord::Base self.abstract_class = true establish_connection adapter: "sqlite3", database: "local.db" end def RemoteBase < ActiveRecord::Base self.abstract_class = true establish_connection adapter: "sqlite3", database: "remote.db" end
能夠看出裏面有重複的代碼,使用define_class
就能規避這些重複的代碼:ruby
YAML.load(File.read("db.yaml")).each do |name, info| define_class(name, ActiveRecord::Base) do self.abstract_class = true establish_connection info end end
同時,我把數據庫鏈接信息移到了db.yaml
文件中:工具
LocalBase: adapter: sqlite3 database: local.db RemoteBase: adapter: sqlite3 database: remote.db