我是 ruby?? 的新手,并試圖弄清楚 Sequel gem 下面的類宣告是如何在幕后作業的。
class Enumeration < Sequel::Model(DB[:enumerations]); end
對 Sequel gem 的代碼進行快速調查后,在我看來,模塊方法 Sequel::Model 回傳一個具有配置類屬性的類實體。然后在繼承層次中使用Class的回傳實體,所以我嘗試通過代碼來測驗我的理解;
module MySequel
class MyModel
module ClassMethods
attr_accessor :table_name
def model(table_name)
klass = Class.new(self)
klass.table_name = table_name
puts klass.table_name # prints table_name, it does get set for the first class Class object klass
klass
end
end
extend ClassMethods
end
end
class Enumeration < MySequel::MyModel.model(:enumerations); end
class EnumerationValue < MySequel::MyModel.model(:enumeration_values); end
p Enumeration.table_name # prints nil
p EnumerationValue.table_name # prints nil
根據我的理解,在創建 Class 實體時會設定類變數table_name并傳播到它的子類中。然而,情況似乎并非如此。
有人可以解釋 Sequel::Model 背后的概念以及我的示例實作的問題以實作相同的結果。
此示例中的行為類似于使用上述匿名類時的行為。
class TestModel
@@table_name = 'test'
def TestModel.table_name
@@table_name
end
def TestModel.table_name=(value)
@@table_name = value
end
end
TestModel.table_name = 'posts'
p TestModel.table_name # prints posts
class ChildTestModel < TestModel; end
puts Enumeration.table_name # prints nil
Sequel 庫似乎通過呼叫模塊方法向子類(通過匿名類)傳播有關資料集集的資訊。
但是,我想不通;Ruby 語言的什么構造允許下面的 Status 類知道它僅限于表列舉中名稱設定為“status”的記錄。
class Status < Sequel::Model(DB[:enumerations].where(name: 'status')); end
uj5u.com熱心網友回復:
Sequel 庫似乎通過呼叫模塊方法向子類傳播有關資料集集的資訊
確實是的。Sequel 使用inherited回呼將類實體變數復制到子類(請參閱 參考資料lib/sequel/model/base.rb#843)。
這是您的示例類的一個非常基本的版本:
module MySequel
class MyModel
module ClassMethods
attr_accessor :table_name
def model(table_name)
klass = Class.new(self)
klass.table_name = table_name
klass
end
def inherited(subclass)
instance_variables.each do |var|
value = instance_variable_get(var)
subclass.instance_variable_set(var, value)
end
end
end
extend ClassMethods
end
end
因此,子類會將它們的類實體變數(此處@table_name)設定為與(匿名)父類相同的值:
class Enumeration < MySequel::MyModel.model(:enumerations); end
class EnumerationValue < MySequel::MyModel.model(:enumeration_values); end
p Enumeration.table_name #=> :enumerations
p EnumerationValue.table_name #=> :enumeration_values
uj5u.com熱心網友回復:
所以,大部分代碼是正確的,你對它如何作業的假設是正確的。這真的很棒,絕對不是紅寶石的新手級別!
那么,什么不起作用。當您定義某個類的子類時,該子類會繼承所有“類方法”(在引號中,因為實際上沒有這樣的東西),但不會繼承實體變數(即 - 類的實體的實體變數 Class ):
class A
@foo = 1
end
A.instance_variables #=> [:@foo]
class B < A; end
B.instance_variables #=> []
這意味著,如果您在model方法中創建的匿名類上呼叫 setter ,它只會在該類上設定實體變數。并且該匿名類的子類不繼承它。你可以看到這會起作用:
Enumeration = MySequel::MyModel.model(:enumerations)
EnumerationValue = MySequel::MyModel.model(:enumeration_values)
Enumeration.table_name #=> :enumerations
EnumerationValue.table_name #=> :enumeration_values
老實說,在這里對匿名類進行子類化并沒有太大的好處。這只有在您也一直快取這些類并且對該方法的單獨呼叫兩次回傳相同的 Class 物件時才有意義。
如果您仍然希望table_name可繼承,則需要對此非常明確,而不是使用attr_accessor,您需要直接查看超類:
attr_setter :table_name
def table_name
@table_name || (superclass.table_name if superclass.respond_to?(:table_name))
end
您可能需要在這里考慮一些調整。以上版本
uj5u.com熱心網友回復:
表名在定義 Enumeration 或 EnumerationValue 時設定,并保存在父類(這是一個匿名類)中。
對我個人而言,在將它與來自 javascript 的原型繼承進行比較時,掌握這個概念要簡單得多。
可以通過 Enumeration 和 EnumerationValue 類的超類訪問它。
# frozen_string_literal: true
module MySequel
class MyModel
module ClassMethods
attr_accessor :table_name
def model(table_name)
klass = Class.new(self)
klass.table_name = table_name
klass
end
end
extend ClassMethods
end
end
class Enumeration < MySequel::MyModel.model(:enumerations); end
class EnumerationValue < MySequel::MyModel.model(:enumeration_values); end
p Enumeration.superclass.table_name # prints :enumerations
p EnumerationValue.superclass.table_name # prints :enumeration_values
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/383469.html
上一篇:如何迭代不均勻陣列?
