C
Clifford Heath
Here's a function similar to attr_accessor, except it takes a block,
which is used to validate assignments to the attribute, and substitute
in a string value to be used as a key to the hash inside class_eval.
It's just ugly having to use a hash to store the block. class_eval and
friends should support saving parameters into global variables for the
duration? Or is there an obvious way of doing this that I've missed?
I removed some checking for simplicity.
Clifford Heath.
def validated_attr(*names, &block)
begin
Thread.critical = true
$__VALIDATOR_BLOCK ||= {}
while $__VALIDATOR_BLOCK.has_key?([r = (rand*16777216).to_i]); end
$__VALIDATOR_BLOCK[r] = block
ensure
Thread.critical = false
end
names.each{|name|
class_eval <<-END
def #{name}
@#{name}
end
def #{name}=(__val)
if !$__VALIDATOR_BLOCK[#{r.to_s}.to_i].call(__val)
throw "Invalid assignment of \#{__val.inspect} to #{name}"
end
@#{name} = __val
end
END
}
end
class Foo
validated_attrbar) {|v| v.kind_of?(Integer) && (0..14).include?(v)}
end
f = Foo.new
begin
f.bar = 2 # Ok
rescue => e
puts e.to_s
end
begin
f.bar = 15 # Not ok
rescue => e
puts e.to_s
end
begin
f.bar = "Hi there" # Not ok
rescue => e
puts e.to_s
end
which is used to validate assignments to the attribute, and substitute
in a string value to be used as a key to the hash inside class_eval.
It's just ugly having to use a hash to store the block. class_eval and
friends should support saving parameters into global variables for the
duration? Or is there an obvious way of doing this that I've missed?
I removed some checking for simplicity.
Clifford Heath.
def validated_attr(*names, &block)
begin
Thread.critical = true
$__VALIDATOR_BLOCK ||= {}
while $__VALIDATOR_BLOCK.has_key?([r = (rand*16777216).to_i]); end
$__VALIDATOR_BLOCK[r] = block
ensure
Thread.critical = false
end
names.each{|name|
class_eval <<-END
def #{name}
@#{name}
end
def #{name}=(__val)
if !$__VALIDATOR_BLOCK[#{r.to_s}.to_i].call(__val)
throw "Invalid assignment of \#{__val.inspect} to #{name}"
end
@#{name} = __val
end
END
}
end
class Foo
validated_attrbar) {|v| v.kind_of?(Integer) && (0..14).include?(v)}
end
f = Foo.new
begin
f.bar = 2 # Ok
rescue => e
puts e.to_s
end
begin
f.bar = 15 # Not ok
rescue => e
puts e.to_s
end
begin
f.bar = "Hi there" # Not ok
rescue => e
puts e.to_s
end