Ruby: как справиться с ошибочной или неверной инициализацией - PullRequest
5 голосов
/ 14 мая 2011

Какова лучшая практика ruby ​​для обработки ситуации, в которой объект должен не инициализироваться из-за того, что ему переданы недопустимые аргументы инициализации?

Я понимаю, что в ruby ​​вводить утку означает, что мы не должныбыть чрезмерно озабоченным тем, какие типы переменных / параметров, а скорее заботиться о том, как они ведут себя.Тем не менее, я работаю в MacRuby, который соединен с API-интерфейсом Cocoa Objective-C, и некоторые методы Какао ожидают типизированных параметров.

Например, у меня есть класс ruby, который вызывает API Objective-C и должен передать ему объект класса NSURL.Это выглядит примерно так:

class Alpha
  attr_accessor :model
  def initialize(hopefully_a_NSURL)
    # bridged from Objective-C API
    @model=NSManagedObjectModel.alloc.initWithContentsOfURL(hopefully_a_NSURL)    
  end # initialize  
end 

... и я бы назвал это так:

#bridged from Objective-C API
u=NSURL.fileURLWithPath(p)
a=Alpha.new(u)
puts "a=#{a.model}" # => a=#<NSManagedObjectModel:0x2004970e0

>

... что прекрасно работает.

Однако, если бы я проскользнул:

a=Alpha.new("Whoops, a string not a NSURL" )

... он беспорядочно взрывается ошибками, приходящими из глубин Objective-C API.

Я могу, конечно, поставить тест, который предотвратит неверный параметр для достижения соединенных объектов:

class Alpha
  attr_accessor :model
  def initialize(hopefully_a_NSURL)
    if hopefully_a_NSURL.class==NSURL
      @model=NSManagedObjectModel.alloc.initWithContentsOfURL(hopefully_a_NSURL) 
    end   
  end # initialize  
end 


u=NSURL.fileURLWithPath(p)
a=Alpha.new("")
puts "a=#{a}" # => a=#<Alpha:0x200399160>

... но я все еще получаю живой экземпляр.Я даже пытался вернуть nil из инициализации, но похоже, что ruby ​​настаивает на том, чтобы всегда возвращать живой экземпляр.

Все, что я прочитал, говорит о том, что проверка типов в ruby ​​неодобрительна, но, возможно, мне придется сделать исключение в случае MacRuby.Будет ли это хорошим использованием исключений в ruby ​​или есть более элегантное решение?Я нуб в рубине, поэтому предположим, что я подхожу к проблеме с неправильной точки зрения.

1 Ответ

1 голос
/ 14 мая 2011

Я бы попытался преобразовать аргумент и поднять TypeError, если преобразование невозможно:

Повышается при встрече с объектом, который не относится к ожидаемому типу.

[1, 2, 3].first("two")

поднимает исключение:

TypeError: can't convert String into Integer

Ядро Ruby и стандартные библиотеки делают это, поэтому нет никаких причин, по которым вы тоже не можете это сделать. Ядро Ruby будет вызывать исключения, когда вы делаете что-то, чего не должны делать (вызываете неподдерживаемый метод, вызываете метод с неправильным числом аргументов, ...), поэтому выбрасывание TypeError будет иметь смысл. И если TypeError не совсем уместно, всегда есть ArgumentError.

В вашем конкретном случае попытайтесь преобразовать аргумент в NSURL, вызвав to_s, а затем создайте экземпляр NSURL, используя эту строку, если они не дают NSURL. Я не знаю, как обходиться с MacRuby или соответствующими API-интерфейсами Mac, поэтому я думаю о разумном поведении в этом конкретном случае, но я думаю, что идея «преобразовать или поднять исключение» является разумной и разумной.

Конечно, вы должны задокументировать поведение, которое вы собираетесь использовать в документации API.

...