Skip to content

Instantly share code, notes, and snippets.

@weapp
Last active September 27, 2018 07:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save weapp/7588a36b12412284770adeb20d63c077 to your computer and use it in GitHub Desktop.
Save weapp/7588a36b12412284770adeb20d63c077 to your computer and use it in GitHub Desktop.
class Field
attr_accessor :name, :type, :default
def initialize(name, type, default)
@name = name.to_s
@type = type
@default = default
end
TYPECASTS = {
string: ->(val) { val.to_s },
symbol: ->(val) { val.to_sym },
bool: ->(val) { !(!val || ["false", "0", 0].include?(val) ) },
integer: ->(val) { val.to_i },
float: ->(val) { val.to_f },
bigdecimal: ->(val) { val },
datetime: ->(val) { val },
time: ->(val) { val },
date: ->(val) { val },
any: ->(val) { val },
}
def cast(value)
typecast = TYPECASTS.fetch(type, type)
typecast.respond_to?(:typecast) ? typecast.method(:typecast) : typecast
typecast.call(value)
end
end
class SerializableModel
attr_accessor :attributes
class << self
def fields
@fields ||= {}
end
def field(field_name, type=:string, default: nil, read_only: false)
field_name = field_name.to_s
fields[field_name] = Field.new(field_name, type, default)
define_method field_name do
attributes[field_name]
end
unless read_only
define_method "#{field_name}=" do |val|
attributes[field_name] = val
end
end
end
def model_name
@model_name ||= name.downcase
end
def model_name=(name)
@model_name = name
end
def symbolize_keys(hash)
Hash[hash.map { |k, v| [k.to_sym, v] }]
end
def desymbolize_keys(hash)
Hash[hash.map { |k, v| [k.to_s, v] }]
end
end
def initialize(attrs)
self.attributes = self.class.desymbolize_keys(attrs)
end
def attributes=(raw)
@attributes = {}
self.class.fields.each do |key, field|
# @attributes[key] = raw.has?(key) ? field.cast(raw[key]) : field.default_value
@attributes[key] = field.cast(raw.fetch(key, field.default))
# raw.slice(*self.class.fields.keys)
end
end
def eql?(other)
self.class.equal?(other.class) && other.attributes == attributes
end
def as_json(**opts)
base = @attributes.dup
base.merge!(Hash[opts[:methods].map {|k| [k, send(k)]}]) if opts[:methods]
base
end
def to_json(**opts)
as_json(**opts).to_json
end
end
class Model < SerializableModel
field :name, :string
field :show_in_menu, :bool
field :icon, :string
field :primary_key_name, :string, default: "id"
field :fields, :any
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment