Cuando trabajamos con Ruby on Rails, en ocasiones, tenemos la sensación que tenemos muchos métodos que significan lo mismo, o que utilizamos indistintamente. Eso es lo que suele pasar con los tres métodos de los que vamos a hablar hoy .nil? .empty? y .blank?
Lo que ocurre es que hay sutiles diferencias entre ellos que los hacen realmente apropiados para distintas situaciones. Vamos a ver cada uno de ellos en detalle:
Método .nil?
En Ruby, el método .nil? es un método que afecta a objetos y que simplemente nos devuelve nil? cuando el objeto es nil, que sorpresa, verdad? Vamos a ver algunos ejemplos. Podéis jugar con la consola y ver los distintos resultados.
Partamos de la base de que todo en Ruby son objetos, pues bien, el método .nil? solo nos devolverá true cuando el objeto sea una instancia de nilClass.
Mirad las distintas respuestas al usar este método de tres formas diferentes en la consola de rails:
> nil.nil? => true > "".nil? => false > [].nil? => false
Como véis, la única forma en la que obtenemos una respuesta de true es cuando le pasamos una instancia de nilClass. Este comportamiento, por ejemplo, lo hace ideal para comprobar si tenemos una respuesta nula al hacer una query o detectar objetos no inicializados. Pero por otra parte, tenemos que tener cuidado si estamos haciendo una query de una asociación, por ejemplo, que nos devuelve un array vacío, ya que ahí el método .nil? nos devolverá false aunque no haya elementos devueltos.
El método .empty?
El método .empty? por ejemplo, es diferente, ya que funciona a nivel de clase, así que el resultado será diferente en función del tipo de clase que estemos manejando, por ejemplo, no es lo mismo un array vacío que un string vacío.
> nil.empty? NoMethodError: undefined method `empty?' for nil:NilClass from (irb):4 from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/console.rb:110:in `start' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/console.rb:9:in `start' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:68:in `console' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:39:in `run_command!' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands.rb:17:in `<top (required)>' from bin/rails:4:in `require' from bin/rails:4:in `<main>' > "".empty? => true > " ".empty? => false > [].empty? => true > {}.empty? => true
Realmente el método .empty? es muy potente, ya que nos dice si un elemento que tenemos está vacío, esto es bastante más eficiente que por ejemplo:
if array.length > 0
Si estáis usando este método olvidaos ya de el, es lento, largo e ineficiente, y os echarán de la comunidad de Rails si seguís por ese camino insensatos… que os pensáis que es esto? PHP?
Bueno, regañinas aparte, fijaos en una debilidad del método, si evaluamos un objeto nil con .empty? lo que tenemos es una excepción, así que, en muchas ocasiones el método .empty? nos obligará antes a usar el método .nil? Y, para que vamos a escribir dos líneas de código pudiendo usar solo una?
El método .blank?
Efectivamente, lo habéis adivinado, aquí es donde el método .blank? viene en nuestra ayuda, ya que evalúa tanto si el objeto es nil como si está vacío. Vamos a ver algunos ejemplos:
> nil.blank? => true > "".blank? => true > " ".blank? => true > [].blank? => true > {}.blank? => true > 5.blank? => false
Fijaos que bien! El método blank? nos cubre todos los casos, no peta en caso de que tengamos un objeto a nil y además detecta si un objeto está vacío.
Aun así, tenemos que tener en cuenta un par de peculiaridades con respecto al método empty? que debemos conocer. Fijaos en las siguientes líneas:
2.4.1 :018 > " ".empty? => false 2.4.1 :019 > " ".blank? => true 2.4.1 :020 > false.empty? NoMethodError: undefined method `empty?' for false:FalseClass from (irb):20 from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/console.rb:110:in `start' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/console.rb:9:in `start' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:68:in `console' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands/commands_tasks.rb:39:in `run_command!' from /Users/antonioperez/.rvm/gems/ruby-2.4.1/gems/railties-4.2.10/lib/rails/commands.rb:17:in `<top (required)>' from bin/rails:4:in `require' from bin/rails:4:in `<main>' 2.4.1 :021 > false.blank? => true
La primera de las peculiaridades la tenemos con un string que solo contiene un espacio. Fijaos como .empty? será false mientras que .blank? será true.
La otra peculiaridad la tenemos con un false .empty? directamente nos lanzará una excepción mientras que .blank? nos devolverá true. No es que sea algo malo, pero si que debemos conocer que el método se comporta de esa manera. Puede ser útil, pero desde luego puede ser un quebradero de cabeza si no conoceis este detalle esperando tener ahí un false.
El método .present?
Por último el método .present? simplemente nos dará lo contrario de .blank? es decir, su negación lógica. Aquí vemos los ejemplos anteriores
> "".present? => false > " ".present? => false > [].present? => false > {}.present? => false > 5.present? => true > false.present? => false
Este método también es muy útil en nuestro día a día. Teniendo en cuenta que tiene las mismas peculiaridades que .blank? pero obteniendo el resultado contrario.
Tanto .blank? como .present? son una navaja suiza al verificar si tenemos valores en una variable o en una query. Pero eso si, usadlos con sabiduría jovenes padawan.
Si os interesa el lenguaje podéis echar un vistazo a la nueva versión de Ruby que se lanzó en Diciembre de 2019, la versión 2.7 en este post. Y como no, las imprescindibles ruby-lang.org (esta os la pongo en español directamente) y ruby-doc.org
Deja una respuesta