Ruby 3.0. Ruby y los métodos de control de la privacidad menos conocidos
Tomasz Szkaradek
Arquitecto de desarrollo
Una de las características más queridas de Ruby es su sintaxis muy flexible. Personalmente, me encanta Ruby por la cantidad de posibilidades que tenemos a la hora de definir clases y sus propiedades, y esto es lo que trataré en este artículo.
Soluciones básicas
Supongamos que estamos utilizando la clase Foo que tiene un método público y un método privado:
clase Foo
def barra
:impresionante
end
privado
def baz
:algo_privado
end
end
Todo es estupendo, vemos una solución de este tipo en prácticamente todos los proyecto. Ejecutar Foo.new.baz provocará el error NoMethodError (método privado 'baz' llamado para # ) y eso es lo que queríamos hacer. ¿Qué pasa si intentamos cambiar el formato de guardado y añadimos private como prefijo en la definición de la clase?
clase Foo
def barra
:impresionante
end
private def baz
:algo_privado
end
end
Como se puede ver después de ejecutar el código¡funciona de verdad! ¿Por qué podemos introducir la visibilidad del método antes de hacerlo? Porque al definir un método, def devuelve el nombre del método como un símbolo. Esta expresión no es sólo una parte de la sintaxis, sino de facto un método derivado de la clase Módulo y que trata este símbolo como un argumento. Para más información, consulte la documentación en este enlace. Ya que empezó tan fácil con private, vamos a intentar cambiar la visibilidad del método private.
clase Foo
def barra
:impresionante
end
private def baz
:algo_privado
end
público :baz
end
¿Qué ocurrirá después de ejecutar el código?
irb(main):012:0> Foo.new.baz
=> :algo_privado
¡Éxito! Nuestro método de bases se hizo público porque lo hicimos visible dos veces. Por supuesto, la misma operación se aplica a los módulos. Genial, pero ¿adónde nos lleva? Esta funcionalidad nos aporta mucho porque podemos cambiar libremente la visibilidad de un método al definirlo, o incluso cambiar la visibilidad de los métodos al heredarlos.
Ahora, echemos un vistazo a lo que Ruby 2.7 puede hacer en términos de cambiar la visibilidad de alias y accessors.
clase Foo
private attr_accessor :impresionante_variable
fin
Desafortunadamente, obtenemos un error ya que el método privado espera symbols y attr_accessor. El código devuelve nil y por lo tanto este método no es compatible con el uso de private en Ruby 2.7. Entonces, ¿cuáles son nuestras opciones?
Podemos utilizar attr_accessor bajo la palabra clave private para que funcione, es decir, obtendremos un error cuando queramos hacer referencia a la variable asombrosa_variableasombrosa_variable método.
clase Foo
privado
attr_accessor :impresionante_variable
fin
La segunda opción es ejecutar el método privado en métodos generados por atributo_attr; en este caso, también tenemos que acordarnos de introducir allí el setter.
clase Foo
attr_accessor :variable_asombrosa
private :awesome_variable, :awesome_variable=
end
Problemas con el attr_ * no son los únicos obstáculos. Podemos encontrarnos con la misma dificultad cuando queremos crear un alias privado.
clase Foo
private alias :barra, :barra_impresionante
fin
Ruby 3.0 y nuestro negocio
Afortunadamente, Ruby 3.0 introduce un gran cambio ya que los métodos de visibilidad pueden tomar array como argumento y los métodos alias, attr_ *, pueden reajustar el array con los nombres de los métodos que se han definido. Puedes leer más aquí.
Ahora, veamos algunos ejemplos en el último euba y comprobemos si realmente se han realizado los cambios y cómo podemos utilizarlos. En el primer ejemplo, vamos a utilizar private antes del accessor attr:
clase Foo
private attr_accessor :impresionante_variable
fin
Tal llamada no causará errores en el análisis sintáctico de la sintaxis y, lo que es importante, el variable_asombrosa yawesome_variable =se convierten en privados. El método alias hará lo mismo ya que ahora también devuelve un símbolo como nombre del nuevo método y lo hace visible.
clase Foo
private alias :barra, :barra_impresionante
fin
Un hecho interesante es que también podemos profundizar en otros métodos, por ejemplo, el impresionanteel módulo print puede ser llamado entre private y attres importante que dicho método devuelva una matriz con los nombres de los métodos que se encuentran en el lado derecho de la expresión.
clase Módulo
def impresionante_imprimir(nombres)
puts nombres
nombres
end
end
clase Foo
private awesome_print attr_reader :awesome_bar
end
Resumen
Espero que este artículo le resulte útil. En caso de más noticias sobre Ruby 3.0. leer más aquí.