2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
|
# File 'lib/must_be/attr_typed.rb', line 2
def attr_typed(symbol, *types, &test)
raise TypeError, "#{symbol} is not a symbol" if symbol.is_a? Integer
types.each do |type|
raise TypeError, "class or module required" unless type.is_a? Module
end
attr_reader symbol
name = symbol.to_sym.id2name
check_method_name = "attr_typed__check_#{name}"
unless types.empty?
types_message = types.size == 1 ? types[0] :
types.size == 2 ? "#{types[0]} or #{types[1]}" :
"one of #{types.inspect}"
type_check = lambda do |value|
if types.none?{|type| value.is_a? type }
must_notify("attribute `#{name}' must be a #{types_message},"\
" but value #{value.inspect} is a #{value.class}")
end
end
end
if test
test_check = lambda do |value|
unless test[value]
must_notify("attribute `#{name}' cannot be #{value.inspect}")
end
end
end
define_method(check_method_name, &(
if types.empty?
if test
test_check
else
lambda do |value|
if value.nil?
must_notify("attribute `#{name}' cannot be nil")
end
end
end
else
if test
lambda do |value|
type_check[value]
test_check[value]
end
else
type_check
end
end
))
module_eval(<<-END, __FILE__, __LINE__ + 1)
def #{name}=(value)
#{check_method_name}(value)
@#{name} = value
end
END
end
|