En el primer artículo sobre Clases y Objetos en Ruby, hablamos sobre las propiedades de los objetos y cómo se accedía a dichas propiedades para consultar o modificar sus valores. A modo de recordatorio, comentábamos que las propiedades de un objeto estaban gestionadas por unas variables con visibilidad de instancia, es decir que sólo podían ser accedidas desde la propia clase, y no directamente desde fuera de ella. Para acceder a estas variables había que crear e invocar a ciertos métodos para acceso de lectura (consulta) o de escritura (modificación).
En este artículo simplificaremos aún más la forma de acceder a las propiedades, y veremos en detalle la visibilidad de las variables en una clase.
SIMPLIFICANDO EL ACCESO A LAS PROPIEDADES
Recordemos el código de nuestra clase Humano:
class Humano def initialize(nombre, apellidos, edad, altura, peso, sexo) @nombre = nombre @apellidos = apellidos @edad = edad @altura = altura @peso = peso @sexo = sexo end def to_s "#{@nombre} #{@apellidos}, #{@sexo}, de #{@edad} años, de #{@peso} kg y #{@altura} m" end def nombre @nombre end def apellidos @apellidos end def edad @edad end def altura @altura end def peso @peso end def sexo @sexo end def nombre=(nombre) @nombre = nombre end def apellidos=(apellidos) @apellidos = apellidos end def edad=(edad) @edad = edad end def altura=(altura) @altura = altura end def peso=(peso) @peso = peso end def sexo=(sexo) @sexo = sexo end end un_humano = Humano.new("Adela","Sanchez Gomez", "27", 1.67, 55.7, "mujer") otro_humano = Humano.new("Javier", "Martin Lopez", "44", 1.74, 80.5, "hombre") puts "Valor de un_humano: " + un_humano.to_s puts "Valor de otro_humano: " + otro_humano.to_s un_humano.peso = 71 un_humano.edad = 32 puts un_humano.nombre + " " + un_humano.apellidos + " tiene #{un_humano.edad} años de edad y #{un_humano.peso} kg de peso" |
Para consultar el valor de una propiedad utilizábamos un método que tenía el mismo nombre que la propiedad, retornando el valor de la propiedad, representado por una variable de instancia:
def nombre @nombre end |
Ruby permite simplificar toda esta sintaxis, mediante la siguiente abreviatura:
attr_reader :propiedad1, :propiedad2, ...A la hora de ejecutar la aplicación, el pre-compilador de Ruby generará, automáticamente, los métodos de acceso de lectura correspondientes.
Para modificar el valor de una propiedad utilizábamos un método que tenía el mismo nombre que la propiedad más el signo igual, asignando a la propiedad el valor pasado por parámetro:
def nombre=(nombre) @nombre = nombre end |
Ruby permite simplificar toda esta sintaxis, mediante la siguiente abreviatura:
attr_writer :propiedad1, :propiedad2, ...A la hora de ejecutar la aplicación, el pre-compilador de Ruby generará, automáticamente, los métodos de acceso de escritura correspondientes.
Así pues, el código final de la aplicacion se reduciría drásticamente:
class Humano attr_reader :nombre, :apellidos, :edad, :altura, :peso, :sexo attr_writer :nombre, :apellidos, :edad, :altura, :peso, :sexo def initialize(nombre, apellidos, edad, altura, peso, sexo) @nombre = nombre @apellidos = apellidos @edad = edad @altura = altura @peso = peso @sexo = sexo end def to_s "#{@nombre} #{@apellidos}, #{@sexo}, de #{@edad} años, de #{@peso} kg y #{@altura} m" end end un_humano = Humano.new("Adela","Sanchez Gomez", "27", 1.67, 55.7, "mujer") otro_humano = Humano.new("Javier", "Martin Lopez", "44", 1.74, 80.5, "hombre") puts "Valor de un_humano: " + un_humano.to_s puts "Valor de otro_humano: " + otro_humano.to_s un_humano.peso = 71 un_humano.edad = 32 puts un_humano.nombre + " " + un_humano.apellidos + " tiene #{un_humano.edad} años de edad y #{un_humano.peso} kg de peso" |
VISIBILIDAD DE LAS VARIABLES
VARIABLES DE METODO
Las variables definidas en un método, ya sea como parámetro o como parte del cuerpo del propio método, solamente tienen visibilidad dentro del propio método. Es decir, se crean en el método y se destruyen cuando termina la ejecución del método.
def metodo(nombre) mi_nombre = nombre end |
Las variables de método tienen su propia instancia en memoria, por lo que, aunque exista una variable de visibilidad superior con idéntico nombre, éstas se asumen como diferentes:
def metodo(nombre) @nombre = nombre end |
En este caso, se asigna a la variable de instancia @nombre el valor de la variable de método nombre pasada por parámetro. Cuando termina la ejecución del método, la variable nombre se destruye, pero la variable @nombre sigue vigente con el valor asignado.
VARIABLES DE INSTANCIA
Las variables de instancia son variables con una visibilidad para toda la clase, es decir, que puede ser utilizada por cualquier método de la misma mientras el objeto instanciado esté vivo. Estas variables son privadas a la clase, y no pueden ser accedidas fuera de ella, a no ser que se utilicen métodos que accedan de forma explícita a los mismos.
Por ejemplo:
class Clase def initialize @var=12 end end miClase = Clase.new() puts "Valor: #{miClase.var}" |
Esto generará el siguiente error:
Clase.rb:24:in '<main>': undefined method 'var' for #<Clase:0x0000000318de38 @var=12> (NoMethodError)
Tampoco permitirá acceder mediante la siguiente expresión:
puts "Valor: #{miClase.@var}"Generará el siguiente error:
Clase.rb:24: syntax error, unexpected tIVAR, expecting '('puts "Valor: #{miClase.@var}"Ello se debe a que al escribir el nombre del objeto y un punto, lo siguiente que espera es un método, no una variable.
Como vimos en el artículo anterior, el acceso de lectura y escritura se realizará mediante dos métodos que tienen el mismo nombre que la propiedad:
class Clase def initialize @var=12 end # Metodo de consulta a propiedad def var @var end # Metodo de asignacion a propiedad def var=(var) @var=var end end miClase = Clase.new() puts "Valor inicial: #{miClase.var}" # Llama al metodo de asignacion a propiedad miClase.var = 24 # Llama al metodo de consulta a propiedad puts "Valor cambiado: #{miClase.var}" |
El resultado es el siguiente:
Valor inicial: 12 Valor cambiado: 24Podemos utilizar otros métodos para acceder a las variables de instancia de otras maneras:
class Clase def initialize @var=12 end def incrementar @var = @var+1 end def incrementar_por(incremento) # incremento es variable de metodo @var = @var+incremento end # Metodo de consulta a propiedad def var @var end # Metodo de asignacion a propiedad def var=(var) # Asignacion de variable de metodo a variable de instancia @var=var end end miClase = Clase.new() puts "Valor inicial: #{miClase.var}" # Llama al metodo de asignacion a propiedad miClase.var = 24 # Llama al metodo de consulta a propiedad puts "Valor cambiado: #{miClase.var}" # Llama al metodo incrementar dos veces miClase.incrementar miClase.incrementar puts "Valor incrementado: #{miClase.var}" # Llama al metodo incrementar_por # incremento de 10 miClase.incrementar_por(10) puts "Valor incrementado por 10: #{miClase.var}" |
El método incrementar suma 1 al valor actual de la variable de instancia.
El método incrementar_por suma el valor pasado por parámetro al valor actual de la variable de instancia.
El resultado será el siguiente
Valor inicial: 12 Valor cambiado: 24 Valor incrementado: 26 Valor incrementado por 10: 36