4

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

为了避免必须在任何地方命名-mangle,我有一个 mixin,它提供了用于访问这些设置的通用类方法。使用这个 mixin,我可以使用如下代码访问“news.show_date”:

News.setting :show_date
=> true

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

self.class
=> Class

这对我不是很有帮助。在我幼稚的实现中,这导致所有模型都将其设置存储在“类”下。命名空间,这是不可接受的。

对于无法更清楚地说明问题,我深表歉意。我对 Ruby 有点陌生,还没有完全理解它的对象模型。问题可能与Ruby 中似乎需要混合类方法的 kludge 有关

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.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
于 2012-04-24T20:52:43.190 回答
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

内部的代码在ClassMethodsClassThatMixesMeIn. 然后它将具有正确的值。

于 2012-04-24T20:37:16.437 回答