从mixin访问类名

时间:2012-04-24 20:30:28

标签: ruby-on-rails ruby mixins

在我的Rails项目中,我将全局设置存储在字符串索引的哈希中,其中每个类(模型)都有自己设置的“命名空间”。例如,新闻模型可能具有“news.stories_per_page”或“news.show_date”设置。

为了避免在任何地方进行命名,我有一个mixin,它提供了访问这些设置的通用类方法。使用这个mixin,我可以使用以下代码访问'news.show_date':

News.setting :show_date
=> true

现在,这是问题所在。为了生成字符串'news.show_date',我需要知道混合我的模块的模型的类名。但是在类方法中,

self.class
=> Class

这对我没有多大帮助。在我天真的实现中,这导致所有模型将他们的设置存储在“类”下。命名空间,这是不可接受的。

我为无法更清楚地陈述问题而道歉。我对Ruby有点新,并且没有完全理解它的对象模型。问题可能与kludge which seems to be required in Ruby to mix in class methods有关。

3 个答案:

答案 0 :(得分: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

答案 1 :(得分:2)

而是使用self.class,您可以使用self.ancestors或更详细的self.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

答案 2 :(得分:0)

一种解决方法是在每个类方法中实例化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调用之前未被解析(或似乎是这样)。然后它将具有正确的值。