TypeCast
Type casting of attributes defined in superclass or realized through method_missing.
Converts string attributes with parser object (object that respond_to? :parse)
or attribute of any type with type-casting method (e.g. :to_i, :to_f).
Installation
Add this line to your application's Gemfile:
gem 'typecast'
And then execute:
$ bundle
Or install it yourself as:
$ gem install typecast
Usage
class User
def orders_count
"4"
end
def aov
"207.56"
end
def created_at
"2014-05-26T19:31:04+03:00"
end
def updated_at
"2014-05-26 19:49:59 +0300"
end
def expires_at
"26 September 2014 at 19:50:38 EEST"
end
def suggestions_count
nil
end
def method_missing(method_name, *args, &block)
return super unless "dynamic_created_at" == method_name.to_s
"2014-05-27T13:19:25+03:00"
end
end
class Customer < User
include TypeCast
type_cast :expires_at, DateTime # performs type casting of ancestor's instance method with object which respond_to? parse method
type_cast :created_at, :updated_at, Time # several attributes provided at once
type_cast :dynamic_created_at, Time # attribute that works through method_missing
type_cast :orders_count, :suggestions_count, :to_i
type_cast :aov, :to_f
end
customer = Customer.new
customer.expires_at # => DateTime.parse("26 September 2014 at 19:50:38 EEST")
customer.created_at # => Time.parse("2014-05-26T19:31:04+03:00")
customer.updated_at # => Time.parse("2014-05-26 19:49:59 +0300")
customer.dynamic_created_at # => Time.parse("2014-05-27T13:19:25+03:00")
customer.orders_count # => 4
customer.suggestions_count # => 0
customer.aov # => 207.56
customer.created_at_before_type_cast # => "2014-05-26T19:31:04+03:00"
customer.orders_count_before_type_cast # => "4"
History :)
Gem was originally created to use with ActiveRecourse, because next stuff don't work
class User < ActiveResource::Base
attribute 'created_at', :time # doesn't work
attribute 'created_at', :datetime # doesn't work
# doesn't work
schema do
datetime :created_at
end
# doesn't work
schema do
time :created_at
end
end
Next solution works but has some issue
# It check all atributes and parses to DateTime all that matches datetime regexp.
ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
ActiveSupport.parse_json_times = true
But ruby's DateTime.strftime method has minor bug: DateTime.strftime('%Z')
output is incorrect format
Time.now.strftime('%Z') # => "EEST"
DateTime.now.strftime('%Z') # => "+03:00"
You can monkey patch ActiveSupport
to use Time.parse
insted of DateTime.parse
to avoid this issue, but it still be slower
module ActiveSupport
module JSON
class << self
private
def convert_dates_from(data)
case data
when nil
nil
when DATE_REGEX
begin
Time.parse(data)
rescue ArgumentError
data
end
when Array
data.map! { |d| convert_dates_from(d) }
when Hash
data.each do |key, value|
data[key] = convert_dates_from(value)
end
else
data
end
end
end
end
end
Among cons of the proposed solution is that you'll need add type casting to all models.
Or perhaps type_cast
common attributes in ActiveResource::Base
class ActiveResource::Base
include TypeCast
type_cast :created_at, :updated_at, Time
end
Contributing
- Fork it ( http://github.com/shhavel/typecast/fork )
- Create your feature branch (
git checkout -b my-new-feature
) - Commit your changes (
git commit -am 'Add some feature'
) - Push to the branch (
git push origin my-new-feature
) - Create new Pull Request