Skip to content

Instantly share code, notes, and snippets.

@davybrion
Created September 15, 2012 14:59
Show Gist options
  • Save davybrion/3728369 to your computer and use it in GitHub Desktop.
Save davybrion/3728369 to your computer and use it in GitHub Desktop.
code snippets for "Writing A Simple DSL" post
require 'forwardable'
class Model
extend Forwardable
def initialize
@entities = []
end
def add_entity(entity)
@entities << entity
end
def entity_for(name)
@entities.detect { |entity| entity.name == name }
end
def_delegator :@entities, :each, :each_entity
end
class Entity
extend Forwardable
attr_reader :name
def initialize(name)
@name = name
@collections = []
@properties = []
@references = []
end
def add_collection(collection)
@collections << collection
end
def add_property(property)
@properties << property
end
def add_reference(reference)
@references << reference
end
def identifier
@properties.detect { |property| property.is_identifier? }
end
def_delegator :@collections, :each, :each_collection
def_delegator :@properties, :each, :each_property
def_delegator :@references, :each, :each_reference
end
class Property
attr_reader :name
attr_reader :required
attr_reader :type
def self.new_identifier(name, type)
self.new(name, type, false, true)
end
def initialize(name, type, required=false, is_identifier=false)
@name = name
@type = type
@required = required
@is_identifier = is_identifier
end
def is_identifier?
@is_identifier
end
end
class Reference
attr_reader :name
attr_reader :entity
attr_reader :is_required
def initialize(name, entity, is_required)
@name = name
@entity = entity
@is_required = is_required
end
end
class Reference
attr_reader :name
attr_reader :entity
attr_reader :is_required
def initialize(name, entity, is_required)
@name = name
@entity = entity
@is_required = is_required
end
end
class Collection
attr_reader :name
attr_reader :entity
def initialize(name, entity)
@name = name
@entity = entity
end
end
entity "Invoice"
identified_by "Id", :guid
must_reference "Customer"
must_have "Date", :date
can_have "Discount", :double
contains "Lines", "InvoiceLine"
require_relative 'application.rb'
require_relative 'entity.rb'
require_relative 'collection.rb'
require_relative 'property.rb'
require_relative 'reference.rb'
@model = Model.new
def entity(name)
entity = Entity.new(name)
@model.add_entity entity
@current_entity = entity
end
def identified_by(name, type)
@current_entity.add_property Property.new_identifier(name, type)
end
def must_have(name, type)
has name, type, true
end
def can_have(name, type)
has name, type, false
end
def must_reference(entity_name, name=nil)
references entity_name, true, name
end
def can_reference(entity_name, name=nil)
references entity_name, false, name
end
def contains(name, entity_name)
referred_entity = @model.entity_for entity_name
@current_entity.add_collection Collection.new(name, referred_entity)
end
def has(name, type, required=false)
@current_entity.add_property Property.new(name, type, required)
end
def references(entity_name, is_required=false, name=nil)
referred_entity = @model.entity_for entity_name
name = entity_name if name.nil?
@current_entity.add_reference Reference.new(name, entity_name, is_required)
end
Dir.glob('*_def.rb').each do |file|
@current_entity = nil
load file
end
@model.each_entity do |entity|
puts entity.name
print_name = Proc.new { |item| puts "\t\t#{item.name}"}
puts "\t has the following properties:"
entity.each_property &print_name
puts "\t has the following references:"
entity.each_reference &print_name
puts "\t has the following collections:"
entity.each_collection &print_name
end
Dir.glob('*_def.rb').each do |file|
@current_entity = nil
load file
end
entity "Customer"
identified_by "Id", :guid
must_have "Name", :string
can_have "Email", :string
entity "Product"
identified_by "Id", :guid
must_have "Name", :string
must_have "Price", :integer
entity "InvoiceLine"
identified_by "Id", :guid
must_reference "Product"
must_have "Count", :integer
entity "Invoice"
identified_by "Id", :guid
must_reference "Customer"
must_have "Date", :date
can_have "Discount", :double
contains "Lines", "InvoiceLine"
@model.each_entity do |entity|
puts entity.name
print_name = Proc.new { |item| puts "\t\t#{item.name}"}
puts "\t has the following properties:"
entity.each_property &print_name
puts "\t has the following references:"
entity.each_reference &print_name
puts "\t has the following collections:"
entity.each_collection &print_name
end
Customer
has the following properties:
Id
Name
Email
has the following references:
has the following collections:
Invoice
has the following properties:
Id
Date
Discount
has the following references:
Customer
has the following collections:
Lines
InvoiceLine
has the following properties:
Id
Count
has the following references:
Product
has the following collections:
Product
has the following properties:
Id
Name
Price
has the following references:
has the following collections:
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment