Coercion of nil


#1

Summary: null param should be returned as nil

Let me explain. Suppose I have the following params:

param :code, Integer
param :name, String

And my app is an API that receives the following JSON:

{
  "code": null,
  "name": null
}

Now let´s see how Lotus coerces the values. Currently, the default behaviour is to delegate coercion to Ruby. Lotus/Validations, will call kernel/Integer and kernel/String respectively to coerce the params. That´s what happens:

Actual result

code => 0
name = ""

This can lead to unexpected behaviour because I would expect both empty values, in others words, to be “not present”.

Expected result

code => nil
name => nil

After chatting with @pascalbetz and @eduardodeoh, they agree that a null param should be held as nil.

Proposal

updated to reflect @pascalbetz comment.

Change how each coercer deals with null params:

# Lotus::Utils::Kernel.Integer(nil) # => nil
# Lotus::Utils::Kernel.Integer("23.4") # => 23
def self.Integer(arg)
    if arg.nil?
        nil
    else
        super(arg)
    # ...
end

And apply the same for the rest of the coercers.


#2

I think that nil handling should be left up to each coercer and not wrapped away.


#3

You´re right. It´s a responsibility of each coercer to know what to do with nil.


#4

Today,

nil.public_methods.select {|e| e =~ /^to_/ }.map {|v| {"#{v}" => nil.send(v)} }

returns

=> [{"to_i"=>0}, {"to_f"=>0.0}, {"to_s"=>""}, {"to_a"=>[]}, {"to_h"=>{}}, {"to_r"=>(0/1)}, {"to_c"=>(0+0i)}, {"to_enum"=>#<Enumerator: ...>}]

So, i also agree with you and @pascalbetz.