Ruby Language
Las clases
Buscar..
Sintaxis
- nombre de la clase
- # algún código que describe el comportamiento de la clase
- fin
Observaciones
Los nombres de las clases en Ruby son constantes, por lo que la primera letra debe ser mayúscula.
class Cat # correct
end
class dog # wrong, throws an error
end
Creando una clase
Puede definir una nueva clase utilizando la palabra clave de class
.
class MyClass
end
Una vez definido, puede crear una nueva instancia usando el método .new
somevar = MyClass.new
# => #<MyClass:0x007fe2b8aa4a18>
Constructor
Una clase solo puede tener un constructor, es decir, un método llamado initialize
. El método se invoca automáticamente cuando se crea una nueva instancia de la clase.
class Customer
def initialize(name)
@name = name.capitalize
end
end
sarah = Customer.new('sarah')
sarah.name #=> 'Sarah'
Variables de clase e instancia
Hay varios tipos de variables especiales que una clase puede usar para compartir datos más fácilmente.
Variables de instancia, precedidas por @
. Son útiles si desea utilizar la misma variable en diferentes métodos.
class Person
def initialize(name, age)
my_age = age # local variable, will be destroyed at end of constructor
@name = name # instance variable, is only destroyed when the object is
end
def some_method
puts "My name is #{@name}." # we can use @name with no problem
end
def another_method
puts "My age is #{my_age}." # this will not work!
end
end
mhmd = Person.new("Mark", 23)
mhmd.some_method #=> My name is Mark.
mhmd.another_method #=> throws an error
Variable de clase, precedida por @@
. Contienen los mismos valores en todas las instancias de una clase.
class Person
@@persons_created = 0 # class variable, available to all objects of this class
def initialize(name)
@name = name
# modification of class variable persists across all objects of this class
@@persons_created += 1
end
def how_many_persons
puts "persons created so far: #{@@persons_created}"
end
end
mark = Person.new("Mark")
mark.how_many_persons #=> persons created so far: 1
helen = Person.new("Helen")
mark.how_many_persons #=> persons created so far: 2
helen.how_many_persons #=> persons created so far: 2
# you could either ask mark or helen
Variables globales, precedidas por $
. Estos están disponibles en cualquier parte del programa, así que asegúrese de usarlos sabiamente.
$total_animals = 0
class Cat
def initialize
$total_animals += 1
end
end
class Dog
def initialize
$total_animals += 1
end
end
bob = Cat.new()
puts $total_animals #=> 1
fred = Dog.new()
puts $total_animals #=> 2
Acceso a variables de instancia con captadores y definidores.
Tenemos tres métodos:
-
attr_reader
: se utiliza para permitirread
la variable fuera de la clase. -
attr_writer
: se utiliza para permitir la modificación de la variable fuera de la clase. -
attr_accessor
: combina ambos métodos.
class Cat
attr_reader :age # you can read the age but you can never change it
attr_writer :name # you can change name but you are not allowed to read
attr_accessor :breed # you can both change the breed and read it
def initialize(name, breed)
@name = name
@breed = breed
@age = 2
end
def speak
puts "I'm #{@name} and I am a #{@breed} cat"
end
end
my_cat = Cat.new("Banjo", "birman")
# reading values:
my_cat.age #=> 2
my_cat.breed #=> "birman"
my_cat.name #=> Error
# changing values
my_cat.age = 3 #=> Error
my_cat.breed = "sphynx"
my_cat.name = "Bilbo"
my_cat.speak #=> I'm Bilbo and I am a sphynx cat
Tenga en cuenta que los parámetros son símbolos. Esto funciona creando un método.
class Cat
attr_accessor :breed
end
Es básicamente lo mismo que:
class Cat
def breed
@breed
end
def breed= value
@breed = value
end
end
Niveles de acceso
Ruby tiene tres niveles de acceso. Son public
, private
y protected
.
Los métodos que siguen a las palabras clave private
o protected
se definen como tales. Los métodos que vienen antes de estos son métodos implícitamente public
.
Métodos Públicos
Un método público debe describir el comportamiento del objeto que se está creando. Estos métodos se pueden llamar desde fuera del alcance del objeto creado.
class Cat
def initialize(name)
@name = name
end
def speak
puts "I'm #{@name} and I'm 2 years old"
end
...
end
new_cat = Cat.new("garfield")
#=> <Cat:0x2321868 @name="garfield">
new_cat.speak
#=> I'm garfield and I'm 2 years old
Estos métodos son métodos públicos de rubí, describen el comportamiento para inicializar un nuevo gato y el comportamiento del método de hablar.
public
palabra clave public
es necesaria, pero puede usarse para escapar de forma private
o protected
def MyClass
def first_public_method
end
private
def private_method
end
public
def second_public_method
end
end
Métodos privados
Los métodos privados no son accesibles desde fuera del objeto. Son utilizados internamente por el objeto. Usando el ejemplo del gato otra vez:
class Cat
def initialize(name)
@name = name
end
def speak
age = calculate_cat_age # here we call the private method
puts "I'm #{@name} and I'm #{age} years old"
end
private
def calculate_cat_age
2 * 3 - 4
end
end
my_cat = Cat.new("Bilbo")
my_cat.speak #=> I'm Bilbo and I'm 2 years old
my_cat.calculate_cat_age #=> NoMethodError: private method `calculate_cat_age' called for #<Cat:0x2321868 @name="Bilbo">
Como puede ver en el ejemplo anterior, el objeto Cat recién creado tiene acceso al método calculate_cat_age
internamente. Asignamos la age
variable al resultado de ejecutar el método private calculate_cat_age
que imprime el nombre y la edad del gato en la consola.
Cuando intentamos llamar al método calculate_cat_age
desde fuera del objeto my_cat
, recibimos un NoMethodError
porque es privado. ¿Consíguelo?
Métodos protegidos
Los métodos protegidos son muy similares a los métodos privados. No se puede acceder a ellos fuera de la instancia del objeto de la misma manera que los métodos privados no pueden ser. Sin embargo, utilizando el método self
ruby, los métodos protegidos pueden llamarse dentro del contexto de un objeto del mismo tipo.
class Cat
def initialize(name, age)
@name = name
@age = age
end
def speak
puts "I'm #{@name} and I'm #{@age} years old"
end
# this == method allows us to compare two objects own ages.
# if both Cat's have the same age they will be considered equal.
def ==(other)
self.own_age == other.own_age
end
protected
def own_age
self.age
end
end
cat1 = Cat.new("ricky", 2)
=> #<Cat:0x007fe2b8aa4a18 @name="ricky", @age=2>
cat2 = Cat.new("lucy", 4)
=> #<Cat:0x008gfb7aa6v67 @name="lucy", @age=4>
cat3 = Cat.new("felix", 2)
=> #<Cat:0x009frbaa8V76 @name="felix", @age=2>
Puede ver que hemos agregado un parámetro de edad a la clase cat y que hemos creado tres nuevos objetos cat con el nombre y la edad. Vamos a llamar al método protegido own_age
para comparar la edad de los objetos de nuestro gato.
cat1 == cat2
=> false
cat1 == cat3
=> true
Mire eso, pudimos recuperar la edad de cat1 utilizando el método self.own_age
protected y compararla con la edad de cat2 llamando a cat2.own_age
dentro de cat1.
Clases de métodos de clase
Las clases tienen 3 tipos de métodos: métodos de instancia, singleton y clase.
Métodos de instancia
Estos son métodos que se pueden llamar desde una instance
de la clase.
class Thing
def somemethod
puts "something"
end
end
foo = Thing.new # create an instance of the class
foo.somemethod # => something
Método de clase
Estos son métodos estáticos, es decir, pueden invocarse en la clase, y no en una instanciación de esa clase.
class Thing
def Thing.hello(name)
puts "Hello, #{name}!"
end
end
Es equivalente a usar self
en lugar del nombre de la clase. El siguiente código es equivalente al código anterior:
class Thing
def self.hello(name)
puts "Hello, #{name}!"
end
end
Invoca el método escribiendo
Thing.hello("John Doe") # prints: "Hello, John Doe!"
Métodos singleton
Estos solo están disponibles para instancias específicas de la clase, pero no para todos.
# create an empty class
class Thing
end
# two instances of the class
thing1 = Thing.new
thing2 = Thing.new
# create a singleton method
def thing1.makestuff
puts "I belong to thing one"
end
thing1.makestuff # => prints: I belong to thing one
thing2.makestuff # NoMethodError: undefined method `makestuff' for #<Thing>
Tanto los métodos singleton
como los de class
se llaman eigenclass
es. Básicamente, lo que hace Ruby es crear una clase anónima que contenga dichos métodos para que no interfiera con las instancias que se crean.
Otra forma de hacerlo es mediante la class <<
constructor. Por ejemplo:
# a class method (same as the above example)
class Thing
class << self # the anonymous class
def hello(name)
puts "Hello, #{name}!"
end
end
end
Thing.hello("sarah") # => Hello, sarah!
# singleton method
class Thing
end
thing1 = Thing.new
class << thing1
def makestuff
puts "I belong to thing one"
end
end
thing1.makestuff # => prints: "I belong to thing one"
Creación dinámica de clases
Las clases se pueden crear dinámicamente mediante el uso de Class.new
.
# create a new class dynamically
MyClass = Class.new
# instantiate an object of type MyClass
my_class = MyClass.new
En el ejemplo anterior, se crea una nueva clase y se asigna a la constante MyClass
. Esta clase puede ser instanciada y utilizada como cualquier otra clase.
El método Class.new
acepta una Class
que se convertirá en la superclase de la clase creada dinámicamente.
# dynamically create a class that subclasses another
Staffy = Class.new(Dog)
# instantiate an object of type Staffy
lucky = Staffy.new
lucky.is_a?(Staffy) # true
lucky.is_a?(Dog) # true
El método Class.new
también acepta un bloque. El contexto del bloque es la clase recién creada. Esto permite definir métodos.
Duck =
Class.new do
def quack
'Quack!!'
end
end
# instantiate an object of type Duck
duck = Duck.new
duck.quack # 'Quack!!'
Nuevo, asignar e inicializar
En muchos idiomas, las nuevas instancias de una clase se crean utilizando una new
palabra clave especial. En Ruby, new
también se usa para crear instancias de una clase, pero no es una palabra clave; en cambio, es un método estático / clase, no es diferente de cualquier otro método estático / clase. La definición es aproximadamente esta:
class MyClass
def self.new(*args)
obj = allocate
obj.initialize(*args) # oversimplied; initialize is actually private
obj
end
end
allocate
realiza la verdadera 'magia' de crear una instancia no inicializada de la clase
Tenga en cuenta también que el valor de retorno de initialize
se descarta, y se devuelve obj en su lugar. Esto hace que sea inmediatamente claro por qué se puede codificar su método de inicialización sin tener que preocuparse acerca de regresar self
al final.
El new
método "normal" que todas las clases obtienen de la Class
funciona como se indicó anteriormente, pero es posible redefinirlo como desee, o definir alternativas que funcionen de manera diferente. Por ejemplo:
class MyClass
def self.extraNew(*args)
obj = allocate
obj.pre_initialize(:foo)
obj.initialize(*args)
obj.post_initialize(:bar)
obj
end
end