O que faz uma constante
Um oito, escrito em letras maiúsculas
O Auth::PasswordPolicy desta app começa com três linhas que decidem como toda senha da app é validada:
module Auth
class PasswordPolicy
MIN_LENGTH = 8
MAX_LENGTH = 128
FORMAT = /\A(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[^a-zA-Z\d\s]).+\z/
end
end
MIN_LENGTH, MAX_LENGTH e FORMAT são constantes. Nada na sintaxe é especial: elas são atribuídas com o mesmo = de qualquer variável local. O Ruby as trata de outro jeito por uma regra: um nome que começa com letra maiúscula é uma constante. min_length seria uma variável local e MIN_LENGTH é uma constante, e o interpretador decide isso ao ler o nome, sem declaração separada.
Por que não escrever 8?
Todo lugar que checa o tamanho de uma senha lê Auth::PasswordPolicy::MIN_LENGTH em vez do literal 8. É esse o ponto: um nome, definido uma vez, lido em todo lugar. Se a política mudar para um mínimo de dez caracteres no próximo trimestre, uma linha muda. Toda validação, mensagem de erro e teste que se refere a MIN_LENGTH pega o valor novo. Um 8 solto espalhado por uma dúzia de arquivos pediria uma dúzia de edições, e alguém esqueceria uma.
A convenção de nome: SCREAMING_SNAKE_CASE
O Ruby só exige que a primeira letra seja maiúscula. A convenção da comunidade para constantes que guardam um valor fixo é SCREAMING_SNAKE_CASE, tudo maiúsculo com palavras separadas por sublinhado: MIN_LENGTH, e não MinLength ou Minlength. Nomes de classe e de módulo também são constantes em Ruby (mais sobre isso adiante no curso), e seguem outra convenção, CamelCase, como o próprio PasswordPolicy. Os dois são constantes; a caixa das letras diz qual tipo você está vendo.
Reatribuir uma constante gera aviso, não erro
Rode isto e o Ruby não impede:
X = 1
X = 2
# warning: already initialized constant X
# warning: previous definition of X was here
Os dois avisos aparecem, X termina valendo 2 e o programa segue rodando. Isso surpreende quem vem de linguagens em que reatribuir uma constante é erro de compilação. As constantes do Ruby são uma convenção de nome apoiada por um aviso, e não uma regra que o interpretador impõe. O aviso vai para o stderr mesmo sem a flag -w do Ruby, então é fácil perdê-lo num log movimentado. Ele existe para pegar o engano de redefinir algo que deveria ficar fixo.
Constantes podem viver em qualquer nível
MIN_LENGTH vive dentro de Auth::PasswordPolicy, no escopo dessa classe. Uma constante também pode viver no nível de cima de um arquivo, fora de qualquer classe ou módulo. Para algo além de um script avulso, porém, isso arrisca colidir com outra constante de nível de cima em algum ponto de uma app grande. Pôr constantes dentro de um módulo ou classe, como o PasswordPolicy faz, é o jeito comum de evitar a colisão. Uma aula mais adiante volta a isso ao ver como o Ruby acha uma constante.
O que este curso cobre
A aula "Módulos como namespaces", de Módulos Ruby, mostrou o Catalog::Course usando :: para agrupar as classes de uma área de negócio sob um nome comum. Este curso parte disso e vai aonde aquela aula não foi. Ele cobre o que é uma constante, por que reatribuir uma só gera aviso e por que uma constante ainda pode ser alterada apesar do nome. Depois vêm a ordem em que o Ruby procura uma constante e o const_get/const_set para alcançar uma constante por um nome calculado em tempo de execução. As últimas aulas ligam tudo a um arquivo desta app, o app/services/auth.rb, e a uma surpresa sobre como o autoloading do Rails o trata.
Pontos-chave
- Uma constante é qualquer nome que começa com letra maiúscula; o Ruby decide isso ao ler o código, sem declaração separada.
SCREAMING_SNAKE_CASEé a convenção para constantes que guardam valores;CamelCaseé a convenção para classes e módulos, que também são constantes.- Reatribuir uma constante imprime
warning: already initialized constant Xe segue rodando; não levanta erro. Auth::PasswordPolicy::MIN_LENGTHé a fonte única do tamanho de senha nesta app, lida em todo lugar em vez de um número mágico repetido.
Continue com a aula 2
Constantes ainda podem ser mutadas
Mudar o objeto para o qual a constante aponta não gera aviso, então constantes Array e Hash precisam de .freeze.
Com uma conta grátis você também tem os quizzes, seu progresso e suas anotações, e a discussão.