我希望创建一种方法,使子类在类级别上表达一些业务定义。
我试图使用类变量来实现这个目的,但是我发现它们在所有类之间共享状态,所以一旦我定义了第二个类,“@”属性类变量就为所有相邻的类实例更改其值。
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工具的三元组之一,大多数有经验的Rubiest很少使用。相反,您希望使用类级实例变量,Parent
是类的实例。
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"
首先,类方法
Class
称为“setter”,类方法“type”称为“getter”。你有个二传手,在争论如果你这样做,你怎么才能得到它的价值呢要同时使用它作为一个getter,您必须执行以下操作: def self.type=(value=nil)
if value.nil?
@type
else
@type = value
end
end
在这里,定义一个getter更有意义
def self.type
@type
end
没有setter,只是写,例如,
type=
。这是不可靠的,只有当您不想将
type
设置为@type = "name"
时才有效您也可以将方法保留为setter并使用@type
获取其值,但这同样糟糕最好有一个二传手和一个盖特手。当使用setter时,我们需要在
nil
前面加上self.class.instance_variable_get(:@type)
来告诉ruby我们希望调用getter,而不是将局部变量type
设置为给定值。当然,我们可以只写,例如,`@type=“title”。创建setter和getter的传统方法是编写
self.
(调用类方法Module#attr_accessor)由于类方法存储在类的singleton类中,可以按以下方式执行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
现在考虑实例方法
type
作为实例方法,它的接收者是类(或子类)的实例,比如attr_accessor :type
这意味着当在方法Parent#render
中调用parent = Parent.new
时,等于render
。但是,我们想调用类方法self
。因此,我们必须将parent
转换为type
,这是用parent
实现的。一另外两个(当然,在我看来)是全局变量和
Parent
循环。他们在ruby新手中的受欢迎程度可能是因为他们倾向于在许多学习ruby的书籍的第一章中首次亮相。2在
self.class
的单例类中有很多定义for
的方法。另外两个是attr_accessor
和Parent
。