4

Railsプロジェクトでは、グローバル設定を文字列インデックス付きハッシュに格納します。各クラス(モデル)には、独自の設定用の「名前空間」があります。たとえば、ニュースモデルの設定は「news.stories_per_page」または「news.show_date」である可能性があります。

どこでも名前を変更する必要をなくすために、これらの設定にアクセスするための一般的なクラスメソッドを提供するミックスインがあります。このミックスインを使用すると、次のようなコードで「news.show_date」にアクセスできます。

News.setting :show_date
=> true

さて、ここに問題があります。文字列'news.show_date'を生成するには、モジュールを混在させるモデルのクラス名を知る必要があります。ただし、クラスメソッド内では、

self.class
=> Class

これは私にはあまり役に立ちません。私のナイーブな実装では、これによりすべてのモデルが「クラス」の下に設定を保存していました。名前空間。これは受け入れられません。

問題をより明確に述べることができなかったことをお詫び申し上げます。私はRubyに少し慣れておらず、そのオブジェクトモデルを完全には理解していません。この問題は、Rubyでクラスメソッドに混在させるために必要と思われるクラッジに関係している可能性があります。

4

3 に答える 3

5

クラスの名前は、クラスの ですname

module Foo
  def whoami
    self.name
  end
end

class Bar
  extend Foo
end

p Bar.whoami #=> "Bar"

文字列を作成しません。クラスごとに設定の新しいハッシュを作成します。

module Settings
  def setting(name,value=:GIT_DA_VALUE)
    @_class_settings ||= {}  # Create a new hash on this object, if needed
    if value==:GIT_DA_VALUE
      @_class_settings[name]
    else
      @_class_settings[name] = value
    end
  end
end

class Foo
  extend Settings
end
class Bar
  extend Settings
end
Foo.setting(:a,42)

p Foo.setting(:a), #=> 42
  Foo.setting(:b), #=> nil
  Bar.setting(:a)  #=> nil  (showing that settings are per class)

...または、クラス オブジェクト自体によって単一のグローバル ハッシュ (必要な場合) のインデックスを作成します。

module Settings
  # A single two-level hash for all settings, indexed by the object
  # upon which the settings are applied; automatically creates
  # a new settings hash for each object when a new object is peeked at
  SETTINGS = Hash.new{ |h,obj| h[obj]={} }
  def setting(name,value=:GIT_DA_VALUE)
    if value==:GIT_DA_VALUE
      SETTINGS[self][name]
    else
      SETTINGS[self][name] = value
    end
  end
end

# Usage is the same as the above; settings are unique per class
于 2012-04-24T21:21:26.160 に答える
2

使用する代わりに、またはより詳細に使用self.classできます:self.ancestorsself.ancestors.first

module Mixin
  def setting(name)
    puts "call #{self.ancestors.first}.#{__method__} with #{name}"
  end
end

class A
  extend Mixin
end

A.setting :a  #-> call A.setting with a
于 2012-04-24T20:52:43.190 に答える
0

1 つの回避策は、各クラス メソッド内でインスタンス化し、インスタンスselfを呼び出すclassことです。それは特に美しい解決策ではありませんが、うまくいくようです。

module SettingsMixin
  def self.included receiver
     receiver.extend ClassMethods
  end

  module ClassMethods
    def setting(key)
      class_name = self.new.class # => ClassThatMixesMeIn

      # Setting-fetching logic here...

    end
  end
end

内のコードClassMethodsは、から呼び出されるまで解析されません (またはそのように見えます) ClassThatMixesMeIn。その後、正しい値になります。

于 2012-04-24T20:37:16.437 に答える