非常规方法(解决您提出的问题)
好的。为了后代,我将把代码放在这里如何完成你的要求。请记住,这不是该语言的使用方式。但是,如果您进入元编程,这将是非常有用的知识。
class Playlist
def display
puts "Your playlist name is #{name}"
end
private
def name
scope = ObjectSpace.each_object(Binding).to_a[-1]
scope.
local_variables.
select {|i| eval(i.to_s, scope) == self}.
map(&:to_s).delete_if {|i| i== "_"}.first
end
end
alternative = Playlist.new
# => #<Playlist:0x00000002caad08>
alternative.display
# Your playlist name is alternative
详细信息(工作原理)
好吧,让我解释一下这些部分。 ObjectSpace 是存储所有对象的地方。您可以通过调用 ObjectSpace.count_objects 来查看存在的对象数量。在我看来,最有用的特性是 each_object 方法。使用此方法,您可以迭代许多已创建的任何特定对象。因此,对于播放列表,您可以调用 ObjectSpace.each_object(Playlist) 并获得一个 Enumerable 对象。我们可以通过在末尾附加 .to_a 将其转换为列表。但是此时您将在这样的数组中获取播放列表的实例:[#<Playlist:0x0000000926e540>, #<Playlist:0x000000092f4410>, #<Playlist:0x000000092f7d90>]。如果您想单独访问它们并执行某些操作,这很有用。但这不是您想要做的,因为我们没有这些实例分配给的实例化变量名称。
我们真正想要调用的是 local_variables 方法,我们希望在主范围内(而不是在您的类范围内)调用它。如果您在显示方法中调用 local_variables,您将返回一个空数组 []。但是如果你在创建实例后在主控制台中调用它,你会得到类似[:alternative, :_] 的东西。现在我们在说话!现在存在从类外部获取范围以在其中使用的问题。这很难追踪。通常你可以将 binding 作为参数传入,甚至可以使用 TOPLEVEL_BINDING。但我注意到的一些事情告诉我,它们每个都创建了一个不会再更新的 Binding 实例。这意味着一旦您调用 TOPLEVEL_BINDING,您定义的任何其他内容(例如另一个播放列表)都不会更新,并且不会更新到您的 TOPLEVEL_BINDING.local_variables 列表中。这对我来说是一件可悲的事情。但我发现了解决这个问题的方法。
通过调用ObjectSpace.each_object(Binding).to_a,我们现在有了每个绑定实例的列表。所以我们只需要知道如何获得最新的最新版本。经过试验,我发现最后一个总是最新的。所以我们按[-1] 索引。现在我们可以在其上调用 .local_variables ,我们将始终获得全局范围内的最新实例变量集合。这很棒!现在我们只需要将实例变量与我们所在的当前播放列表匹配。所以我们从全局 local_variables 中选择任何匹配当前实例的变量。我们需要调用 eval 来获取实例,并且使用 eval 我们需要告诉它要运行的范围,所以我们使用select {|i| eval(i.to_s, scope) == self}。从那里我们获取符号并使用 .map(&:to_s) 将它们映射到字符串,最后我们的列表中有一个我们不需要的额外项目。下划线符号是一种 Ruby 技巧,用于获取最后处理的内容。所以我们需要删除它,因为它评估为与我们当前变量实例相同的 id。所以我们做 .delete_if {|i| i== "_"}。最后,它是一个项目列表,我们想要的东西,所以我们用 .first
来挑选它
注意:这种范围选择方法在 Rails 中不起作用。实例化了许多绑定。带有 local_variables 的最后一个和最大的不是最新的。
这经历了许多非常规的方式来完成您所询问的任务。现在,您可能不知道命名播放列表类之类的标准方式,这没关系。一开始没人知道,这是一种后天习得的特质。
命名播放列表的传统方式
这是命名播放列表类的首选方法。
class Playlist
def initialize(name)
@name = name
end
def display
puts "Your playlist name is #{@name}"
end
end
list = Playlist.new("Alternative")
list.display
# => "Your playlist name is Alternative"
这是相当直截了当的。最好按照设计使用语言的方式工作。
如果我是你,我会列出一个播放列表项目数组并像这样使用它。
list = []
list << Playlist.new("Alternative")
list << Playlist.new("Rock")
list
# => [#<Playlist:0x000000028a4f60 @name="Alternative">, #<Playlist:0x000000028e4868 @name="Rock">]
list[0].display
# Your playlist name is Alternative
list[1].display
# Your playlist name is Rock
现在您有了一个播放列表列表!甜!
当您进入元编程时,您可能会使用这里非常规方法的许多功能。元编程是代码编写代码的地方。很好玩!