b0d2258bd3
database, and more dependencies on active_support.
176 lines
5.2 KiB
Ruby
176 lines
5.2 KiB
Ruby
require 'time'
|
|
require 'bigdecimal'
|
|
require 'bigdecimal/util'
|
|
require File.join(File.dirname(__FILE__), 'property')
|
|
|
|
class Time
|
|
# returns a local time value much faster than Time.parse
|
|
def self.mktime_with_offset(string)
|
|
string =~ /(\d{4})[\-|\/](\d{2})[\-|\/](\d{2})[T|\s](\d{2}):(\d{2}):(\d{2})([\+|\s|\-])*(\d{2}):?(\d{2})/
|
|
# $1 = year
|
|
# $2 = month
|
|
# $3 = day
|
|
# $4 = hours
|
|
# $5 = minutes
|
|
# $6 = seconds
|
|
# $7 = time zone direction
|
|
# $8 = tz difference
|
|
# utc time with wrong TZ info:
|
|
time = mktime($1, RFC2822_MONTH_NAME[$2.to_i - 1], $3, $4, $5, $6, $7)
|
|
tz_difference = ("#{$7 == '-' ? '+' : '-'}#{$8}".to_i * 3600)
|
|
time + tz_difference + zone_offset(time.zone)
|
|
end
|
|
end
|
|
|
|
module CouchRest
|
|
module More
|
|
module Typecast
|
|
|
|
def typecast_value(value, klass, init_method)
|
|
return nil if value.nil?
|
|
klass = klass.constantize unless klass.is_a?(Class)
|
|
if value.instance_of?(klass) || klass == Object
|
|
value
|
|
elsif [String, TrueClass, Integer, Float, BigDecimal, DateTime, Time, Date, Class].include?(klass)
|
|
send('typecast_to_'+klass.to_s.downcase, value)
|
|
else
|
|
# Allow the init_method to be defined as a Proc for advanced conversion
|
|
init_method.is_a?(Proc) ? init_method.call(value) : klass.send(init_method, value)
|
|
end
|
|
end
|
|
|
|
protected
|
|
|
|
# Typecast a value to an Integer
|
|
def typecast_to_integer(value)
|
|
typecast_to_numeric(value, :to_i)
|
|
end
|
|
|
|
# Typecast a value to a String
|
|
def typecast_to_string(value)
|
|
value.to_s
|
|
end
|
|
|
|
# Typecast a value to a true or false
|
|
def typecast_to_trueclass(value)
|
|
if value.kind_of?(Integer)
|
|
return true if value == 1
|
|
return false if value == 0
|
|
elsif value.respond_to?(:to_s)
|
|
return true if %w[ true 1 t ].include?(value.to_s.downcase)
|
|
return false if %w[ false 0 f ].include?(value.to_s.downcase)
|
|
end
|
|
value
|
|
end
|
|
|
|
# Typecast a value to a BigDecimal
|
|
def typecast_to_bigdecimal(value)
|
|
if value.kind_of?(Integer)
|
|
value.to_s.to_d
|
|
else
|
|
typecast_to_numeric(value, :to_d)
|
|
end
|
|
end
|
|
|
|
# Typecast a value to a Float
|
|
def typecast_to_float(value)
|
|
typecast_to_numeric(value, :to_f)
|
|
end
|
|
|
|
# Match numeric string
|
|
def typecast_to_numeric(value, method)
|
|
if value.respond_to?(:to_str)
|
|
if value.to_str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/
|
|
$1.send(method)
|
|
else
|
|
value
|
|
end
|
|
elsif value.respond_to?(method)
|
|
value.send(method)
|
|
else
|
|
value
|
|
end
|
|
end
|
|
|
|
# Typecasts an arbitrary value to a DateTime.
|
|
# Handles both Hashes and DateTime instances.
|
|
# This is slow!! Use Time instead.
|
|
def typecast_to_datetime(value)
|
|
if value.is_a?(Hash)
|
|
typecast_hash_to_datetime(value)
|
|
else
|
|
DateTime.parse(value.to_s)
|
|
end
|
|
rescue ArgumentError
|
|
value
|
|
end
|
|
|
|
# Typecasts an arbitrary value to a Date
|
|
# Handles both Hashes and Date instances.
|
|
def typecast_to_date(value)
|
|
if value.is_a?(Hash)
|
|
typecast_hash_to_date(value)
|
|
elsif value.is_a?(Time) # sometimes people think date is time!
|
|
value.to_date
|
|
elsif value.to_s =~ /(\d{4})[\-|\/](\d{2})[\-|\/](\d{2})/
|
|
# Faster than parsing the date
|
|
Date.new($1.to_i, $2.to_i, $3.to_i)
|
|
else
|
|
Date.parse(value)
|
|
end
|
|
rescue ArgumentError
|
|
value
|
|
end
|
|
|
|
# Typecasts an arbitrary value to a Time
|
|
# Handles both Hashes and Time instances.
|
|
def typecast_to_time(value)
|
|
if value.is_a?(Hash)
|
|
typecast_hash_to_time(value)
|
|
else
|
|
Time.mktime_with_offset(value.to_s)
|
|
end
|
|
rescue ArgumentError
|
|
value
|
|
rescue TypeError
|
|
value
|
|
end
|
|
|
|
# Creates a DateTime instance from a Hash with keys :year, :month, :day,
|
|
# :hour, :min, :sec
|
|
def typecast_hash_to_datetime(value)
|
|
DateTime.new(*extract_time(value))
|
|
end
|
|
|
|
# Creates a Date instance from a Hash with keys :year, :month, :day
|
|
def typecast_hash_to_date(value)
|
|
Date.new(*extract_time(value)[0, 3])
|
|
end
|
|
|
|
# Creates a Time instance from a Hash with keys :year, :month, :day,
|
|
# :hour, :min, :sec
|
|
def typecast_hash_to_time(value)
|
|
Time.local(*extract_time(value))
|
|
end
|
|
|
|
# Extracts the given args from the hash. If a value does not exist, it
|
|
# uses the value of Time.now.
|
|
def extract_time(value)
|
|
now = Time.now
|
|
[:year, :month, :day, :hour, :min, :sec].map do |segment|
|
|
typecast_to_numeric(value.fetch(segment, now.send(segment)), :to_i)
|
|
end
|
|
end
|
|
|
|
# Typecast a value to a Class
|
|
def typecast_to_class(value)
|
|
value.to_s.constantize
|
|
rescue NameError
|
|
value
|
|
end
|
|
|
|
end
|
|
end
|
|
end
|
|
|