在没有ActiveRecord的情况下在属性上设置默认值的最佳方法?

时间:2012-01-18 20:47:21

标签: ruby

我认为这个问题(How to do attr_accessor_with_default in ruby?)回答了我的问题,但我没有使用ActiveRecord而after_initialize取决于它。

实现attr_accessor默认值的Ruby最佳实践是什么? this与文档最接近吗?我应该停止使用attr_accessor,因为它是私有的吗?

4 个答案:

答案 0 :(得分:25)

class Foo
  # class-level instance variable

  # setting initial value (optional)
  @class_var = 42  

  # making getter/setter methods on the class itself
  class << self
    attr_accessor :class_var
  end

  # instance-level variable getter/setter methods
  attr_accessor :inst_var
  def initialize
    # setting initial value (optional)
    @inst_var = 17
  end
end

p Foo.class_var
#=> 42
Foo.class_var = 99
p Foo.class_var
#=> 99

f1 = Foo.new
f2 = Foo.new
f2.inst_var = 1
p [f1.inst_var, f2.inst_var]
#=> [17,1]

答案 1 :(得分:0)

@Phrogz提供了一个很好的解决方案,但你应该了解更多。

在这里你创建一个class-level instance variable,它实际上不是一个类变量,但是谁在乎,因为在初始化一个具有相同名称的实类变量之后,你会丢失一个旧的引用。

要检查虚假,请使用上面的代码,但使用数组:

class Foo
  @class_var = [42]
  class << self
    attr_accessor :class_var
  end
end
b = [Foo.class_var]
Foo.class_var = 69
p b # still [[42]] 

当你试图通过@@获取变量时,你会遇到一个问题。{/ 1}}这是一个真正的类变量。

class Bar
  @class_var = [42]
  class << self
    attr_accessor :class_var
  end
  def biz
    self.class.class_var
  end
  def baz
    @@class_var
  end
end
p Bar.new.biz # self.class. is kinda a way to emulate the reference from outside
p Bar.new.baz # and exception, because you don't really have a class variable defined yet!

答案 2 :(得分:0)

为任何类的实例变量指定默认值的另一种方法是修补Module,然后像这样编写set defaults:

class Zaloop

  attr_accessor var1: :default_value, var2: 2

  def initialize
    initialize_default_values
  end

end

puts Zaloop.new.var1 # :default_value

模块补丁:

Module.module_eval do

  alias _original_attr_accessor attr_accessor
  def attr_accessor(*args)
    attr_names = extract_default_values args
    _original_attr_accessor *attr_names
  end

  alias _original_attr_reader attr_reader
  def attr_reader(*args)
    attr_names = extract_default_values args
    _original_attr_reader *attr_names
  end

  def extract_default_values(args)
    @default_values ||= {}
    attr_names = []
    args.map do |arg|
      if arg.is_a? Hash
        arg.each do |key, value|
          define_default_initializer if @default_values.empty?
          @default_values[key] = value
          attr_names << key
        end
      else
        attr_names << arg
      end
    end
    attr_names
  end

  def define_default_initializer
    default_values = @default_values
    self.send :define_method, :initialize_default_values do
      default_values.each do |key, value|
        instance_variable_set("@#{key}".to_sym, value)
      end
    end
  end

  def initialize_default_values
    # Helper for autocomplete and syntax highlighters
  end

end

答案 3 :(得分:0)

仅是为了澄清上面可能引起误解的一些代码片段,在Ruby实例变量上设置默认值的最佳方法是与PHP或Python行为不同。

简单的解决方案是为实例变量设置默认值,即在initialize()方法中设置它们:

class MyClass
    attr_accessor :foo
    # @foo = 'This is totally ignored! Do not try to set a default value here!'  
    def initialize
      @foo = 'default'    
    end
end

x = MyClass.new
print x.foo  # tada!