Skip to content

Instantly share code, notes, and snippets.

@brianknapp
Last active December 15, 2015 07:09
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brianknapp/5221420 to your computer and use it in GitHub Desktop.
Save brianknapp/5221420 to your computer and use it in GitHub Desktop.
Obvious immutable entity with validation
module Obvious
module EntityMixin
class << self
def included(base)
base.extend ClassMethods
end
end
module ClassMethods
attr_reader :shape
attr_reader :validations
def value name, type
name = name.to_sym
@shape ||= {}
@shape[name] = type
define_method(name) { @values[name] }
end
def validation name, method
name = "#{name}_validation".to_sym
@validations ||= []
@validations << name
define_method(name) { instance_exec &method }
end
end
end
class Entity
include EntityMixin
def initialize input
shape = self.class.shape
validations = self.class.validations || []
@values = {}
input.each do |k, v|
unless shape[k]
raise StandardError.new "Invalid input field: #{k}"
else
@values[k] = v
end
end
freeze
shape.each do |k, v|
unless @values[k].class == v
msg = "Validation Error: Invalid value for #{k}, should be a #{v}"
raise StandardError.new msg
end
end
validations.each { |method| send method }
end
def to_hash
hash = {}
@values.each do |k, v|
hash[k] = v
end
hash
end
end
end
class Thing < Obvious::Entity
value :foo, String
value :test, Fixnum
validation :something, Proc.new {
if foo != "hello world"
msg = "Validation Error: Invalid value for foo, should be 'hello world'"
raise StandardError.new msg
end
}
end
class Thing2 < Obvious::Entity
value :something, String
value :else, TrueClass
end
describe Thing do
it 'should be a thing' do
thing = Thing.new foo: 'hello world', test: 1
puts thing.inspect
puts Thing.shape
puts thing.foo
puts thing.test
puts thing.to_hash
thing2 = Thing2.new something: 'funny', else: true
puts thing2.inspect
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment