How to inherit from NilClass or how to simulate similar function

后端 未结 3 751
梦谈多话
梦谈多话 2021-01-03 09:04

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 be

相关标签:
3条回答
  • 2021-01-03 09:41

    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 讨论(0)
  • 2021-01-03 09:44

    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).

    0 讨论(0)
  • 2021-01-03 09:50

    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

    0 讨论(0)
提交回复
热议问题