commit 66e78c7acebee5c95dc56e1cba5c159426581743
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Fri Sep 9 03:29:16 2011 +0200

    [evol] attributes parameters rework §1 (core code) (refs #142)

diff --git a/lib/ldap_shadows/elements.rb b/lib/ldap_shadows/elements.rb
index 6378c9d..5b142f5 100644
--- a/lib/ldap_shadows/elements.rb
+++ b/lib/ldap_shadows/elements.rb
@@ -46,9 +46,10 @@ module LdapShadows
         def ldap_virtual_attr(attr, syntax, single_value = false, binary = false)
           @virtual_attributes ||= {}
           @virtual_attributes[attr.to_s] = {
-             :syntax => syntax,
-             :single_value => single_value,
-             :binary => binary
+            :syntax        => syntax,
+            :single_value  => single_value,
+            :binary        => binary,
+            :operational   => false
           }
         end
 
@@ -57,10 +58,11 @@ module LdapShadows
           return if attr_info.nil?
 
           {
-             :syntax => attr_info.syntax.to_param,
-             :single_value => attr_info.single_value?,
-             :read_only => attr_info.read_only?,
-             :binary => attr_info.binary?
+            :syntax        => attr_info.syntax.to_param,
+            :single_value  => attr_info.single_value?,
+            :read_only     => attr_info.read_only?,
+            :binary        => attr_info.binary?,
+            :operational   => attr_info.directory_operation?
           }
         end
 
diff --git a/lib/ldap_shadows/elements/object.rb b/lib/ldap_shadows/elements/object.rb
index 0fbdec6..ca12866 100644
--- a/lib/ldap_shadows/elements/object.rb
+++ b/lib/ldap_shadows/elements/object.rb
@@ -144,7 +144,7 @@ module Elements
 
     def human_name
       attr_list = ['displayName', 'cn']
-      name_attribute = self.class.parameters[:presentation][:name_attribute]
+      name_attribute = self.class.parameters[:interface][:name_attribute]
       attr_list.unshift(name_attribute) unless name_attribute.nil?
       attr_list.each do |attr|
         if attr == 'dn'
@@ -159,7 +159,7 @@ module Elements
 
     def human_description
       attr_list = ['description']
-      desc_attribute = self.class.parameters[:presentation][:desc_attribute]
+      desc_attribute = self.class.parameters[:interface][:desc_attribute]
       attr_list.unshift(desc_attribute) unless desc_attribute.nil?
       attr_list.each do |attr|
         if self.attribute_present?(attr)
@@ -199,43 +199,36 @@ module Elements
     end
 
     def organized_data
-      # merge ignored and expert attributes for object and all present aspects
-      ignored_attrs = self.class.shadow.get_config[:presentation][:hidden_attributes]
-      ignored_attrs += self.class.parameters[:presentation][:hidden_attributes]
-      expert_attributes = self.class.parameters[:presentation][:expert_attributes]
-      self.aspects.values.each do |aspect|
-        aspect_data = aspect.parameters
-        ignored_attrs += aspect_data[:presentation][:hidden_attributes]
-        expert_attributes += aspect_data[:presentation][:expert_attributes]
-      end
-
-      attr_list = self.nonempty_attributes - ignored_attrs
-
-      admin_attributes = attr_list.select do |attr|
-        ActiveLdap::Base.schema.attribute(attr).directory_operation?
-      end
-
+      attr_list = self.nonempty_attributes
       rel_list = self.possible_relations
 
       # first pass to take aspects forced relations into account
       obj_aspects = {}
       self.aspects.values.each do |aspect|
-        aspect_data = aspect.parameters
+        aspect_mapping = aspect.parameters[:mapping]
 
-        unless aspect_data[:mapping][:associated_attributes].empty?
-          taken_attr_list = aspect_data[:mapping][:associated_attributes] & (attr_list + ignored_attrs)
+        unless aspect_mapping[:associated_attributes].empty?
+          taken_attr_list = aspect_mapping[:associated_attributes] & attr_list
           unless taken_attr_list.empty?
+            attrs_data = taken_attr_list.collect do |attr|
+              [attr, fetch_attribute_data(attr, aspect)]
+            end.compact
+
             obj_aspects[aspect.handle] ||= {}
-            obj_aspects[aspect.handle].merge!(fetch_attributes_data(taken_attr_list, expert_attributes, admin_attributes))
+            obj_aspects[aspect.handle].merge!(Hash[attrs_data])
             attr_list -= taken_attr_list
           end
         end
 
-        unless aspect_data[:mapping][:associated_relations].empty?
-          taken_rel_list = aspect_data[:mapping][:associated_relations] & rel_list
+        unless aspect_mapping[:associated_relations].empty?
+          taken_rel_list = aspect_mapping[:associated_relations] & rel_list
           unless taken_rel_list.empty?
+            rels_data = taken_rel_list.collect do |rel|
+              ["rel:" + rel, fetch_relation_data(rel, aspect)]
+            end.compact
+
             obj_aspects[aspect.handle] ||= {}
-            obj_aspects[aspect.handle].merge!(fetch_relations_data(taken_rel_list, expert_attributes))
+            obj_aspects[aspect.handle].merge!(Hash[rels_data])
             rel_list -= taken_rel_list
           end
         end
@@ -246,20 +239,26 @@ module Elements
       if self.class.parameters[:mapping][:associate_unclaimed_attributes]
         taken_attr_list = attr_list
       else
-        taken_attr_list = admin_attributes
-        taken_attr_list += self.class.parameters[:mapping][:associated_attributes]
+        taken_attr_list = self.class.parameters[:mapping][:associated_attributes]
         taken_attr_list += self.class.possible_attributes
       end
       taken_attr_list = taken_attr_list.uniq & attr_list
       taken_attr_list += self.class.virtual_attributes
-      obj_info = fetch_attributes_data(taken_attr_list, expert_attributes, admin_attributes)
+      attrs_data = taken_attr_list.collect do |attr|
+        [attr, fetch_attribute_data(attr, self)]
+      end.compact
+      obj_info = Hash[attrs_data]
       attr_list -= taken_attr_list
 
       # manage general relations
       if self.class.parameters[:mapping][:associated_relations]
         taken_rel_list = self.class.parameters[:mapping][:associated_relations] & rel_list
         unless taken_rel_list.empty?
-          obj_info.merge!(fetch_relations_data(taken_rel_list, expert_attributes))
+          rels_data = taken_rel_list.collect do |rel|
+            ["rel:" + rel, fetch_relation_data(rel, self)]
+          end.compact
+
+          obj_info.merge!(Hash[rels_data])
           rel_list -= taken_rel_list
         end
       end
@@ -269,14 +268,27 @@ module Elements
         self.aspects.values.each do |aspect|
           taken_attr_list = (aspect.possible_attributes & attr_list)
           taken_attr_list += aspect.virtual_attributes
+
+          attrs_data = taken_attr_list.collect do |attr|
+            [attr, fetch_attribute_data(attr, aspect)]
+          end.compact
+
           obj_aspects[aspect.handle] ||= {}
-          obj_aspects[aspect.handle].merge!(fetch_attributes_data(taken_attr_list, expert_attributes, admin_attributes))
+          obj_aspects[aspect.handle].merge!(Hash[attrs_data])
           attr_list -= taken_attr_list
 
           break if attr_list.empty?
         end
       end
 
+      # third pass to dispath the remaining attributes
+      unless attr_list.empty?
+        attrs_data = attr_list.collect do |attr|
+          [attr, fetch_attribute_data(attr, self)]
+        end.compact
+        obj_info.merge!(Hash[attrs_data])
+      end
+
       [obj_info, obj_aspects]
     end
 
@@ -697,60 +709,63 @@ module Elements
       end
     end
 
-    def fetch_attributes_data(attr_list, expert_attributes, admin_attributes)
-      attr_data = attr_list.collect do |attr|
-        base_info = self.attribute_info(attr)
+    def attribute_parameters(attr, claimed_by)
+      self.class.shadow.parameters[:interface][:attribute_defaults].dup.
+        recursive_merge(claimed_by.class.parameters[:interface][:attribute_defaults]).
+        recursive_merge(self.class.shadow.parameters[:interface][:attributes][attr.to_sym] || {}).
+        recursive_merge(claimed_by.class.parameters[:interface][:attributes][attr.to_sym] || {})
+    end
 
-        if base_info.nil?
-          nil
-        else
-          val = self.send(attr)
-          [attr, base_info.merge({
-             :value => val,
-             :multiple => val.is_a?(Array),
-             :expert => expert_attributes.include?(attr),
-             :admin => admin_attributes.include?(attr)
-           })]
-        end
-      end
-      Hash[attr_data.compact]
+    def fetch_attribute_data(attr, claimed_by)
+      base_info = self.attribute_info(attr)
+      return nil if base_info.nil?
+
+      attr_data = attribute_parameters(attr, claimed_by)
+
+      val = (attr == 'objectClass') ? self.classes : self.send(attr)
+      attr_data.merge!({
+                         :value        => val,
+                         :multiple     => val.is_a?(Array)
+                       })
+
+      attr_data
     end
 
-    def fetch_relations_data(rel_list, expert_attributes)
-      rel_data = rel_list.collect do |rel|
-        data = self.send(rel)
-        if data.is_a? Enumerable
-          if data.empty?
-            value = nil
-          else
-            value = data.collect{|g| g.handle }
-            multiple = true
-          end
+    def fetch_relation_data(rel, claimed_by)
+      data = self.send(rel)
+      if data.is_a? Enumerable
+        if data.empty?
+          value = nil
         else
-          # the exists? method also ensure the object is loaded
-          if data.exists?
-            value = data.handle
-          else
-            value = nil
-          end
-          multiple = false
+          value = data.collect{|g| g.handle }
+          multiple = true
         end
-
-        if value.nil?
-          nil
+      else
+        # the exists? method also ensure the object is loaded
+        if data.exists?
+          value = data.handle
         else
-          rel_key = "rel:" + rel
-          [rel_key, {
-             :syntax => nil,
-             :value => value,
-             :multiple => multiple,
-             :expert => expert_attributes.include?(rel_key),
-             :admin => false,
-             :binary => false
-           }]
+          value = nil
         end
+        multiple = false
+      end
+
+      if value.nil?
+        nil
+      else
+        attr_data = attribute_parameters(attr, claimed_by)
+
+        attr_data.merge!({
+                           :syntax        => nil,
+                           :value         => value,
+                           :single_value  => !multiple,
+                           :multiple      => multiple,
+                           :binary        => false,
+                           :operational   => false
+                         })
+
+        attr_data
       end
-      Hash[rel_data.compact]
     end
   end
 
diff --git a/lib/ldap_shadows/shadow.rb b/lib/ldap_shadows/shadow.rb
index 427db3e..b056c23 100644
--- a/lib/ldap_shadows/shadow.rb
+++ b/lib/ldap_shadows/shadow.rb
@@ -56,6 +56,8 @@ module LdapShadows
       @shadow_config
     end
 
+    alias_method :parameters, :get_config
+
     def add_aspect(aspect_name, aspect_def_raw)
       add_container_element('aspect', aspect_name, aspect_def_raw)
     end
@@ -107,7 +109,7 @@ module LdapShadows
            item_list[item.dn]= item
         end
       else
-        self.get_config[:presentation][:tree_objects].each do |obj_hdl|
+        self.get_config[:interface][:tree_objects].each do |obj_hdl|
           obj_klass = get_object(obj_hdl.downcase)
           unless obj_klass
             raise PreProcessingError, _("Tree object '%s' not defined") % obj_hdl
