Книга: 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)