module Multitype::ClassMethods
Public Instance Methods
__get_multitype_cache__(type = nil, cat = nil, klass = self.name.to_sym, depth = 0)
click to toggle source
# File lib/multitype.rb, line 162 def __get_multitype_cache__(type = nil, cat = nil, klass = self.name.to_sym, depth = 0) type = type.to_sym if type cat = cat.to_sym if cat # If the klass is not cached just return nil return nil unless __multitype_cache__[klass] # Return the level of data requested result = if type.nil? && cat.nil? __multitype_cache__[klass] elsif cat.nil? && __multitype_cache__[klass] __multitype_cache__[klass][type] elsif __multitype_cache__[klass] && __multitype_cache__[klass][type] __multitype_cache__[klass][type][cat] else nil end # Don't loop through ancestors on lower objects return result if depth > 0 # Iterate over ancestors to use their typesets ancestors.inject(result) do |out, ancestor| ancestor = ancestor.name.to_sym # Skip if ancestor is self or Multitype if ancestor == klass || ancestor == 'Multitype' out else # Get data lower down the ancestry tree merge_in = __get_multitype_cache__(type, cat, ancestor, depth + 1) # Merge in data as required if out.nil? && ! merge_in.nil? merge_in else if merge_in.is_a?(Array) out.concat(merge_in) elsif merge_in.is_a?(Hash) out.merge(merge_in) else out end end end end end
deftype(type, name, args = {}, &block)
click to toggle source
# File lib/multitype.rb, line 75 def deftype(type, name, args = {}, &block) __create_multitype_datastore__ type = type.to_sym name = name.to_sym # Merge in name, type and model for accessable access args.merge!(type: type, name: name, model: self) # Get the list of accessable keys we need accessable = args.keys.map(&:to_sym) # Kickstart the type comparators type_comparator(type) # Get the name of the class to extend if it exists type_class = if args[:class] klass = if args[:class].is_a?(String) get_const(args[:class]) else args[:class] end klass.is_a?(Object) ? klass : Object else Object end # Define the class and mark as a typeset object = Class.new(type_class) object.class_attribute :__multitype_typeset__ object.__multitype_typeset__ = true # Execute the passed block as if it was class level code object.class_exec(&block) if block_given? # Instantiate the object object = object.new # Make the variables passed accessable type_accessor(object, *accessable) # Set the instance attributes that were passed in args.each { |key, val| object.__send__("#{key}=", val) } # Add the type to the multitype cache __update_multitype_cache__(type, :typesets, {name => object}) # Create the accessor method if it does not exist unless self.respond_to?(type) self.__send__(:define_method, type) do use_typeset = nil # Object to return # Loop through the types to find the one to use __get_multitype_cache__(type, :typesets).each do |name, typeset| match = true # Did we find a match # Loop through the type comparators to find a match __get_multitype_cache__(type, :comparators).each do |model_comparator, typeset_comparator| # Check the comparator for a match match = if typeset.respond_to?(typeset_comparator) && self.respond_to?(model_comparator) typeset.__send__(typeset_comparator) == self.__send__(model_comparator) else false end # If we fail at least one # match then break the loop break unless match end # If we have a match, # stop looking for one if match use_typeset = typeset break end end # Return the typeset use_typeset end end object end
type_accessor(type, *columns)
click to toggle source
# File lib/multitype.rb, line 60 def type_accessor(type, *columns) __create_multitype_datastore__ # Add accessors to the typeset that is passed or any typesets matching type if type.is_a?(Object) && type.respond_to?(:__multitype_typeset__) type.class.__send__(:attr_accessor, *columns) else raise NoTypeError, type.to_s unless __get_multitype_cache__(type) raise NoTypeSetError, type.to_s unless __get_multitype_cache__(type, :typesets) __get_multitype_cache__(type, :typesets).each do |name, typeset| typeset.class.attr_accessor(*columns) end end end
type_alias(type, *aliases)
click to toggle source
# File lib/multitype.rb, line 48 def type_alias(type, *aliases) __create_multitype_datastore__ # Get the type name if a typeset is passed as an object type = type.type if type.is_a?(Object) && type.respond_to?(:__multitype_typeset__) raise NoTypeError, type.to_s unless __get_multitype_cache__(type) aliases.each do |_alias| alias_method _alias, type end end
type_comparator(type, *comparators)
click to toggle source
# File lib/multitype.rb, line 29 def type_comparator(type, *comparators) new_comparators = comparators.inject({}) do |out, comparator| if comparator.is_a?(Hash) out.merge(comparator) else out.merge({comparator => comparator}) end end __send__(:attr_accessor, *new_comparators.keys) __create_multitype_datastore__ # Get the type name if a typeset is passed as an object type = type.type if type.is_a?(Object) && type.respond_to?(:__multitype_typeset__) # Append to the list comparator columns __update_multitype_cache__(type, :comparators, new_comparators) end
Private Instance Methods
__create_multitype_datastore__()
click to toggle source
# File lib/multitype.rb, line 238 def __create_multitype_datastore__ if ! self.respond_to?(:__multitype_cache__) class_attribute :__multitype_cache__ self.__send__(:__multitype_cache__=, {}) true else false end end
__update_multitype_cache__(type, cat, data)
click to toggle source
# File lib/multitype.rb, line 213 def __update_multitype_cache__(type, cat, data) klass = self.name.to_sym type = type.to_sym cat = cat.to_sym # Create the hashes if they don't exist __multitype_cache__[klass] ||= {} __multitype_cache__[klass][type] ||= {} __multitype_cache__[klass][type][cat] ||= data # Merge in the data for hashes if data.is_a?(Hash) data = __multitype_cache__[klass][type][cat].merge(data) __multitype_cache__[klass][type][cat] = data end # Concatanate the data for arrays if data.is_a?(Array) data = __multitype_cache__[klass][type][cat].concat(data).uniq __multitype_cache__[klass][type][cat] = data end __multitype_cache__[klass] end