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
64
65
66
67
68
69
70
71
|
# File 'lib/modis/attribute.rb', line 32
def attribute(name, type, options = {})
name = name.to_s
raise AttributeError, "Attribute with name '#{name}' has already been specified." if attributes.key?(name)
type_classes = Array(type).map do |t|
raise UnsupportedAttributeType, t unless TYPES.key?(t)
TYPES[t]
end.flatten
attributes[name] = options.update(type: type)
attributes_with_defaults[name] = options[:default]
define_attribute_methods([name])
value_coercion = type == :timestamp ? 'value = Time.new(*value) if value && value.is_a?(Array) && value.count == 7' : nil
predicate = type_classes.map { |cls| "value.is_a?(#{cls.name})" }.join(' || ')
type_check = <<-RUBY
if value && !(#{predicate})
raise Modis::AttributeCoercionError, "Received value of type '\#{value.class}', expected '#{type_classes.join("', '")}' for attribute '#{name}'."
end
RUBY
class_eval <<-RUBY, __FILE__, __LINE__ + 1
def #{name}
attributes['#{name}']
end
def #{name}=(value)
#{value_coercion}
# ActiveSupport's Time#<=> does not perform well when comparing with NilClass.
if (value.nil? ^ attributes['#{name}'].nil?) || (value != attributes['#{name}'])
#{type_check}
#{name}_will_change!
attributes['#{name}'] = value
end
end
RUBY
end
|