我希望创建一种方法来使Children类在类级别上表达一些业务定义。
我试图为此使用类变量,但是我发现它们在所有类之间共享状态,因此一旦定义了第二类,“ @@ attribute”类var就会更改所有相邻类实例的值。
>class Parent
def self.type(value)
@@_type = value
end
def render
puts @@_type
end
end
class Children < Parent
type "name"
end
Children.new.render # Result: name. Expected: name
class Children2 < Parent
type "title"
end
Children2.new.render # Result: title. Expected: title
Children.new.render # Result: title. Expected: name
如何以最简单直接的方式创建此DSL? 这是HTTParty,Virtus等几种Ruby Gems的常见模式。
我什至试图查看他们的源代码以了解其工作方式,但是对于我想要的东西来说似乎太复杂了。
感谢您的帮助!
答案 0 :(得分:1)
类变量是Ruby工具的老三级之一,大多数经验丰富的Rubiesst很少使用(如果有的话)。 1 。相反,您想使用类级实例变量,Parent
是类Class
的实例。
class Parent
def self.type=(value)
@type = value
end
def self.type
@type
end
def render
puts self.class.type
end
end
class Children < Parent
self.type = "name"
end
Children.new.render
#=> "name"
class Children2 < Parent
self.type = "title"
end
Children2.new.render
#=> "title"
Children.new.render
#=> "name"
首先,类方法type=
被称为“ setter”,而类方法“ type”被称为“ getter”。您有一个二传手type
,在吵架。如果这样做,您将如何获得其价值?要将其用作吸气剂,您还必须执行以下操作:
def self.type=(value=nil)
if value.nil?
@type
else
@type = value
end
end
在这里定义一个吸气剂会更有意义
def self.type
@type
end
并且没有设置器,只写例如@type = "name"
。
这很麻烦,仅当您不想将@type
设置为nil
时才有效。您也可以将方法保留为设置方法,并使用self.class.instance_variable_get(:@type)
来获取其值,但这同样令人恐惧。最好有一个setter和一个getter。
使用setter时,我们需要在type
前面加上self.
来告诉Ruby,我们希望调用getter而不是将局部变量type
设置为给定值。当然,我们可以只写“ @type =“ title”。
创建setter和getter的常规方法是编写attr_accessor :type
(调用类方法Module#attr_accessor)。由于类方法存储在类的单例类中,因此可以按以下方式进行 2 :
class Parent
class << self
attr_accessor :type
end
def render
puts self.class.type
end
end
class Children < Parent
self.type = "name"
end
Children.new.render
#=> "name"
class Children2 < Parent
self.type = "title"
end
现在考虑实例方法Parent#render
。作为实例方法,它的接收者是类(或子类)的实例,例如parent = Parent.new
。这意味着在方法render
中调用self
等于parent
。但是,我们要调用类方法type
。因此,我们必须将parent
转换为Parent
。{p}
1。另外两个(当然,我认为)是全局变量和self.class
循环。他们在Ruby新手中的流行可能是由于他们倾向于在许多学习Ruby的书的第1章中首次亮相。
2。在for
的单例类中定义attr_accessor
的方法有很多。其他两个是Parent
和singleton_class.instance_eval do { attr_accessor :type }
。
答案 1 :(得分:-1)
好吧,我不知道为什么会这样,但是它是这样工作的:
class Parent
class << self
attr_accessor :_type
def type(value)
self._type = value
end
end
def render
puts self.class._type
end
end
我真的很想理解为什么,但是“ self.class”和“ class << self”对我来说似乎很黑暗。
光?