# encoding: utf-8 module Axiom module Algebra class Rename # Aliases that map old attributes to new renamed attributes class Aliases extend Aliasable include Enumerable include Equalizer.new(:to_hash) inheritable_alias(:| => :union) # Instantiate new set of Aliases # # @example # aliases = Aliases.new(aliases) # # @param [Hash{Attribute => Attribute}] aliases # # @return [Aliases] # # @api public def self.new(aliases) assert_unique_aliases(aliases) super end # Asset the aliases are unique # # @param [Hash{Attribute => Attribute}] aliases # # @return [undefined] # # @raise [DuplicateAliasError] # raised when the aliases are duplicates # # @api private def self.assert_unique_aliases(aliases) if aliases.values.uniq! fail DuplicateAliasError, 'the aliases must be unique' end end private_class_method :assert_unique_aliases # Initialize rename aliases # # @param [Hash] aliases # the old and new attributes # # @return [undefined] # # @api public def initialize(aliases) @aliases = self.class.freezer.call(aliases) end # Lookup the new attribute given the old attribute # # @example # new_attribute = aliases[old_attribute] # # @param [Attribute] attribute # the old attribute # # @return [Attribute] # # @api public def [](attribute) @aliases.fetch(attribute, attribute) end # Union the aliases with another set of aliases # # @example # new_aliases = aliases.union(other) # # @param [Aliases] other # the aliases to union with # # @return [Aliases] # # @api public def union(other) other_aliases = other.to_hash.dup inverted = other_aliases.invert # Remove aliases that cancel out, and preserve different aliases each do |old_attribute, new_attribute| old_attribute = inverted.fetch(old_attribute, old_attribute) other_aliases.delete(old_attribute) unless old_attribute.eql?(new_attribute) other_aliases[old_attribute] = new_attribute end end self.class.new(other_aliases) end # Iterate over each old and new attribute # # @example # aliases = Aliases.new(old => new) # aliases.each { |old, new| ... } # # @yield [old, new] # # @yieldparam [Attribute] old_attribute # the old attribute # @yieldparam [Attribute] new_attribute # the new attribute # # @return [self] # # @api public def each return to_enum unless block_given? @aliases.each { |old_attribute, new_attribute| yield old_attribute, new_attribute } self end # Test if there are no aliases # # @example # aliases.empty? # => true or false # # @return [Boolean] # # @api public def empty? @aliases.empty? end # Return the inverse aliases # # @example # inverse = aliases.inverse # # @return [Aliases] # # @api public def inverse self.class.new(@aliases.invert) .memoize(inverse: self) end # Compare the aliases with other aliases for equivalency # # @example # aliases == other # => true or false # # @param [Aliases] other # the other aliases to compare with # # @return [Boolean] # # @api public def ==(other) cmp?(__method__, other) end # Convert the aliases to a Hash # # @example # hash = aliases.to_hash # # @return [Hash] # # @api public def to_hash @aliases end # Coerce a Hash of old and new attributes into Aliases # # @param [Header] attributes # the header containing the old attributes # @param [Aliases, #map] aliases # the aliases to coerce # # @return [Aliases] # # @api private def self.coerce(attributes, aliases) return aliases if aliases.kind_of?(Aliases) header = Relation::Header.coerce(attributes) renames = aliases.map do |old_attr, new_attr| coerce_alias_pair(header, old_attr, new_attr) end new(Hash[renames]) end # Coerce old and new attributes into Attribute objects # # @param [Header] attributes # the header containing the old attributes # @param [Symbol, Attribute] old_attr # the old attribute name or Attribute object # @param [Symbol, Attribute] new_attr # the new attribute name or Attribute object # # @return [Array(Attribute, Attribute)] # # @api private def self.coerce_alias_pair(attributes, old_attr, new_attr) old_attr = attributes[old_attr] new_attr = old_attr.rename(new_attr) if new_attr.kind_of?(Symbol) [old_attr, new_attr] end private_class_method :coerce_alias_pair memoize :inverse end # class Aliases end # class Rename end # module Algebra end # module Axiom