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

Quiz: Checked Attributes (Step 3)

Where you sprinkle some flexibility over today’s project.

To solve the boss’ challenge, you and Bill still need to implement a few important features. One of these features is described in the third step of your development plan: “validate attributes through a block.” Right now, your generated attribute raises an exception if you assign it nil or false. But it’s supposed to support flexible validation through a block.

Because this step changes the interface of add_checked_attribute, it also calls for an update of the test suite. Bill replaces the two test cases that checked for nil or false attributes with a single new test case:

 
require ​'test/unit'
 
 
class​ Person; ​end
 
 
class​ TestCheckedAttribute < Test::Unit::TestCase
 
def​ setup
*
add_checked_attribute(Person, :age) {|v| v >= 18 }
 
@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
 
*
def​ add_checked_attribute(klass, attribute, &validation)
 
# ... (The code here doesn't pass the test. Modify it.)
 
end

Can you modify add_checked_attribute so that it passes the new tests?

Quiz Solution

You can pass the tests and solve the quiz by changing a couple of lines in add_checked_attribute:

*
def​ add_checked_attribute(klass, attribute, &validation)
 
klass.class_eval ​do
 
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

“Step 3 was quick,” Bill notes. “Let’s move on to step 4.”

Назад: Quiz: Checked Attributes (Step 2)
Дальше: Quiz: Checked Attributes (Step 4)