2009-09-28 5 views
9

Новое для Ruby, и я пытаюсь выяснить, какую идиому использовать, чтобы ограничить некоторые целочисленные значения конструктору класса.Конструкторы и исключения Ruby

Из того, что я сделал до сих пор, если я создаю исключение в initialize(), объект все равно будет создан, но будет находиться в недопустимом состоянии (например, некоторые значения nil в переменных экземпляра). Я не могу понять, как я должен ограничивать значения, не вдаваясь в то, что выглядит излишне большими шагами, такими как ограничение доступа к new().

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

+0

Да, я путать себя по этой проблеме. Я был «спасением» исключения в конструкторе, поэтому разумно, что экземпляр будет создан. – Chris

ответ

13

Да, вы совершенно правы, что объект все еще живет, даже если initialize создает исключение. Тем не менее, это будет довольно трудно для любого, чтобы повесить на ссылку, если вы не утечка self из initialize как следующий код, который я только что написал это:

>> class X 
>> def initialize 
>>  $me = self 
>>  raise 
>> end 
>> def stillHere! 
>>  puts "It lives!" 
>> end 
>> end 
=> nil 
>> t = X.new 
RuntimeError: 
    from (irb):14:in `initialize' 
    from (irb):20:in `new' 
    from (irb):20 
>> t 
=> nil 
>> $me 
=> #<X:0xb7ab0e70> 
>> $me.stillHere! 
It lives! 
3

Я не уверен в этом заявлении:

Из того, что я сделал до сих пор, если я поднимаю исключение в Initialize(), объект все равно создается, но будет в недопустимое состояние (например, некоторые значения nil в переменных экземпляра).

class Foo 

    def initialize(num) 
    raise ArgumentError.new("Not valid number") if num > 1000 
    @num = num 
    end 

end 

f = Foo.new(4000) #=> n `initialize': not valid (RuntimeError) 
+0

Хм, мне нужно будет просмотреть мой код и посмотреть, может, я ошибаюсь. Спасибо за ответ. – Chris

+1

На самом деле, объект * * создан, это просто .new не вернет ссылку, поэтому, если объект не свяжется с самим собой во время 'initialize', он получит gc'ed. – DigitalRoss

2

Если я правильно читать ваш вопрос, что вы хотите что-то вроде этого:

class SerialNumber 
    VALID_SERIAL_NUMBERS = (0..10,000,000,000) 
    def initialize(n) 
    raise ArgumentError.new("Serial numbers must be positive integers less than 10 Billion") unless VALID_SERIAL_NUMBERS.include?(n) 
    @n = n 
    end 
end 

Не волнуйтесь, что SerialNumber.new создает экземпляр до этого метода initialize называется - он будет очищен, если ошибка будет поднята.

0

Использование validatable module кажется действительно подходящим в контексте.

Вот пример того, как использовать его:

class Person 
    include Validatable 
    validates_numericality_of :age 
    end 

Для проделывают номера только в определенном диапазоне было бы:

class Person 
    include Validatable 
    validates_numericality_of :age 
    validates_true_for :age, :logic => lambda { (0..100).include?(age) } 
    end 

Это, конечно, будет проверять, что возраст находится в пределах диапазон 0 и 100.

Смежные вопросы