首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >当前对象/类实例的名称

当前对象/类实例的名称
EN

Stack Overflow用户
提问于 2012-11-08 23:45:03
回答 4查看 3.4K关注 0票数 1

我需要加载一个YAML文件(我正在试验SettingsLogic),并且我希望实例以与它相同的名称加载YAML。简要说明:

代码语言:javascript
复制
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...

原因是我还不知道必须加载哪些配置文件,并输入:

代码语言:javascript
复制
my_config = MySettings.new("my_config.yml") 

代码语言:javascript
复制
my_config = MySettings.new(:MyConfig) 

好像是在重复我自己。

我环顾了一下Google和Stackoverflow,最近找到的答案要么是"Get Instance Name“,要么是关于实例名有多无意义的讨论!(不过,我可能把查询搞错了。)

我试过instance#classinstance#name,也试过instance#_id2ref(self)

我遗漏了什么?!

提前感谢!

EN

回答 4

Stack Overflow用户

回答已采纳

发布于 2012-11-09 00:48:20

好的,因此对于局部变量赋值,存在一些障碍,例如,分配可能比局部变量列表中添加的局部变量符号稍晚一些。但是下面是我的模块ConstMagicErsatz,我用它来实现类似于开箱即用的Ruby常量魔法:

代码语言:javascript
复制
a = Class.new
a.name #=> nil - anonymous
ABC = a # constant magic at work
a.name #=> "ABC"

这里的优点是,您不必编写ABC = Class.new(名称:"ABC“),名称被指定为‘魔术’。这也适用于Struct类:

代码语言:javascript
复制
Koko = Struct.new
Koko.name #=> "Koko"

但没有其他课程。所以我的ConstMagicErsatz允许你做

代码语言:javascript
复制
class MySettings < SettingsLogic
  include ConstMagicErsatz
end

ABC = MySettings.new
ABC.name #=> "ABC"

以及

代码语言:javascript
复制
a = MySettings.new name: "ABC"
a.name #=> "ABC"

下面是:

代码语言:javascript
复制
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方法时找到引用给定实例的常量。

唯一使用常量的约束是,您必须将其大写。当然,您想要的是在对象已经生成并分配给常量之后修改对象的元类。同样,由于没有钩子,所以您必须找到这样做的时机,例如新对象最初用于其目的的时间。所以,有

代码语言:javascript
复制
ABC = MySettings.new

然后,当第一次使用MySettings实例时,在执行任何其他操作之前,修补其元类:

代码语言:javascript
复制
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
票数 2
EN

Stack Overflow用户

发布于 2012-11-08 23:51:41

你不应该这样做吗?

代码语言:javascript
复制
File.open(File.join(File.expand_path(File.dir_name(__FILE__)), foo.class), "r")

代码语言:javascript
复制
require foo.class

第一个问题不一定那么复杂。但是,如果我对您的理解是正确的,您可以直接在require语句中使用foo.class。

根据需要调整YAML加载,但#class返回一个普通的旧字符串。

票数 0
EN

Stack Overflow用户

发布于 2012-11-08 23:57:07

如果你有大量的变量要实例化,我会亲自创建一个Hash来保存它们,这样就更干净了。现在,要实例化所有这些,您可以执行一个循环(其他所有yaml文件):

代码语言:javascript
复制
my_settings = {}
[:basic_config, :advanced_cfg, :some_yaml, :some_yaml2].each do |yaml_to_parse|
  my_settings[yaml_to_parse] = MySettings.new(yaml_to_parse)
end

确保您的initialize方法在MySettings中处理您给它的符号!

然后得到这样的变量:

代码语言:javascript
复制
my_settings[:advanced_cfg]
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/13299897

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档