#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; -)