本文介绍了当前对象/类实例的名称的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我需要加载一个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#classinstance#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

这篇关于当前对象/类实例的名称的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!

08-05 10:03