Ruby:如何处理失败或无效的初始化

Ruby:如何处理失败或无效的初始化,ruby,exception-handling,initialization,macruby,Ruby,Exception Handling,Initialization,Macruby,对于处理对象由于传递无效的初始化参数而无法初始化的情况,ruby的最佳实践是什么 我意识到,在ruby中,duck类型意味着我们不应该过度关注变量/参数类型,而应该关注它们的行为。然而,我在MacRuby中工作,它是连接Cocoa Objective-C API的桥梁,一些Cocoa方法需要类型化参数 例如,我有一个ruby类,它调用Objective-CAPI,并且必须向它传递一个NSURL类的对象。它看起来像这样: class Alpha attr_accessor :model d

对于处理对象由于传递无效的初始化参数而无法初始化的情况,ruby的最佳实践是什么

我意识到,在ruby中,duck类型意味着我们不应该过度关注变量/参数类型,而应该关注它们的行为。然而,我在MacRuby中工作,它是连接Cocoa Objective-C API的桥梁,一些Cocoa方法需要类型化参数

例如,我有一个ruby类,它调用Objective-CAPI,并且必须向它传递一个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
。。。它在Objective-CAPI的深处爆发出混乱的错误

当然,我可以进行测试,以防止到达桥接对象的错误参数:

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>
阿尔法类
属性存取器:模型
def初始化(希望为NSURL)
如果希望_a_NSURL.class==NSURL
@model=NSManagedObjectModel.alloc.initWithContentsOfURL(希望是NSURL)
结束
结束#初始化
结束
u=NSURL.fileURLWithPath(p)
a=α-新(“”)
将“a={a}”放入a=#
。。。但我还是得到了一个活的实例。我甚至尝试从initialize返回nil,但ruby似乎坚持总是返回一个活动实例


我读到的每一篇文章都说,在ruby中,类型检查是非常不受欢迎的,但在MacRuby中,我可能不得不破例。这是ruby中异常的一个很好的用法,还是有更优雅的解决方案?我是ruby中的noob,所以假设我从错误的角度处理问题

如果无法转换,我会尝试转换参数并提出:

遇到非预期类型的对象时引发

[1,2,3]。第一个(“两个”)

引发异常:

TypeError:无法将字符串转换为整数

Ruby核心和标准库可以做到这一点,因此没有理由不能做到这一点。当你做了一些你不应该做的事情(调用一个不受支持的方法,调用一个参数数目错误的方法,…)时,Ruby内核会引发异常,因此抛出
TypeError
是有意义的。而且,如果
TypeError
不太合适,那么总是存在错误

在您的特定情况下,尝试将参数转换为
NSURL
,方法是调用
to_s
,然后使用该字符串实例化
NSURL
,如果他们没有给您
NSURL
。我不知道我对MacRuby或相应的MacAPI的看法,所以我在猜测这种特定情况下的合理行为,但我认为“转换或引发异常”的想法是合理和合理的


当然,您也应该在API文档中记录您将要使用的行为。

等等,您是说如果向构造函数传递无效参数,您希望应用程序以静默方式失败?不,但我希望它以一种可控的方式失败,而不留下活动对象。如果我在纯Objective-C中执行此操作,我可以为对象返回一个nil,然后进行测试。我可能过于偏执,甚至可能不想麻烦,但一旦出现问题,我想知道如何处理它。因此,在
初始化
中,我将测试NSURL的,如果失败,则抛出异常。然后我会在异常处理程序中包装对
initialize
的调用?@TechZen:我可能会检查它是否是
NSURL
;如果是,则继续;如果不是,则尝试从参数构造一个
NSURL
。“construct NSURL”分支将封装在异常处理程序中,该异常处理程序将把任何异常转换为
TypeError
ArgumentError
并引发转换后的异常。我可能希望能够传递一个字符串或类的实例。如果您可以将参数强制为
NSURL
,则执行此操作,否则会引发异常。@TechZen:另一个示例是,如果无法解析您提供的日期字符串,则会引发
ArgumentError
异常。太短了--很抱歉,我没有机会测试您的答案。我试着安装rmv,结果有点不对劲。@TechZen:不用担心,我只是在中遇到了一个
ArgumentError
,我想你可能会感兴趣。
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>