diff options
author | Jeremy Kemper <jeremy@bitsweat.net> | 2009-10-19 12:33:36 -0700 |
---|---|---|
committer | Jeremy Kemper <jeremy@bitsweat.net> | 2009-10-19 12:33:36 -0700 |
commit | a49c3b03650b3193cc9440a3b219ab7f19326297 (patch) | |
tree | dd68d637a074bc08d1328d780aeb092b2a4c8874 /activerecord/lib/active_record/attributes/typecasting.rb | |
parent | 028911ad00e7f7733064a80393a1548401bba7af (diff) | |
parent | 1ac5cf478825391071d34ec3d7f294fe28c0fceb (diff) | |
download | rails-a49c3b03650b3193cc9440a3b219ab7f19326297.tar.gz rails-a49c3b03650b3193cc9440a3b219ab7f19326297.tar.bz2 rails-a49c3b03650b3193cc9440a3b219ab7f19326297.zip |
Merge branch 'master' of github.com:rails/rails
Diffstat (limited to 'activerecord/lib/active_record/attributes/typecasting.rb')
-rw-r--r-- | activerecord/lib/active_record/attributes/typecasting.rb | 117 |
1 files changed, 117 insertions, 0 deletions
diff --git a/activerecord/lib/active_record/attributes/typecasting.rb b/activerecord/lib/active_record/attributes/typecasting.rb new file mode 100644 index 0000000000..56c32f9895 --- /dev/null +++ b/activerecord/lib/active_record/attributes/typecasting.rb @@ -0,0 +1,117 @@ +module ActiveRecord + module Attributes + module Typecasting + # Typecasts values during access based on their key mapping to a Type. + # + # Example: + # class Attributes < Hash + # include Typecasting + # end + # + # attributes = Attributes.new + # attributes.types['comments_count'] = Type::Integer + # attributes['comments_count'] = '5' + # + # attributes['comments_count'] + # => 5 + # + # To support keys not mapped to a typecaster, add a default to types. + # attributes.types.default = Type::Unknown + # attributes['age'] = '25' + # attributes['age'] + # => '25' + # + # A valid type supports #cast, #precast, #boolean, and #appendable? methods. + # + def [](key) + value = super(key) + typecast_read(key, value) + end + + def []=(key, value) + super(key, typecast_write(key, value)) + end + + def to_h + hash = {} + hash.merge!(self) + hash + end + + def dup # :nodoc: + copy = super + copy.types = types.dup + copy + end + + # Provides a duplicate with typecasting disabled. + # + # Example: + # attributes = Attributes.new + # attributes.types['comments_count'] = Type::Integer + # attributes['comments_count'] = '5' + # + # attributes.without_typecast['comments_count'] + # => '5' + # + def without_typecast + dup.without_typecast! + end + + def without_typecast! + types.clear + self + end + + def typecast! + keys.each { |key| self[key] = self[key] } + self + end + + # Check if key has a value that typecasts to true. + # + # attributes = Attributes.new + # attributes.types['comments_count'] = Type::Integer + # + # attributes['comments_count'] = 0 + # attributes.has?('comments_count') + # => false + # + # attributes['comments_count'] = 1 + # attributes.has?('comments_count') + # => true + # + def has?(key) + value = self[key] + boolean_typecast(key, value) + end + + def types + @types ||= {} + end + + protected + + def types=(other_types) + @types = other_types + end + + def boolean_typecast(key, value) + value ? types[key].boolean(value) : false + end + + def typecast_read(key, value) + type = types[key] + value = type.cast(value) + self[key] = value if type.appendable? && !frozen? + + value + end + + def typecast_write(key, value) + types[key].precast(value) + end + + end + end +end |