-
-
Save mbbx6spp/1083536 to your computer and use it in GitHub Desktop.
Class-Table Inheritance Meta-model for DataMapper
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Module with mixins for common queries across descendants: | |
module Descendant | |
# I guess I could use ActiveSupport::Concern here... | |
def self.included(receiver) | |
receiver.extend ClassMethods | |
receiver.send :include, InstanceMethods | |
end | |
module ClassMethods | |
def self.included(receiver) | |
ut = receiver.to_s.underscore.to_sym # since you already depend on AS for #to_sym | |
# const_set is asking for trouble later on...need to rethink this | |
Unit::TYPES << receiver.const_set(:UNIT_TYPE, ut) | |
end | |
def named(name) | |
first(:unit => Unit.first(:name => name)) | |
end | |
end | |
module InstanceMethods | |
def unit_type | |
begin | |
self.class.const_get(:UNIT_TYPE) | |
rescue NameError => e | |
raise 'Unit subtypes must include Descendant module' | |
end | |
end | |
end | |
end | |
# Units: | |
class Unit | |
include DataMapper::Resource | |
# Added to when included by a descendant of unit... | |
TYPES = [] | |
property :id, Integer, :serial => true | |
property :name, String | |
has n, :stats # not modeled here, just a one-to-many association | |
def type(*args) | |
options = args.extract_options! | |
types = normalize(args.shift) | |
# Ensure all descendant types are in TYPES | |
invalid_type unless (types - TYPES).empty? | |
# Prepare descendant type query | |
args.unshift(:all) | |
types.collect do |type| | |
type.class.to_s.camelize.send(args) | |
end.flatten | |
end | |
private | |
def normalize(specifier) | |
case | |
when specifier === :all | |
TYPES.dup | |
when specifier.respond_to?(:to_sym) | |
[specifier.to_sym] | |
when specifier.respond_to?(:to_ary) | |
specifier.to_ary | |
else | |
invalid_type | |
end | |
end | |
def invalid_type | |
raise ArgumentError.new('specifier values must be :all, or exist in Unit::TYPES') | |
end | |
end | |
class Champion | |
include DataMapper::Resource | |
include Descendant | |
property :unit_id, Integer | |
delegate :name, :name=, :to => :unit | |
end | |
class Structure | |
include DataMapper::Resource | |
include Descendant | |
property :unit_id, Integer | |
delegate :name, :name=, :to => :unit | |
end | |
# Usage: | |
@champions_and_structures = Unit.type([:champion,:structure]) # all champions and structures | |
@champions = Unit.type(:champion) | |
@specific_champion = Champion.named('Shen') | |
@turret = Structure.named('Turret') | |
# Might work? | |
@champions_stats = Unit.type(:champion).collect(&:stats) | |
# I can't think of a good use case, but arguments passed into type will be forwarded | |
# to *each* Descendant class as #all options. Any further ordering, filtering, or whatever | |
# of the results will have to be done programmatically. | |
@contrived = Unit.type(:all, :conditions => []) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment