module Eco module Data module Hashes class DiffResult extend Eco::Language::Models::ClassHelpers include Eco::Data::Hashes::DiffMeta inheritable_class_vars :key, :compared_attrs, :case_sensitive attr_reader :src1, :src2 def initialize(src1, src2) @src1 = src1 @src2 = src2 end def key self.class.key end def case_sensitive? self.class.case_sensitive? end def dup(src1: nil, src2: nil) src1 ||= self.src1 src2 ||= self.src2 self.class.new(src1.dup, src2.dup) end def new? !src1 && !!src2 end def del? !!src1 && !src2 end def update? !new? && !del? && diff? end # @note `diff_attrs` may not include the `key` attribute # This is always included via `new?` (new key value) and `del?` (missing key value) # @return [Boolean] was there any change? def diff? new? || del? || !diff_attrs.empty? end # Is the `key` attr value changing? def key? !(new? || del?) && diff_attr?(key) end # Is `attr` part of the attributes that change? def diff_attr?(attr) return true if new? return true if del? diff_attrs.include?(attr.to_s) end # @return [Value] the current value of `attr` (in `src2`) def attr(attr) return nil unless src2 src2[attr.to_s] end # @return [Value] the previous value of `attr` (in `src1`) def attr_prev(attr) return nil unless src1 src1[attr.to_s] end # @note the `key` attribute will always be added (even if there's no change) # @return [Hash] hash with the differences as per `src2` def diff_hash target_attrs = [key] | compared_attrs return src2.slice(*target_attrs) if new? return src1.slice(key) if del? src2.slice(key, *diff_attrs) end # @return [Array] hash with the differences as per `src2` def diff_attrs @diff_attrs ||= comparable_attrs.each_with_object([]) do |attr, out| out << attr unless eq?(src1[attr], src2[attr]) end end # @return [Boolean] whether `val1` is equal to `val2` def eq?(val1, val2) return true if val1 == val2 return false if case_sensitive? return false if !val2 || !val1 val1.upcase == val2.upcase end # @note when is `new?` or to be deleted (`del?`), it returns empty array. # @return [Array] the set of attributes that are comparable in this instance. def comparable_attrs return [] if new? || del? compared_attrs end # @return [Array] the set of attributes that are comparable in this class. def compared_attrs comp_attrs = self.class.compared_attrs.map(&:to_s).uniq return comp_attrs unless comp_attrs.empty? (src1&.keys || []) & (src2&.keys || []) end end end end end