Есть ли способ для средств доступа Ruby возвращать что-то другое, кроме переменной set?

#ruby #class #accessor

Вопрос:

Я хочу немного проверить средство доступа для записи. Моей первой идеей было вернуть логическое значение.

 class MyClass
  def var=(var)
    @var = var
    # some checking
    return true
  end
end

m = MyClass.new
retval = (m.var = 'foo')

=> "foo"
 

Могу ли я установить возвращаемое значение в способе доступа для записи? Если да, то как я могу получить это значение?

Комментарии:

1. Можете ли вы привести пример того, какого рода проверка? Я немного сбит с толку тем, что вы имеете в виду под этим. Но у меня есть предчувствие, что это очень возможно, просто нужно кое-что уточнить.

2. Просто потому, что что-то возможно, не значит, что это хорошая идея. 😉

3. Создание исключения, безусловно, лучший способ сделать это.

4. То, о чем вы, по-видимому, просите, вероятно, окажется неинтуитивным и не по-рубиновому. Вы можете доказать это себе, используя свою форму, а затем используя ее в каком-то коде. Да, вы будете знать, что вам нужно делать что-то по-другому, но по мере написания кода вы должны заметить, похоже ли это на другие методы Ruby. Если вы не чувствуете того же самого, тогда не делайте этого. Согласованное поведение на языке очень важно и распространяется на то, как мы пишем наш собственный код.

Ответ №1:

Я бы использовал set_var(var) вместо того, что вы пытаетесь сделать, предполагается, что модуль записи атрибутов просто работает. То, что вы пытаетесь сделать, является нестандартным и неочевидным для следующего бедного человека, который будет использовать ваш код. (Это может быть просто ты сам) Я бы выдал исключение, если будет отправлен плохой ввод или произойдет что-то довольно исключительное.

Вы хотите такого поведения

 Correct
>>temp = object.var = 7
=> 7 

Wrong
>>temp = object.var = 7
=> false
 

Оператор = всегда должен возвращать переданное ему значение. Ruby использует неявные возвраты, что редко встречается в языках программирования. Дважды проверьте возврат при использовании method=() .

Ответ №2:

 class Test
  def var=(var)
    @var = var
    return true
  end
end

t1, t2 = Test.new, Test.new

t1.var = 123 # evaluates to 123

# Why is it impossible to return something else:
t1.var = t2.var = 456
 

Как указано в комментарии: я считаю, что невозможно изменить возвращаемое значение, чтобы разрешить последовательные назначения. Изменение возвращаемого значения, вероятно, было бы неожиданным для большинства программистов Ruby в любом случае.

Отказ от ответственности: Я протестировал приведенный выше код, но не нашел явных ссылок для подтверждения моего утверждения.

Обновить

 class Test
  def method_missing(method, *args)
    if method == :var=
      # check something
      @var = args[0]
      return true
    else
      super(method, *args)
    end
  end

  def var
    @var
  end
end

t = Test.new
t.var = 123 # evaluates to 123
t.does_not_exists # NoMethodError
 

Это действительно кажется невозможным! Приведенный выше пример предполагает, что возвращаемое значение вообще не связано с var= методом. Вы не можете изменить это поведение — это фундаментальный способ работы назначений Ruby.

Обновление 2: Найдено решение

Вы могли бы создать исключение!

 class Test
  def var=(var)
    raise ArgumentError if var < 100 # or some other condition
    @var = var
  end
  def var
    @var
  end
end

t = Test.new
t.var = 123 # 123
t.var = 1 # ArgumentError raised
t.var # 123
 

Комментарии:

1. Повышение исключений, безусловно, является способом сделать это.

Ответ №3:

Кроме того, в соответствии с вашим примером, чтобы навести порядок, вы могли бы сделать следующее:

 class MyClass
  attr_accessor :var
end

m = MyClass.new
m.var = "Test"
puts m.var # => "Test"
 

Однако, что касается вашего вопроса, вы спрашиваете, можете ли вы вернуть значение, отличное от того, которое вы установили для значения объекта?

Обновить

Проверьте этот проект: Можно проверить. Он добавляет проверки типа ActiveRecord к атрибутам вашего класса.

Быстрый сценарий:

 class Person
  include Validatable
  validates_presence_of :name
  attr_accessor :name
end

class PersonPresenter
  include Validatable
  include_validations_for :person
  attr_accessor :person

  def initialize(person)
    @person = person
  end
end

presenter = PersonPresenter.new(Person.new)
presenter.valid? #=> false
presenter.errors.on(:name) #=> "can't be blank"
 

Комментарии:

1. Мне нужно немного проверить, прежде чем я сохраню значение, поэтому я не использую attr_accessor. Да, вы поняли мой вопрос. Лучшим вопросом может быть «как класс должен реагировать на недопустимое значение?».

Ответ №4:

Я знаю, что это запоздалый ответ на вечеринку…

Трудно понять, что вы пытаетесь сделать с классом. Вы упомянули, что хотели проверить это перед сохранением… в базу данных? досье?

Что бы вы хотели, чтобы произошло в случае неправильного значения атрибута?

Используя логическое возвращаемое значение, вы эффективно «скрываете» ошибку (потому что забудете о странной вещи-необходимости проверять возвращаемое значение сеттера).

В то время как вы можете делать то, что предлагали другие

  • Используйте плагин валидатора
  • Вызвать ошибку

Вы также можете рассмотреть isValid? метод, как и многие классы, которые в конечном итоге сохраняются, так и делают. Затем сохранение может проверить состояние объекта и выдать ошибку.

Нижняя линия:

  • Не делай того, что ты написал
  • Действительно выдайте ошибку (любым из опубликованных решений)

Один из способов помочь в решении проблемы-рассмотреть возможность написания поведения, которое вы ищете в первую очередь (т. Е. BDD). Затем пройдите свой дальнейший путь к тому, что должен делать класс, используя TDD с помощью RSpec, чтобы получить желаемый «контракт» класса, который должен появиться для поддержки желаемого поведения.

Комментарии:

1. Спасибо за ваш ответ. Сейчас это действительно кажется плохой идеей , так что с тех пор я, вероятно, кое-чему научился в Ruby; -)