Skip to content

Instantly share code, notes, and snippets.

@plukevdh
Last active August 29, 2015 14:01
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 plukevdh/50d66dd8ad6f3c445562 to your computer and use it in GitHub Desktop.
Save plukevdh/50d66dd8ad6f3c445562 to your computer and use it in GitHub Desktop.
entity parser for a schama dsl
require 'schemad/extensions'
require 'schemad/type_handler'
module Schemad
class Entity
extend Schemad::Extensions
def self.inherited(subclass)
subclass.instance_variable_set(:@attributes, [])
end
def self.attribute(name, args, &block)
attr_accessor name
define_parser_for(name, args, &block)
@attributes << name
end
def self.from_data(data)
obj = new
indiff = indifferent_hash(data)
@attributes.each do |key|
value = obj.send "parse_#{key}", indiff
obj.send "#{key}=", value
end
obj
end
def attributes
self.class.instance_variable_get(:@attributes)
end
private
def self.define_parser_for(name, args, &block)
lookup = args[:key] || name
define_method "parse_#{name}" do |data|
value = data[lookup]
value ||= get_default(args[:default])
value = block.call(value) if block_given? && !value.nil?
self.send "#{name}=", coerce_to_type(value, args[:type])
end
# not sure I like this at all...
define_method "#{name}?" do
!!send(name)
end if args[:type] == :boolean
end
def get_default(default_provider)
return default_provider unless default_provider.is_a? Proc
default_provider.call
end
def coerce_to_type(value, type)
handler = TypeHandler.new type
handler.parse(value)
end
end
end
require 'spec_helper'
require 'schemad/entity'
data = {
"Middle Earth" => "coordinates",
cool: true,
roads: 5,
"beasts" => "1337",
}
class Ent < Schemad::Entity
attribute :forest, type: :string, default: "Green"
attribute :roads, type: :integer do |value|
value * 10
end
attribute :beasts, type: :integer
attribute :world, type: :string, key: "Middle Earth" do |value|
value.upcase
end
attribute :cool, type: :boolean
attribute :created, type: :date_time, default: -> { Time.now }
end
describe Schemad::Entity do
context "#from_data" do
Given(:ent) { Ent.from_data(data) }
Then { ent.attributes.should == [:forest, :roads, :beasts, :world, :cool, :created]}
context "defaults or nil get used when no data" do
Then { ent.forest.should == "Green" }
And { ent.cool.should be_true }
And { ent.created.to_i.should eq(Time.now.to_i) }
end
context "converters modify data" do
Then { ent.roads.should == 50 }
end
context "can alias lookup key" do
Then { ent.world.should == "COORDINATES" }
end
context "parses types" do
Then { ent.beasts.should == 1337 }
end
context "defines #? method for bools" do
Then { ent.should_not be_cool }
end
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment