лучший способ установить значение по умолчанию для свойства без ActiveRecord? - PullRequest
15 голосов
/ 19 января 2012

Я думал, что этот вопрос ( Как сделать attr_accessor_with_default в ruby? ) ответил на мой вопрос, но я не использую ActiveRecord и after_initialize зависит от него.

Каков наилучший метод Ruby для реализации значения по умолчанию для attr_accessor? это ближе всего к документации об этом?Должен ли я прекратить использование attr_accessor, поскольку это личное?

Ответы [ 4 ]

26 голосов
/ 19 января 2012
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 голос
/ 06 сентября 2018

Просто для пояснения некоторых приведенных выше фрагментов кода, которые могут вводить в заблуждение, лучший способ установить значение по умолчанию для переменной экземпляра 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!
0 голосов
/ 09 мая 2018

Другой способ указать значения по умолчанию для переменных экземпляра любого класса - это исправить Module, а затем записать набор значений по умолчанию, например:

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
0 голосов
/ 26 декабря 2013

@ 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]] 

И у вас возникнет проблема при попытке получить переменную через @@, которая должна была быть для переменной реального класса.

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!
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...