1

YAMLファイルをロードする必要があり(SettingsLogicを試しています)、インスタンスに同じ名前のYAMLをロードしたいと思います。簡単に:

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...

この理由は、どの構成ファイルをロードして入力する必要があるのか​​まだわかりません。

my_config = MySettings.new("my_config.yml") 

また

my_config = MySettings.new(:MyConfig) 

繰り返しているようです。

GoogleとStackoverflowの両方を調べたところ、答えに最も近いのは「インスタンス名を取得」か、インスタンス名がどれほど無意味であるかについてのディスカッションです。(ただし、クエリが間違っている可能性があります。)

私は試しましinstance#classた、そしてinstance#name; 私も試し instance#_id2ref(self)ました。

何が足りないの?

前もって感謝します!

4

4 に答える 4

2

OK、ローカル変数の割り当てでは、ローカル変数リストへのローカル変数シンボルの追加よりも少し遅れて割り当てが発生する可能性があるなどの問題があります。ConstMagicErsatzしかし、これが私がすぐに使えるRuby定数マジックに似たものを実装するために使用した私のモジュールです:

a = Class.new
a.name #=> nil - anonymous
ABC = a # constant magic at work
a.name #=> "ABC"

ここでの利点は、ABC = Class.new(name: "ABC")と書く必要がないことです。名前には、「魔法のように」割り当てられます。これはStructクラスでも機能します。

Koko = Struct.new
Koko.name #=> "Koko"

しかし、他のクラスはありません。だからここにConstMagicErsatzあなたがすることができる私の行きます

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

上記のコードは、#nameメソッドが呼び出されるたびに、指定されたインスタンスを参照する定数を見つけることを目的として、Ruby名前空間全体の自動検索を実装しています。

定数を使用する唯一の制約は、それを大文字にする必要があるということです。もちろん、必要なのは、オブジェクトがすでに作成されて定数に割り当てられた後で、オブジェクトのメタクラスを変更することです。繰り返しになりますが、フックがないため、新しいオブジェクトがその目的のために最初に使用されるときなど、これを行う機会を見つける必要があります。だから、持っている

ABC = MySettings.new

次に、MySettingsインスタンスが最初に使用されたときに、他のことを行う前に、そのメタクラスにパッチを適用します。

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
于 2012-11-09T00:48:20.477 に答える
0

インスタンス化する変数がたくさんある場合は、個人的にHashそれらを保持するための変数を作成します。この方法の方がクリーンです。これをすべてインスタンス化するために、他のすべてのyamlファイルをループすることができます:

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あなたがそれを与えるシンボルを扱っていることを確認してください!

次に、次のように変数を取得します。

my_settings[:advanced_cfg]
于 2012-11-08T23:57:07.823 に答える
0

あなたもできるべきではありません

File.open(File.join(File.expand_path(File.dir_name(__FILE__)), foo.class), "r")

また

require foo.class

最初のものは必ずしもそれほど複雑である必要はありません。しかし、私があなたを正しく理解しているのであれば、requireまたはfileloadステートメントで直接foo.classを使用することができます。

YAMLの読み込みに必要に応じて調整しますが、#classは単純な古い文字列を返します。

于 2012-11-08T23:51:41.390 に答える
0

残念ながら、Rubyには変数代入のフックがありませんが、これは回避できます。戦略の概要は次のとおりです。まず、呼び出し元のバインディングでコードを評価MySettings.newするためのメソッドを取得する必要があります。次に、そこでメソッドを呼び出すことにより、呼び出し元のバインディングにローカル変数シンボルのリストが表示されます。その後、それらを繰り返し処理して、カスタムメソッドの呼び出しによって返されたインスタンスを参照しているものを見つけます。そして、そのシンボルをメソッド呼び出しに渡します。local_variablessuperMySettings.newsource

于 2012-11-09T00:12:48.983 に答える