Ruby: booleana convenção atributo de nomeação e uso
-
13-09-2019 - |
Pergunta
Aprendizagem rubi. Tenho a impressão de que atributos booleanos devem ser nomeados da seguinte forma:
my_boolean_attribute?
No entanto, eu recebo erros de sintaxe ao tentar fazer o seguinte:
class MyClass
attr_accessor :my_boolean_attribute?
def initialize
:my_boolean_attribute? = false
end
end
Aparentemente rubi é odiar o "?". Não é a convenção? O que estou fazendo de errado?
Solução
Editar: três anos depois; os tempos, eles estão mudando ...
de Julik resposta é a maneira mais simples e melhor para resolver o problema nos dias de hoje:
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
A minha resposta à pergunta original segue, para a posteridade ...
A versão curta:
Você não pode usar um ponto de interrogação em nome de uma variável de instância.
A versão mais longa:
Tome-se, por exemplo, attr_accessor :foo
- é simplesmente conceitualmente um pouco de açúcar sintático para o seguinte:
def foo
@foo
end
def foo=(newfoo)
@foo = newfoo
end
Além disso, o sufixo de ponto de interrogação é na maior parte apenas uma convenção para indicar que o valor de retorno de um método é um boolean.
A melhor aproximação que eu posso fazer do que você está indo para aqui ...
class MyClass
def initialize
@awesome = true
end
def awesome?
@awesome
end
end
Neste caso, pode haver um caso a ser feito para usar attr_accessor
- afinal, pode ser explícito que você está trabalhando diretamente com um atributo booleano. Geralmente, eu salvar o sufixo de ponto de interrogação para quando estou implementando um método cujo valor de retorno boolean é baseado em condições um pouco mais complexa do que apenas o valor de um atributo.
Felicidades!
Editar, dois anos mais tarde, depois de um comentário recente:
- Ruby obriga a certas convenções de nomenclatura.
Símbolos em Ruby não pode ter pontos de interrogação. Assim invocações deEdit:. Não é correto, é só usar a sintaxe cotado para um símbolo, por exemplo,:my_boolean_attribute?
ambos vão falhar com umNameError
:"my_attribute?"
- Símbolos são imutáveis, a tentativa de atribuir a um vai jogar um
SyntaxError
.
Outras dicas
A maneira mais fácil de adicionar rapidamente um "método de pergunta" é utilizar aliasing para o seu método de leitura
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
O símbolo attr_accessor
implica que o nome da variável é @my_boolean_attribute
, então é isso que você deve ser de ajuste (não o símbolo).
Além disso, você não pode usar? para variáveis, os nomes apenas de método.
? é convenção para methodnames, não variáveis. Você não pode usar uma variável de instância nomeada @foo?
, no entanto, você poderia usar uma variável chamada @foo
e nome do (criado manualmente) método getter foo?
se você quisesse.
metaprogramming Macaco-patch - talvez ele possa ser mais elegante, este é apenas um rascunho rápido, e eu não fiz metaprogramming por pouco tempo ...
# inject the convenience method into the definition of the Object class
class Object
def Object::bool_attr(attrname)
class_eval { define_method(attrname.to_s,
lambda { instance_variable_get('@' + attrname.to_s.chop) }) }
class_eval { define_method(attrname.to_s.chop+"=",
lambda { |x| instance_variable_set('@'+attrname.to_s.chop, x) }) }
end
end
### somewhere later
class MyClass
bool_attr :my_boolean_attribute?
def initialize
@my_boolean_attribute = true
end
end
# yet even more later
foo = MyClass.new
bar = MyClass.new
foo.my_boolean_attribute = 1
puts foo.my_boolean_attribute?
puts bar.my_boolean_attribute?
Com esta abordagem, você pode ser seco e obter o bom questionmark também. Você só pode precisar escolher um nome melhor do que " bool_attr ", como, " bool_attr_accessor " ou algo similar.
As definições que eu fiz são um pouco irritadiço, no sentido de que o ponto de interrogação está presente no símbolo original. Provavelmente uma abordagem mais limpo seria para evitar o questionmark no nome do símbolo e anexá-lo durante a definição do método -. Deve ser menos confuso
Oh, e quase se esqueceu de incluir o link obrigatório: Vendo metaclasses claramente