Skip to content

Instantly share code, notes, and snippets.

@kirel
Created February 4, 2013 14:16
Show Gist options
  • Select an option

  • Save kirel/4706936 to your computer and use it in GitHub Desktop.

Select an option

Save kirel/4706936 to your computer and use it in GitHub Desktop.
module AttributeCasts
extend ActiveSupport::Concern
module ClassMethods
# casts method => type
# type needs to correspond to a TypeCast class that responds to call
def casts casts = {}
casts.each do |meth, cast|
caster = const_get "#{cast}_cast".camelize
define_method "#{meth}_with_cast" do
caster.new.call send("#{meth}_without_cast")
end
alias_method_chain "#{meth}", :cast
end
end
end
class BooleanCast
def call val
case val
when nil, false, 0, "0", "", "false"
false
else
true
end
end
end
class ArrayCast
def call val
case val
when Hash
val.values
else
Array.wrap(val)
end
end
end
end
module AttributeDefaults
extend ActiveSupport::Concern
module ClassMethods
# sets default values for accessors
# defaults are returned whenever an accessor would return nil
# defaults method => default_value
def defaults defaults = {}
defaults.each do |meth, default|
default_proc = default.respond_to?(:to_proc) ? default.to_proc : proc { default }
define_method "#{meth}_default" do
default_proc.call
end
define_method "#{meth}_with_default" do
res = send("#{meth}_without_default")
!res.nil? ? res : send("#{meth}_default")
end
alias_method_chain meth, :default
end
end
end
end
@kirel

kirel commented Feb 4, 2013

Copy link
Copy Markdown
Author

Api enhancements:

casts attribute: :method # cast by calling method on attribute
casts number: :to_i # example
casts attribute: Caster # cast by calling Caster.new
casts admin: Boolean # Boolean should be defined in namespace AttributeCasts
casts attribute: lambda { ... } # casts by calling call
casts attribute: { setter: ... } # casts on setting the attribute / default casts on getting

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment