使用MetaProgramming 動態定義類別
使用MetaProgramming寫程式的確和以往有很多不一樣的地方,例如,我可以在程式中讀取資料庫中的表格名稱和欄位名稱,然後根據表格的Schema動態產生一個類別定義,並且利用此類別產生Instance,像下面這樣:(注:為求簡化範例,資料庫存取的部份用模擬的)
class MetaProgrammingTest
# class method for creating a new class
def self.create_class(class_name, attr_names)
# use class name to create a class
klass = Object.const_set(class_name,Class.new)
klass.class_eval do
attr_accessor *attr_names
define_method(:initialize) do |*values|
attr_names.each_with_index do |name,i|
instance_variable_set("@"+name, values[i])
end
end
define_method(:to_s) do
str = "[#{self.class}:"
attr_names.each {|name| str << " #{name}=#{self.send(name)}" }
str + "]"
end
end
# return the class
klass
end
end
class TestDBSchemaReader
def self.getTableNameFromDB
# 下列程式可以改成從資料庫取得Table Name
return "Person"
end
def self.getAttributeNamesFromDB(table_name)
# 下列程式可以改成從資料庫取得Table的所有欄位名稱
return ["name", "age"]
end
end
table_name = TestDBSchemaReader.getTableNameFromDB
attr_names = TestDBSchemaReader.getAttributeNamesFromDB(table_name)
# 動態產生一個新的類別
myCls = MetaProgrammingTest.create_class(table_name, attr_names)
# 動態產生一個新的類別的Instance
vo = myCls.new("richard", 15)
puts "class name=" + vo.class.name
puts "instance: vo.name = " + vo.name + ", vo.age=" + vo.age.to_s
執行結果像這樣
>ruby meta_programming_test.rb
class name=Person
instance: vo.name = richard, vo.age=15
>Exit code: 0
類別"Person"被動態的定義了,而且還使用此類別建立了Instance,蠻容易的,不是嗎?
更厲害的是,動態定義的類別還可以被繼承,像下列這段,我在程式後方又加上了一個GoodPerson類別,繼承自動態定義出來的Person類別:
class MetaProgrammingTest
# class method for creating a new class
def self.create_class(class_name, attr_names)
…
…
…
#更神奇的是,動態定義的類別還可以被繼承
class GoodPerson < Person
def hello
print "我是#{@name},我今年#{@age},我被發好人卡了!\n"
end
end
gp = GoodPerson.new("steve", 31)
執行結果
>ruby meta_programming_test.rb
class name=Person
instance: vo.name = richard, vo.age=15
我是steve,我今年31,我被發好人卡了!
>Exit code: 0
更進一步的,我還可以在這個GoodPerson類別中,動態加入新method:
...
...
procBlock = proc { |x| puts "the " + x + "is a nerd!" }
GoodPerson.class_eval do
define_method(:showNerd, procBlock)
end
gp.showNerd "jonny"
執行結果
>ruby meta_programming_test.rb
class name=Person
instance: vo.name = richard, vo.age=15
我是steve,我今年31,我被發好人卡了!
the jonnyis a nerd!
>Exit code: 0
沒有留言:
張貼留言