Ruby扩展类

Ruby扩展类,ruby,boolean,null,Ruby,Boolean,Null,我正在尝试为应用程序扩展Ruby的nil类,以便任何方法调用都将返回nil(实际上是self,新的扩展nil)。其目的是避免大量额外的零检查逻辑,例如 results = data.nil? nil : data.process() output = results.nil? nil : results.format() 并简单地用 output = data.process().format() 如果在链的任何地方返回了nil结果,则返回nil 让类响应任意消息非常容易: class Su

我正在尝试为应用程序扩展Ruby的nil类,以便任何方法调用都将返回nil(实际上是self,新的扩展nil)。其目的是避免大量额外的零检查逻辑,例如

results = data.nil? nil : data.process()
output = results.nil? nil : results.format()
并简单地用

output = data.process().format()
如果在链的任何地方返回了nil结果,则返回nil

让类响应任意消息非常容易:

class SuperNil
  def method_missing(sym, *args)
    return self
  end
end
现在,
supernil=supernil.new;supernil.anything
返回对象supernil。然而,这不是一个真正的零,因为它将评估为真。以某种方式扩展NilClass,使我的对象的计算结果为false是否有效?我遇到的麻烦是,即使在扩展NilClass之后,我也无法创建SuperNil对象。NilClass.new给出错误,SuperNil.new也给出错误

是否可以创建类扩展的对象?它的计算结果是否为false?

请尝试:

class NilClass
  def hello
    'hello'
  end

  def method_missing *args
    self
  end
end

nil.hello #=> 'hello'
nil.non_existing_method #=> nil
然而,这可能是一个坏主意,因为nil的
未定义方法是最有用的例外之一-它表示您在没有预料到的地方得到了nil。相反,您应该指定您知道可能发生零的所有位置-看看“AND”gem,它正好满足您的需要:

data.nil? nil : data.process()

# is the same as
data && data.process()

# what justifies the name of the gem
data.andand.process()
更新:

不可能创建nil的子类的原因很简单-NilClass不允许创建新实例,其
new
方法未定义(对于所有不可变类,如Fixnum、Symbol或TrueClass,您都会遇到相同的问题)。因此:

class SuperNil

不会引发任何问题,但您将无法创建此类的任何实例。

在您的情况下扩展
NilClass
不会有任何帮助,因为当您编写
nil
时,您可以创建
NilClass
的实例,并且无法覆盖它。这意味着你的课永远不会被使用

您需要修改
NilClass
或父类。在Ruby中,一切都是对象,包括
nil
。然后可以修改对象以引入一些自定义行为

这是政府采取的方法

这样可以缩短

@person && @person.name

进入


我的建议是不要滥用这种技巧。有时编写更少的代码并不一定是一件好事。

您是否考虑过只使用helper方法?例如,代替

results = data.nil? nil : data.process()
output  = results.nil? nil : results.format(1,2)
你可以写信

results = execute(data, :process)
output  = execute(results, :format, 1, 2)
在哪里

两个例子:

a = [1,2,3]
b = nil
execute(a, :max)       # => 3
execute(b, :max)       # => nil

execute(a, :delete, 2) # => 2, a => [1,3]
execute(b, :delete, 2) # => nil
您可以使用Ruby 2.3.0中引入的

output = data&.process&.format
output = data.dig(:process, :format)
同样,您也可以使用Ruby 2.3.0中引入的

output = data&.process&.format
output = data.dig(:process, :format)

我认为您的谨慎是不打开NilClass的一个很好的理由:任何可能遇到nil的其他代码(特别是包含的模块)都不会引发可能必要的异常。我看这很快就会变得很危险。类似于扩展的东西将允许我创建一个实例supernil,我可以将它与nil分开使用——甚至覆盖数组#[]以返回supernil而不是nil,这样我就可以随心所欲地搅动数据而不必担心。我肯定会让自己陷入困境。我已经更新了答案,说明了为什么你不能从NilClass继承,而gem是唯一的出路(好吧,你可以自己写一些类似的东西,但如果它工作得很好怎么办?)
a = [1,2,3]
b = nil
execute(a, :max)       # => 3
execute(b, :max)       # => nil

execute(a, :delete, 2) # => 2, a => [1,3]
execute(b, :delete, 2) # => nil
output = data&.process&.format
output = data.dig(:process, :format)