module Scrivito class ObjData MissingAttribute = Class.new internal_key_list = %w[ last_changed modification permalink text_links conflicts ] INTERNAL_KEYS = Set.new(internal_key_list.map { |name| "_#{name}" } ) internal_comparison_key_list = %w[ path permalink widget_pool ] INTERNAL_COMPARISON_KEYS = Set.new(internal_comparison_key_list.map { |name| "_#{name}" }) SPECIAL_KEYS = Set.new(%w[ body title blob ]) ATTRIBUTE_DEFAULT_VALUES = { "string" => "", "text" => "", "html" => "", "multienum" => [], "linklist" => [], "referencelist" => [], "widget" => [], "enum" => nil, "binary" => nil, "date" => nil, "reference" => nil, "link" => nil, }.freeze def value_of(attribute_name) value_and_type_of(attribute_name).first end def type_of(attribute_name) value_and_type_of(attribute_name).second end def unchecked_value_of(attribute_name) unchecked_value_and_type_of(attribute_name).first end def value_and_type_of(attribute_name) value_and_type = internal_value_and_type_of(attribute_name) if value_and_type.first.is_a?(MissingAttribute) raise ScrivitoError.new("Illegal attribute name #{attribute_name}") else value_and_type end end def unchecked_value_and_type_of(attribute_name) value_and_type = internal_value_and_type_of(attribute_name) if value_and_type.first.is_a?(MissingAttribute) [nil, nil] else value_and_type end end def all_custom_attributes @all_custom_attributes ||= all_attributes.select do |attribute| has_custom_attribute?(attribute) end end def raw_value_and_type_of(attribute_name) raise NotImplementedError, "implement in subclass" end def has_custom_attribute?(name) raise NotImplementedError, "implement in subclass" end def all_attributes raise NotImplementedError, "implement in subclass" end def ==(other) if other.kind_of?(ObjData) (all_attributes | other.all_attributes).each do |attr| attr = attr.to_s next if attr.start_with?('_') && !INTERNAL_COMPARISON_KEYS.include?(attr) if unchecked_value_of(attr) != other.unchecked_value_of(attr) return false end end return true end false end private def internal_value_and_type_of(attribute_name) value_and_type = raw_value_and_type_of(attribute_name) if value_and_type.blank? if INTERNAL_KEYS.include?(attribute_name) || SPECIAL_KEYS.include?(attribute_name) type = type_of_internal(attribute_name) [default_attribute_value(attribute_name), type] else [ObjData::MissingAttribute.new, nil] end else value, type = value_and_type if value.nil? && has_custom_attribute?(attribute_name) value = ATTRIBUTE_DEFAULT_VALUES[type] end [value, type] end end def type_of_internal(key) case key when "_permalink" "string" when "_text_links" "linklist" when "_last_changed" "date" when "title", "body" "html" when "blob" "binary" else nil end end def default_attribute_value(attribute_name) case attribute_name when "_text_links" [] else nil end end end end