Книга: Metaprogramming Ruby 2
Назад: Quiz: Checked Attributes (Step 3)
Дальше: Hook Methods

Quiz: Checked Attributes (Step 4)

Where you pull a Class Macro () from your bag of tricks.

The fourth step in your development plan asks you to change the Kernel Method to a Class Macro () that’s available to all classes.

What this means is that instead of an add_checked_attribute method, you want an attr_checked method that the boss can use in a class definition. Also, instead of taking a class and an attribute name, this new method should take only the attribute name, because the class is already available as self.

Bill updates the test case:

 
require ​'test/unit'
 
 
class​ Person
*
attr_checked :age ​do​ |v|
*
v >= 18
*
end
 
end
 
 
class​ TestCheckedAttributes < Test::Unit::TestCase
 
def​ setup
*
@bob = Person.new
 
end
 
 
def​ test_accepts_valid_values
 
@bob.age = 20
 
assert_equal 20, @bob.age
 
end
 
 
def​ test_refuses_invalid_values
 
assert_raises RuntimeError, ​'Invalid attribute'​ ​do
 
@bob.age = 17
 
end
 
end
 
end

Can you write the attr_checked method and pass the tests?

Quiz Solution

Think back to the discussion of class definitions in . If you want to make attr_checked available to any class definition, you can simply make it an instance method of either Class or Module. Let’s go for the first option:

*
class​ Class
*
def​ attr_checked(attribute, &validation)
 
define_method ​"​#{attribute}​="​ ​do​ |value|
 
raise ​'Invalid attribute'​ ​unless​ validation.call(value)
 
instance_variable_set(​"@​#{attribute}​"​, value)
 
end
 
define_method attribute ​do
 
instance_variable_get ​"@​#{attribute}​"
 
end
*
end
*
end

This code doesn’t even need to call to class_eval, because when the method executes, the class is already taking the role of self.

“That’s great,” Bill says. “One more step, and we’ll be done.” For this last step, however, you need to learn about a feature that we haven’t talked about yet: Hook Methods.

Назад: Quiz: Checked Attributes (Step 3)
Дальше: Hook Methods