问题描述
我需要加载一个YAML文件(我正在尝试使用SettingsLogic),并且我希望该实例以与其相同的 name 加载YAML.简要地:
I need to load a YAML file (I'm experimenting with SettingsLogic) and I'd like the instance to load the YAML with the same name as it. Briefly:
class MySettings < SettingsLogic
source "whatever_the_instance_is_called.yml"
# Do some other stuff here
end
basic_config = MySettings.new # loads & parses basic_config.yml
advanced_cfg = MySettings.new # loads & parses advanced_cfg.yml
...and so on...
这样做的原因我还不知道我必须加载哪些配置文件,然后键入:
The reason for this I don't yet know what configuration files I'll have to load, and typing:
my_config = MySettings.new("my_config.yml")
或
my_config = MySettings.new(:MyConfig)
似乎只是在重复自己.
我浏览了Google和Stackoverflow,最接近答案的是"获取实例名称"或有关实例名称无意义的讨论! (不过,我可能查询错了.)
I took a look around both Google and Stackoverflow, and the closest I came to an answer is either "Get Instance Name" or a discussion about how meaningless an instance name is! (I'm probably getting the query wrong, however.)
我尝试过instance#class
和instance#name
;我也尝试过instance#_id2ref(self)
.
I have tried instance#class
, and instance#name
; I also tried instance#_id2ref(self)
.
我想念什么?!
提前谢谢!
推荐答案
O.K.,所以在分配局部变量时会遇到一些障碍,例如分配可能会比在局部变量列表中添加局部变量符号稍晚一些.但是,这是我的模块ConstMagicErsatz
,我用来实现类似于开箱即用的Ruby常数魔术的一些东西:
O.K., so with local variable assignment, there are snags, such as that assignment might occur slightly later than local variable symbol addition to the local variable list. But here is my module ConstMagicErsatz
that I used to implement something similar to out-of-the box Ruby constant magic:
a = Class.new
a.name #=> nil - anonymous
ABC = a # constant magic at work
a.name #=> "ABC"
这里的优点是您不必编写ABC = Class.new(name:"ABC"),名称被神奇地"分配了.这也适用于Struct类:
The advantage here is that you don't have to write ABC = Class.new( name: "ABC" ), name gets assigned 'magically'. This also works with Struct class:
Koko = Struct.new
Koko.name #=> "Koko"
,但没有其他类别.因此,我的ConstMagicErsatz
允许您这样做
but with no other classes. So here goes my ConstMagicErsatz
that allows you to do
class MySettings < SettingsLogic
include ConstMagicErsatz
end
ABC = MySettings.new
ABC.name #=> "ABC"
以及
a = MySettings.new name: "ABC"
a.name #=> "ABC"
在这里:
module ConstMagicErsatz
def self.included receiver
receiver.class_variable_set :@@instances, Hash.new
receiver.class_variable_set :@@nameless_instances, Array.new
receiver.extend ConstMagicClassMethods
end
# The receiver class will obtain #name pseudo getter method.
def name
self.class.const_magic
name_string = self.class.instances[ self ].to_s
name_string.nil? ? nil : name_string.demodulize
end
# The receiver class will obtain #name setter method
def name= ɴ
self.class.const_magic
self.class.instances[ self ] = ɴ.to_s
end
module ConstMagicClassMethods
# #new method will consume either:
# 1. any parameter named :name or :ɴ from among the named parameters,
# or,
# 2. the first parameter from among the ordered parameters,
# and invoke #new of the receiver class with the remaining arguments.
def new( *args, &block )
oo = args.extract_options!
# consume :name named argument if it was supplied
ɴς = if oo[:name] then oo.delete( :name ).to_s
elsif oo[:ɴ] then oo.delete( :ɴ ).to_s
else nil end
# but do not consume the first ordered argument
# and call #new method of the receiver class with the remaining args:
instance = super *args, oo, &block
# having obtained the instance, attach the name to it
instances.merge!( instance => ɴς )
return instance
end
# The method will search the namespace for constants to which the objects
# of the receiver class, that are so far nameless, are assigned, and name
# them by the first such constant found. The method returns the number of
# remaining nameless instances.
def const_magic
self.nameless_instances =
class_variable_get( :@@instances ).select{ |key, val| val.null? }.keys
return 0 if nameless_instances.size == 0
catch :no_nameless_instances do search_namespace_and_subspaces Object end
return nameless_instances.size
end # def const_magic
# @@instances getter and setter for the target class
def instances; const_magic; class_variable_get :@@instances end
def instances= val; class_variable_set :@@instances, val end
# @@nameless_instances getter for the target class
def nameless_instances; class_variable_get :@@nameless_instances end
def nameless_instances= val; class_variable_set :@@nameless_instances, val end
private
# Checks all the constants in some module's namespace, recursivy
def search_namespace_and_subspaces( ɱodule, occupied = [] )
occupied << ɱodule.object_id # mark the module "occupied"
# Get all the constants of ɱodule namespace (in reverse - more effic.)
const_symbols = ɱodule.constants( false ).reverse
# check contents of these constant for wanted objects
const_symbols.each do |sym|
# puts "#{ɱodule}::#{sym}" # DEBUG
# get the constant contents
obj = ɱodule.const_get( sym ) rescue nil
# is it a wanted object?
if nameless_instances.map( &:object_id ).include? obj.object_id then
class_variable_get( :@@instances )[ obj ] = ɱodule.name + "::#{sym}"
nameless_instances.delete obj
# and stop working in case there are no more unnamed instances
throw :no_nameless_instances if nameless_instances.empty?
end
end
# and recursively descend into the subspaces
const_symbols.each do |sym|
obj = ɱodule.const_get sym rescue nil # get the const value
search_namespace_and_subspaces( obj, occupied ) unless
occupied.include? obj.object_id if obj.kind_of? Module
end
end
end # module ConstMagicClassMethods
end # module ConstMagicErsatz
以上代码实现了整个Ruby名称空间的自动搜索,目的是在每次调用#name方法时查找哪个常量引用给定实例.
The above code implements automatic searching of whole Ruby namespace with the aim of finding which constant refers to the given instance, whenever #name method is called.
使用常数的唯一约束是,您必须将其大写.当然,您想要的是在对象已经生成并分配给常量之后修改该对象的元类.再一次,由于没有钩子,因此您必须找到执行此操作的机会,例如首次将新对象用于其目的时.因此,
The only constraint using constants gives you, is that you have to capitalize it. Of course, what you want would be modifying the metaclass of the object after it is already born and assigned to a constant. Since, again, there is no hook, you have to finde the occasion to do this, such as when the new object is first used for its purpose. So, having
ABC = MySettings.new
然后,当首次使用MySettings实例时,在进行其他操作之前,先修补其元类:
and then, when the first use of your MySettings instance occurs, before doing anything else, to patch its metaclass:
class MySettings
def do_something_useful
# before doing it
instance_name = self.name
singleton_class.class_exec { source "#{instance_name}.yml" }
end
# do other useful things
end
这篇关于当前对象/类实例的名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!