方法未定义或为零的Ruby one liner

方法未定义或为零的Ruby one liner,ruby,Ruby,我很好奇是否有一种更短的方法来检查一个对象上是否定义了一个方法,如果是,检查它是否为nil。我试过: if !obj.respond_to?(:meth) || obj.meth.nil? 但它看起来又长又丑 如果您在rails中,可以使用。试试 [1] pry(main)> h = {} => {} [2] pry(main)> h.try(:foo) => nil 使用定义的?关键字 irb(main):066:0> obj = "test" # in th

我很好奇是否有一种更短的方法来检查一个对象上是否定义了一个方法,如果是,检查它是否为nil。我试过:

if !obj.respond_to?(:meth) || obj.meth.nil?

但它看起来又长又丑

如果您在rails中,可以使用
。试试

[1] pry(main)> h = {}
=> {}
[2] pry(main)> h.try(:foo)
=> nil

使用
定义的?
关键字

irb(main):066:0> obj = "test" # in this case obj is a string
=> "test"
irb(main):067:0> defined? obj.split
=> "method"
irb(main):068:0> defined? obj.not_a_func
=> nil

定义?表达式测试表达式是否引用任何可识别的内容(文字对象、已初始化的局部变量、从当前范围可见的方法名称等)如果表达式无法解析,则返回值为零


为了让它读得好,我会这样做:

def has_method?(obj, method)
  obj.methods.include?(method)
end

has_method?(2, :+)            #=> true
has_method?('cat', :upcase)   #=> true
has_method?('cat', :group_by) #=> false
has_method?(Array, :new)      #=> true
因此,这将是:

!has_method?(obj, :meth) ||  obj.meth.nil?
或者只是:

!obj.methods.include?(:meth) || obj.meth.nil?
或:


快速、肮脏但简洁:

unless (obj.meth rescue nil)
  ...
end
如果将
meth
发送到
obj
失败(例如,由于缺少该方法),表达式将采用值
nil

当然,这隐藏了
meth中的各种错误。正如建议的那样,meth正是您想要的。使用
try
,您的代码如下所示:

if obj.try(:meth).nil?
  # obj either lacks :meth or has :meth that returns nil
end
我觉得非常简洁易懂

如果您不使用ActiveSupport,您可以快速重新实现一个简单的版本
自己尝试

class Object
  def try(method, *args)
    public_send(method, *args) if respond_to?(method)
  end
end


你是在处理一些对象化的散列还是什么?不,我是在处理一个可能/可能没有定义
:meth
的普通对象。你被优先权螨咬了一口。您的表达式等价于:
if!有什么反应meth
。这是因为首先计算
:meth | | obj.meth.nil?
,并始终返回
:meth
。假设我们有
类字符串;def s;无结束;结束;obj=‘cat’
。然后
!有什么反应meth | | obj.meth.nil?#=>false
,而
!(obj.respond_to?:meth)| | obj.meth.nil?#=>是的
@CarySwoveland,我添加了正确的偏执,只是我忘了把它们放在问题中。这是可以理解的,但我会留下我的评论,因为它的教育价值。他也需要称之为:)也
定义了吗?
是一个关键字,而不是一种方法谢谢@SergioTulentsev,更新了关键字定义的答案?不会告诉你调用方法的结果是NIL,但是对于通过FrederickCheung方法的第一个点的方法MySnfas来实现或定义的方法不起作用,请考虑<代码> KNELL。要回答OP的问题,您建议返回:
!(已定义?Kernel.puts)#=>false
,但
!(Kernel.response_to?:put)| Kernel.put.nil?#=>是的
。信息很好,但是没有Rails标记就无关紧要了。@CarySwoveland:也许他忘了用Rails标记。这是常有的事,我从来没有发生过。当然,我不知道Rails。+5代表创造性,+5代表诚实。使用这个解决方案,因为它既聪明又最接近我要找的一行。它看起来不错,但长度与我的建议相同。但这不是。只考虑可读性,它只与长度松散相关。这就是为什么我更喜欢,例如,
obj.meth!=无
!object.nil?
。然而,我(几乎)对
方法漠不关心。包括?
响应?
;我只是想提供另一个选项。我希望
响应\u?
会更快,如果这很重要的话。
class Object
  def try(method, *args)
    public_send(method, *args) if respond_to?(method)
  end
end