Skip to content

Commit

Permalink
Extract casts to their own module
Browse files Browse the repository at this point in the history
Simplifies ModelAttribute class; means that it doesn't add a 'cast' method to
classes that extend ModelAttribute.
  • Loading branch information
dwaller committed Apr 1, 2015
1 parent d53f86b commit 8adb324
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 76 deletions.
51 changes: 2 additions & 49 deletions lib/model_attribute.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
require "model_attribute/version"
require "model_attribute/json"
require "model_attribute/casts"
require "model_attribute/errors"
require "time"

Expand Down Expand Up @@ -56,7 +56,7 @@ def write_attribute(name, value, type = nil)
type ||= self.class.instance_variable_get('@attribute_types')[name]
raise InvalidAttributeNameError.new(name) unless type

value = cast(value, type)
value = Casts.cast(value, type)
return if value == read_attribute(name)

if changes.has_key? name
Expand Down Expand Up @@ -151,52 +151,5 @@ def inspect
end.join(', ')
"#<#{self.class} #{attribute_string}>"
end

def cast(value, type)
return nil if value.nil?

case type
when :integer
int = Integer(value)
float = Float(value)
raise "Can't cast #{value.inspect} to an integer without loss of precision" unless int == float
int
when :boolean
if !!value == value
value
elsif value == 't'
true
elsif value == 'f'
false
else
raise "Can't cast #{value.inspect} to boolean"
end
when :time
case value
when Time
value
when Date, DateTime
value.to_time
when Integer
# Assume milliseconds since epoch.
Time.at(value / 1000.0)
when Numeric
# Numeric, but not an integer. Assume seconds since epoch.
Time.at(value)
else
Time.parse(value)
end
when :string
String(value)
when :json
if Json.valid?(value)
value
else
raise "JSON only supports nil, numeric, string, boolean and arrays and hashes of those."
end
else
raise UnsupportedTypeError.new(type)
end
end
end
end
74 changes: 74 additions & 0 deletions lib/model_attribute/casts.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
module ModelAttribute
module Casts
class << self
def cast(value, type)
return nil if value.nil?

case type
when :integer
int = Integer(value)
float = Float(value)
raise "Can't cast #{value.inspect} to an integer without loss of precision" unless int == float
int
when :boolean
if !!value == value
value
elsif value == 't'
true
elsif value == 'f'
false
else
raise "Can't cast #{value.inspect} to boolean"
end
when :time
case value
when Time
value
when Date, DateTime
value.to_time
when Integer
# Assume milliseconds since epoch.
Time.at(value / 1000.0)
when Numeric
# Numeric, but not an integer. Assume seconds since epoch.
Time.at(value)
else
Time.parse(value)
end
when :string
String(value)
when :json
if valid_json?(value)
value
else
raise "JSON only supports nil, numeric, string, boolean and arrays and hashes of those."
end
else
raise UnsupportedTypeError.new(type)
end
end

private

def valid_json?(value)
(value == nil ||
value == true ||
value == false ||
value.is_a?(Numeric) ||
value.is_a?(String) ||
(value.is_a?(Array) && valid_json_array?(value)) ||
(value.is_a?(Hash) && valid_json_hash?(value) ))
end

def valid_json_array?(array)
array.all? { |value| valid_json?(value) }
end

def valid_json_hash?(hash)
hash.all? do |key, value|
key.is_a?(String) && valid_json?(value)
end
end
end
end
end
27 changes: 0 additions & 27 deletions lib/model_attribute/json.rb

This file was deleted.

0 comments on commit 8adb324

Please sign in to comment.