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

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

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

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

=> "foo"

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

Ответы [ 4 ]

9 голосов
/ 13 октября 2008

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

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

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

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

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

4 голосов
/ 13 октября 2008
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
2 голосов
/ 13 октября 2008

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

class MyClass
  attr_accessor :var
end

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

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

Обновление

Проверьте этот проект: Validatable . Он добавляет 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 голос
/ 16 декабря 2010

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

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

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

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

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

  • Использовать плагин Validator
  • Поднять ошибку

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

Итог:

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

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

...