Ruby
Classes em Ruby
O código a seguir define uma classe chamada Person. Além de inicializar, o construtor usual cria novos objetos, ele tem dois métodos:- um para substituir o <=> operador de comparação (assim Array # sort pode classificar por idade)
- outro para substituir o método to_s (assim Kernel # puts pode formatar a sua saída).
Aqui, attr_reader é um exemplo de metaprogramação em Ruby: attr_accessor define métodos getter e setter de variáveis de instância, mas attr_reader somente os métodos getter.
A última declaração avaliada em um método é seu valor de retorno, permitindo a omissão de uma instrução de retorno explícita.
class Person attr_reader :name, :age
def initialize(name, age) @name, @age = name, age end
def <=>(person) # the comparison operator for sorting age <=> person.age end
def to_s "#{name} (#{age})" end end group = [ Person.new("Bob", 33), Person.new("Chris", 16), Person.new("Ash", 23) ] puts group.sort.reverse
O código anterior exibe três nomes em ordem reversa de idade:
Bob (33) Ash (23) Chris (16)
Person é uma constante e é uma referência a um objeto class.
Classes abertas
Em Ruby, as classes nunca estão fechadas: métodos podem sempre ser adicionados a uma classe existente. Isso se aplica a todas as classes, incluindo o padrão, classes internas.
Tudo que é necessário fazer é abrir uma definição de classe para uma classe existente e os novos conteúdos especificados serão adicionados aos conteúdos existentes.
Um exemplo simples de adicionar um novo método à classe Time da biblioteca padrão:
# re-open Ruby's Time class class Time def yesterday self - 86400 end end today = Time.now # => 2013-09-03 16:09:37 +0300 yesterday = today.yesterday # => 2013-09-02 16:09:37 +0300
Adicionando métodos a classes previamente definidas é freqüentemente chamado de monkey-patching (uma maneira de estender ou modificar o código em tempo de execução de linguagens dinâmicas, sem alterar o código fonte original). No entanto, se realizada de forma imprudente, essa prática pode levar a colisões de comportamento e resultados inesperados subsequentes e problemas com escalabilidade código.
Tratamento de Exceções
Uma exceção pode ser tratada com uma chamada
raise
:raise
Uma mensagem opcional pode ser adicionada a exceção:
raise "This is a message"
Exceções pode também ser especificadas pelo programador:
raise ArgumentError, "Illegal arguments!"
Como alternativa, uma instância de exceção pode se passada ao método raise:
raise ArgumentError.new("Illegal arguments!")
Esta última estrutura é útil quando uma classe de exceção personalizada com um construtor que toma mais que um argumento precisa ser gerada:
class ParseError < Exception def initialize input, line, pos super "Could not parse '#{input}' at line #{line}, position #{pos}" end end raise ParseError.new("Foo", 3, 9)
Exceções poder ser tratadas com a cláusula rescue; esta cláusula pode captar exceções que herdam StandardError. Outra palavras chaves de controle de fluxo que pode ser usadas quando fizer tratamento de exceções são
else
e ensure :
begin # do something rescue # handle exception else # do this if no exception was raised ensure # do this whether or not an exception was raised end
É um erro comum tentar captar todas as exceções com uma simples cláusula rescue. Para captar todas as exceções, deve-se escrever:
begin # do something rescue Exception # Exception handling code here. # Don't write only "rescue"; that only catches StandardError, a subclass of Exception. end
Ou captar exceções particulares:
begin # do something rescue RuntimeError # handle only RuntimeError and its subclasses end
Também é possível especificar que o objeto exceção seja disponível para a cláusula de tratamento:
begin # do something rescue RuntimeError => e # handling, possibly involving e, such as "puts e.to_s" end
Alternativamente, a exceção mais recente é armazenada no genérico $. Muitas exceções pode ser também captadas:
begin # do something rescue RuntimeError, Timeout::Error => e # handling, possibly involving e end
Nenhum comentário:
Postar um comentário