I was reading another SO question Enums in Ruby and it had the following code snippet:
class Enum
private
def self.enum_attr(name, num)
name = name.to_s
define_method(name + '?') do
@attrs & num != 0
end
define_method(name + '=') do |set|
if set
@attrs |= num
else
@attrs &= ~num
end
end
end
public
def initialize(attrs = 0)
@attrs = attrs
end
def to_i
@attrs
end
end
As I understand this, this is defining a class method named enum_attr, is that correct? What I’m unsure of is what it means to have the define_method statements inside of the enum_attr method.
Then later on that post it shows the class being extended as follows
class FileAttributes < Enum
enum_attr :readonly, 0x0001
enum_attr :hidden, 0x0002
end
I don’t quite understand what this second part does – can someone explain?
In
Enum, a method,enum_attr, is defined on the class’s singleton, and is available to all subclasses. This method is in scope in the class definition body, and inFileAttributesit is being called with the arguments:readonly, 0x0001and then:hidden, 0x0002.When
enum_attris called (let’s look at just the first call,enum_attr :readonly, 0x0001), it defines two methods:readonly?&readonly=(set). The result of this call toenum_attris functionally equivalent to writing out the following inFileAttributes:Since the block passed to
define_methodis a closure, the variablenumfrom the scope in which the block is passed is still in scope when you call the method that is defined. In other words, thenumvariable passed in toenum_attris still available within the generated methodsreadonly?&readonly=when they are called later from a different scope.define_methodmust be used because the name of the method is being dynamically generated (i.e., we do not know the name of the method ahead of time).