开发者

How to inherit from NilClass or how to simulate similar function

I just want to use Null Object Design Pattern, but I found I can inherit from NilClass.

I can write a method "nil?" and return false but what if user write code below

if null_object 
  puts "shouldn't be here"
end

For clarify what I try to do is:

record = DB.find(1)
# if it can not find record 1, the bellow code should not raise exception
record.one_attr 
# and what's more
if record 
  puts "sho开发者_如何学Gouldn't be here"
end
# I don't want to override all NilClass


An approach that may work for you is to overide the method #nil? in your Null object. This means that in your code to test for null you have to use obj.nil? and not just check for obj existence. This is probably reasonable, since you can distinguish between nil and null. Below is an example:

class NullClass
  def nil?
    true
  end

  def null_behavior
    puts "Hello from null land"
  end
end

Inheritance will work:

class NewClass < NullClass
end

Use like so:

normal = Class.new
null = NewClass.new

x = [normal, null]

x.each do |obj|
  if obj.nil?
    puts "obj is nil"
    obj.null_behavior
  end
end

Output:

obj is nil
Hello from null land

Just remember to use #.nil? for any checks that require Null and Nil to be false-ish.

Below this line was my WRONG initial answer

CustomNil = Class.new(NilClass) 

class CustomNil
  def self.new
    ###!!! This returns regular nil, not anything special.
  end
end

[tests deleted for brevity]

Use at your own risk. I haven't researched what side effects this may cause or whether it will do what you want. But it seems it does have some nil like behavior


Instead of inheriting from NilClass I do the following

class NullObject < BasicObject
  include ::Singleton

  def method_missing(method, *args, &block)
    if nil.respond_to? method
      nil.send method, *args, &block
    else
      self
    end
  end
end

This gives you any custom method that have been monkey patched onto NilClass (such as ActiveSupport's blank? and nil?). You can also of course add custom null object behaviors, or change method_missing to handle other calls differently (this one returns the NullObject for chaining, but you could return nil for example).


I don't think Ruby actually allows you to inherit from NilClass and create an object based on it:

class CustomNilClass < NilClass
end

custom_nil_object = CustomNilClass.new
# => NoMethodError: undefined method `new' for CustomNilClass:Class
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜