Os módulos em Crystal servem dois propósitos:
O primeiro é criar um espaço de nomes para evitar colisões de nomes. No entanto, também agrupam o código, o que facilita perceber para que serve.
O segundo é definir mixins para partilhar código entre tipos.
Os módulos são semelhantes às classes, mas a principal diferença é que não podem ser instanciados e, por isso, não têm variáveis de instância.
Para declarar um módulo, usas a palavra-chave module seguida do nome do módulo.
module Foo
end
Um espaço de nomes é uma forma de agrupar código.
Isso evita colisões de nomes e facilita perceber para que serve o código.
Quando queres aceder a uma constante ou a uma classe que foi colocada dentro de um espaço de nomes, usas o operador ::.
module Foo
class Bar
end
end
Foo::Bar.new
Isto pode ser útil quando, por exemplo, várias classes precisam da mesma funcionalidade "base" ou quando é preciso partilhar código entre classes não relacionadas. Ou quando queres partilhar código entre classes que não estão relacionadas.
Há duas formas diferentes de usar um módulo como mixin: a primeira é usar a palavra-chave include e a segunda é usar a palavra-chave extend.
Ambos os métodos tornam as constantes disponíveis para o tipo que inclui ou estende o módulo.
O include disponibiliza todos os métodos do módulo como métodos de instância no tipo que inclui o módulo.
A palavra-chave include deve ficar no início do tipo, seguida do nome do módulo.
module Foo
def foo
"foo"
end
end
class Bar
include Foo
end
Bar.new.foo # => "foo"
O extend funciona de forma semelhante ao include, mas em vez de disponibilizar os métodos como métodos de instância, disponibiliza-os como métodos de classe.
A palavra-chave extend deve ser escrita no início do tipo, seguida do nome do módulo.
module Foo
def foo
"foo"
end
end
class Bar
extend Foo
end
Bar.foo # => "foo"
Um padrão típico em Crystal usa o padrão extend self num módulo.
Isto torna todos os métodos do módulo disponíveis como métodos de classe no próprio módulo.
Isto significa que não precisas de atribuir cada método ao módulo com a sintaxe def self.method_name.
module Foo
extend self
def foo
"foo"
end
end
Foo.foo # => "foo"
A Bellebrook Basketball League é uma liga com várias equipas, cada uma com um plantel de jogadores. Está prestes a começar uma nova época, e eles precisam de criar um novo sistema de bilhetes para vender bilhetes para os jogos. Na época passada, vendiam bilhetes à entrada do estádio, mas a popularidade disparou, e este ano decidiram vender bilhetes online para dar resposta ao aumento da procura.
A liga contactou-te e pediu-te para criares um sistema para gerir a venda de bilhetes.
Primeiro, precisas de criar um sistema de bilhetes para gerir a venda de bilhetes. O sistema de bilhetes tem de indicar quantos bilhetes estão disponíveis para um jogo.
Deve ser criada uma instância de uma classe chamada TicketSystem para cada jogo.
O estado inicializado deve conter as seguintes informações:
Constrói um estado inicializado a partir de argumentos que indiquem o número de bilhetes disponíveis e em que estádio o jogo se realiza.
O estado inicializado deve ser composto pelas variáveis de instância @tickets_available e @stadium.
Estas devem conter o primeiro e o segundo argumentos dados, respetivamente.
TicketSystem.new(100, "Bellebrook")
# => #<TicketSystem:0x10f0b8 @tickets_available=100, @stadium="Bellebrook">
Primeiro, precisas de criar um método que devolva a quantidade de bilhetes disponíveis para um determinado jogo.
Define um módulo chamado TicketingReservation acima da classe já definida.
Este módulo deve ser incluído na classe TicketSystem.
Dentro do módulo, define um método chamado tickets_available.
Este método deve devolver a quantidade de bilhetes disponíveis.
ticket_system = TicketSystem.new(100)
ticket_system.tickets_available
#=> 100
Tens de criar um método que verifique se há bilhetes disponíveis para um determinado jogo. O jogo precisa de ter 100 bilhetes de reserva. Isto serve para garantir que há sempre bilhetes disponíveis para as pessoas que compram bilhetes à entrada do estádio.
Dentro do módulo TicketingReservation, define um método chamado order_ticket?.
O método deve devolver true se estiverem disponíveis pelo menos 100 bilhetes e false caso contrário.
Se estiverem disponíveis pelo menos 100 bilhetes, o método também deve diminuir em 1 o número de bilhetes disponíveis.
ticket_system = TicketSystem.new(100)
ticket_system.order_ticket?
#=> true
O sistema de bilhetes tem de ter mensagens fáceis de compreender para os utilizadores. E as mensagens devem parecer pessoais, por isso devem incluir o nome do utilizador.
Se a compra do bilhete for bem-sucedida, o utilizador deve receber uma mensagem a informá-lo de que a compra foi bem-sucedida, do seu número de bilhete e do estádio onde o jogo se realiza. O número do bilhete deve ser o número de bilhetes disponíveis antes da encomenda.
Se a compra for bem-sucedida, a mensagem deve ter este aspeto: {name}, your purchase was successful, your ticket number is #{ticket_number}, and the game is played at the {stadium_name} stadium..
Se a compra não for bem-sucedida, a mensagem deve ter este aspeto: {name}, your purchase was unsuccessful, there are not enough tickets available..
Dentro do módulo TicketingReservation, define um método chamado order_message que recebe um argumento name com o nome do comprador.
O método deve devolver uma string com a mensagem.
ticket_system = TicketSystem.new(100, "Bellebrook")
ticket_system.order_message("John")
#=> "John, your purchase was successful, your ticket number is #100, and the game is played at the Bellebrook stadium."
Inscreve-te no Exercism para aprenderes e dominares Crystal com 26 conceitos142 exercícios, e mentoria humana real, tudo grátis.