Question

Learning ruby. I'm under the impression that boolean attributes should be named as follows:

my_boolean_attribute?

However, I get syntax errors when attempting to do the following:

class MyClass
  attr_accessor :my_boolean_attribute?

  def initialize
    :my_boolean_attribute? = false
  end
end

Apparently ruby is hating the "?". Is this the convention? What am I doing wrong?

Was it helpful?

Solution

Edit: three-years later; the times, they are a-changin'…

Julik's answer is the simplest and best way to tackle the problem these days:

class Foo
  attr_accessor :dead
  alias_method :dead?, :dead # will pick up the reader method
end

My answer to the original question follows, for posterity…


The short version:

You can't use a question mark in the name of an instance variable.

The longer version:

Take, for example, attr_accessor :foo — it's simply conceptually a bit of syntactic sugar for the following:

def foo
  @foo
end

def foo=(newfoo)
  @foo = newfoo
end

Furthermore, the question-mark suffix is mostly just a convention to indicate that the return value of a method is a boolean.

The best approximation I can make of what you're going for here…

class MyClass

  def initialize
    @awesome = true
  end

  def awesome?
    @awesome
  end

end

In this case, there may be a case to be made for using attr_accessor — after all, it may be explicit that you're working directly with a boolean attribute. Generally, I save the question-mark suffix for when I am implementing a method whose boolean return value is based on slightly more complex conditions than just the value of an attribute.

Cheers!


Edit, two years later, after a recent comment:

  1. Ruby enforces certain naming conventions. Symbols in Ruby can't have question marks. Thus invocations of :my_boolean_attribute? both will fail with a NameError. Edit: not correct, just use the quoted syntax for a symbol, e.g., :"my_attribute?"
  2. Symbols are immutable, attempting to assign to one will throw a SyntaxError.

OTHER TIPS

The easiest way to quickly add a "question method" is to use aliasing for your reader method

class Foo
  attr_accessor :dead
  alias_method :dead?, :dead # will pick up the reader method
end 

The attr_accessor symbol implies that the variable name is @my_boolean_attribute, so that's what you should be setting (not the symbol).

Also, you can't use ? for variables, just method names.

? is convention for methodnames, not variables. You can't use an instance variable named @foo?, however you could use a variable named @foo and name the (manually created) getter method foo? if you wanted to.

Monkey-patching metaprogramming - maybe it can be made more elegant, this is only a quick draft, and I haven't done metaprogramming for a little while...

 # 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?

With this approach, you can be DRY and get the nice questionmark too. You just might need to pick a better name than "bool_attr", like, "bool_attr_accessor" or something similar.

The definitions that I made are a bit cranky, in a sense that the question mark is present in the original symbol. Probably a cleaner approach would be to avoid the questionmark in the symbol name and append it during the definition of the method - should be less confusing.

Oh, and almost forgot to include the obligatory link: Seeing metaclasses clearly

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top