Ruby: соглашение об именах атрибутов Boolean и использование
Изучение рубина. У меня создается впечатление, что логические атрибуты должны быть названы следующим образом:
my_boolean_attribute?
Тем не менее, я получаю синтаксические ошибки при попытке сделать следующее:
class MyClass
attr_accessor :my_boolean_attribute?
def initialize
:my_boolean_attribute? = false
end
end
По-видимому, рубин ненавидит "?". Это конвенция? Что я делаю неправильно?
Ответы
Ответ 1
Изменить: три года спустя; времена, они меняются...
Ответ Джулика - это самый простой и лучший способ решить проблему в наши дни:
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
Мой ответ на исходный вопрос следует, для потомков...
Краткая версия:
Вы не можете использовать знак вопроса в имени переменной экземпляра.
Более длинная версия:
Возьмите, например, attr_accessor :foo
- it просто концептуально немного синтаксического сахара для следующего:
def foo
@foo
end
def foo=(newfoo)
@foo = newfoo
end
Кроме того, суффикс вопросительного знака в основном является просто соглашением, указывающим, что возвращаемое значение метода является логическим.
Лучшее приближение, которое я могу сделать из того, что вы собираетесь здесь...
class MyClass
def initialize
@awesome = true
end
def awesome?
@awesome
end
end
В этом случае может быть случай, когда нужно использовать attr_accessor
- в конце концов, может быть явно, что вы работаете напрямую с логическим атрибутом. Как правило, я сохраняю суффикс вопросительного знака, когда я реализую метод, логическое возвращаемое значение которого основано на несколько более сложных условиях, чем просто значение атрибута.
Ура!
Редактировать, два года спустя, после недавнего комментария:
- Ruby применяет определенные соглашения об именах.
Символы в Ruby не могут иметь вопросительные знаки. Таким образом, вызовы :my_boolean_attribute?
будут терпеть неудачу с NameError
. Изменить: не правильно, просто используйте цитированный синтаксис для символа, например :"my_attribute?"
- Символы неизменяемы, попытка присваивания одному будет вызывать
SyntaxError
.
Ответ 2
Самый простой способ быстро добавить "метод вопроса" - использовать наложение псевдонимов для вашего метода чтения
class Foo
attr_accessor :dead
alias_method :dead?, :dead # will pick up the reader method
end
Ответ 3
Символ attr_accessor
означает, что имя переменной @my_boolean_attribute
, так что вы должны устанавливать (а не символ).
Кроме того, вы не можете использовать? для переменных, просто имена методов.
Ответ 4
? это соглашение для имен методов, а не переменных. Вы не можете использовать переменную экземпляра с именем @foo?
, однако вы могли бы использовать переменную с именем @foo
и указать метод getter foo?
(вручную созданный), если хотите.
Ответ 5
Метапрограммирование Monkey-patching - возможно, его можно сделать более элегантным, это всего лишь быстрый черновик, и я не выполнял метапрограммирование на некоторое время...
# 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?
При таком подходе вы можете быть СУХОЙ и получить хороший вопросительный знак. Вам просто нужно выбрать лучшее имя, чем "bool_attr", например, "bool_attr_accessor" или что-то подобное.
Определения, которые я сделал, немного расстроены, в некотором смысле, что знак вопроса присутствует в исходном символе. Вероятно, более чистым подходом было бы избежать вопросительного знака в имени символа и добавить его во время определения метода - должно быть менее запутанным.
О, и почти забыл включить обязательную ссылку: Увидеть метаклассы четко