Nils和方法链接

时间:2011-08-29 20:09:30

标签: ruby-on-rails ruby null metaprogramming

我只是闯入红宝石世界,我可以伸出援助之手。

假设bnil

我希望以下代码返回nil而不是“NoMethodError:undefined method”

a.b.c("d").e

我尝试的第一件事就是将NilClass的missing_method重载为简单的返回nil。这是我想要的行为,除了我不想成为这种侵扰行为。

如果我可以做这样的话,我会喜欢它

SafeNils.a.b.c("d").e

所以它就像是一种干净的方式来局部地重载NilClass的行为。

我很想听到一些想法或很多资源来挖掘这个。我对其他方法也很开放,只要它相当干净。

非常感谢。

9 个答案:

答案 0 :(得分:6)

我认为您可以在rails中找到一个很好的解决方案,但该解决方案遵循不同的方法。看一下try方法。这是一个干净的方法。

答案 1 :(得分:5)

您可以使用inline rescue

x = a.b.c("d").e rescue nil
如果xnil

b将为nil

或者,正如有人在该链接中发表评论,您可以使用andand gem(请参阅docs):

x = a.andand.b.andand.c("d").andand.e

答案 2 :(得分:3)

正如lucapette所说,“尝试”非常干净。更一般地说,您也可以使用begin-rescue-end块,具体取决于您的情况。

begin
  a.b.c("d").e
rescue NoMethodError=>e
  return nil
end

答案 3 :(得分:3)

检查Ickmaybe

a.b.maybe.c("d").maybe.e

或使用块:

a.b.maybe { |b| b.c("d").e }

答案 4 :(得分:2)

提前备注:b是一种方法,而不是变量。所以b'是'不是零,它返回零。

当'b'是一个方法时,为什么不修改b,所以它返回一些东西,什么可以处理nil。

请参阅下面的示例。


您可以定义缺少的方法:

class A
  def b
    nil
  end
end
class NilClass
  def c(p);nil;end
  def e;nil;end
end
a = A.new

a.b.c("d").e

但我认为,救援可能会更好地满足您的需求:

class A
  def b
    nil
  end
end
a = A.new
x = begin a.c.c("d").e 
rescue NoMethodError
  nil
end

一个例子,你如何定义一个类似nil的例子。

class A
  def b
    MyNil.new
  end
end

class MyNil
  def method_missing(m, *args, &block)
      if nil.respond_to?(m)
        nil.send(m)
    else
      self
    end
  end
  #Simulate nils bahaviour.
  def nil?;true;end
  def inspect;nil.inspect;end
  def to_s;nil;end
end

a = A.new
x = a.b.c("d").e 
p x
puts x
p x.nil?

答案 5 :(得分:1)

使用类似于您所写的safe_nils

def safe_nils &blk
  return blk.call
rescue NoMethodError
  return nil
end

safe_nils { a.b.c("d").e }

答案 6 :(得分:0)

我为此制作了may_nil宝石。 https://github.com/meesern/may_nil

与@Sony Santos的safe_nils一样,它使用一个块来包装方法链并拯救NoMethodError,但会检查nil(因此会为其他类正确引发异常)。

require `may_nil`
may_nil {a.b.c("d").e}   => nil (or the end result)
may_nil {0.b.c("d").e}   => Exception: NoMethodError (b on Fixnum)

andandike的{​​{1}}不同,您不需要对方法链加密。

maybe

答案 7 :(得分:0)

一种方法是对局部变量使用内联赋值:

a && (ab = a.b) && (abcd = ab.c("d")) && abcd.e

对于你所拥有的链条而言,它不是很优雅,但对于较短的链条,它可能很有用:

def date_updated(entry)
  (updated = entry.updated) && updated.content
end

答案 8 :(得分:0)

从ruby v2.3.0开始,该语言内置了另一种方法,即安全导航操作员(&amp ;.) 您可以写:a&.b&.c&.d如果链中的一个调用返回nil,您将安全地获得nil。 你可以在这里读更多关于它的内容: http://mitrev.net/ruby/2015/11/13/the-operator-in-ruby/