commit c331fe496ad1561adfb5d9c0ef3e7554e9a0a5ff
Author: Marc Dequènes (Duck) <Duck@DuckCorp.org>
Date:   Sun Oct 18 15:36:21 2009 +0200

    [evol] rework how object/aspect classes are generated and ensure each shadow materials is in a proper container (to allow loading multiple shadows)

diff --git a/lib/ldap_shadows/display_utils.rb b/lib/ldap_shadows/display_utils.rb
index 4d720b6..98b91f8 100644
--- a/lib/ldap_shadows/display_utils.rb
+++ b/lib/ldap_shadows/display_utils.rb
@@ -68,7 +68,7 @@ module LdapShadows
     end
 
     def self.display_item(item, options = {})
-      obj_human_name = Translator.translate_object_name(item.handle)
+      obj_human_name = Translator.translate_object_name(item.class.handle)
       name = item.human_name
       name += " [#{item.name}]" if options[:handles]
       puts "=== #{obj_human_name}: #{name} ==="
diff --git a/lib/ldap_shadows/object.rb b/lib/ldap_shadows/object.rb
index 5332339..d1b89a5 100755
--- a/lib/ldap_shadows/object.rb
+++ b/lib/ldap_shadows/object.rb
@@ -24,7 +24,7 @@ module LdapShadows
   class LdapObject < ActiveLdap::Base
     include Hooks
 
-    class_inheritable_accessor :handle, :presentation, :shadow, :relations_info
+    class_inheritable_accessor :presentation, :relations_info
 
     ldap_mapping :prefix => '', :classes => ['top'], :scope => :sub
 
@@ -135,7 +135,7 @@ module LdapShadows
     end
 
     def organized_data
-      ignored_attrs = self.shadow.get_shadow_config[:hidden_attributes] || []
+      ignored_attrs = self.class.shadow.get_shadow_config[:hidden_attributes] || []
       ignored_attrs += self.class.presentation[:hidden_attributes] || []
       attr_list = self.nonempty_attributes - ignored_attrs
 
@@ -456,7 +456,7 @@ module LdapShadows
 
     def self.ldap_search_string_aspects(field, op, val_list)
       ldap_search_parts = val_list.split(",").collect do |val|
-        aspect_data = self.shadow.get_aspect(val)
+        aspect_data = self.class.shadow.get_aspect(val)
         raise PreProcessingError, _("No such aspect '%s'") % val if aspect_data.nil?
 
         ldap_classes = aspect_data[:mapping][:classes]
@@ -476,7 +476,7 @@ module LdapShadows
     end
 
     def self.find_raw_item_object(raw_item)
-      self.shadow.objects.each do |obj_hdl|
+      self.class.shadow.objects.each do |obj_hdl|
         obj_klass = $ldapctl.find_klass(obj_hdl)
         ldap_classes = obj_klass.required_classes
         return obj_hdl if raw_item.classes & ldap_classes == ldap_classes
@@ -537,7 +537,7 @@ module LdapShadows
     def add_aspect(aspect)
       return unless self.class.possible_aspects.include?(aspect)
 
-      aspect_data = self.shadow.get_aspect(aspect)
+      aspect_data = self.class.shadow.get_aspect(aspect)
       add_class(*aspect_data[:mapping][:classes])
 
       # recursive dependency enforcement
@@ -550,7 +550,7 @@ module LdapShadows
     def remove_aspect(aspect)
       return unless self.class.possible_aspects.include?(aspect)
 
-      aspect_data = self.shadow.get_aspect(aspect)
+      aspect_data = self.class.shadow.get_aspect(aspect)
       remove_class(*aspect_data[:mapping][:classes])
     end
 
diff --git a/lib/ldap_shadows/shadow.rb b/lib/ldap_shadows/shadow.rb
index c0bb5f3..26b81b3 100755
--- a/lib/ldap_shadows/shadow.rb
+++ b/lib/ldap_shadows/shadow.rb
@@ -21,21 +21,30 @@ $KCODE = 'UTF8'
 require 'jcode'
 require 'active_ldap'
 require 'ldap_shadows/activeldap_fixes'
+require 'facets/metaid'
 require 'ldap_shadows/object'
 require 'ldap_shadows/aspect'
 
 
 module LdapShadows
+  module Shadows
+  end
+
   class Shadow
     attr_reader :name
 
     def initialize(name)
       @name = name
 
-      LdapShadows::LdapObject.shadow = self
-
       @config = Config.instance
 
+      # cannot use anonymous modules/classes, as active_ldap needs named classes for relations
+      module_name = "Shadow" + name.capitalize
+      @container = LdapShadows::Shadows.module_eval(<<-EOS)
+        module #{module_name}; self; end
+      EOS
+
+      @objects = {}
       @object_definitions = {}
       @aspects = {}
       # TODO: should replace @aspects properly one day
@@ -53,24 +62,25 @@ module LdapShadows
 
     def add_aspect(aspect_name, aspect_def_raw)
       aspect_def = @config.parse_and_validate(aspect_name, 'aspect', aspect_def_raw)
-
-      aspect_name = aspect_name.to_sym
-      @aspects[aspect_name] = aspect_def
-
+      klass_name = "LdapAspect" + aspect_name.to_s.capitalize
       klass_content = @config.load_hook_content(@name, 'aspect', aspect_name)
 
-      klass_name = "LdapAspect" + aspect_name.to_s.capitalize
       begin
-        Aspects.module_eval(<<-EOS)
-        class #{klass_name} < LdapAspect
-          #{klass_content}
-        end
+        klass = @container.module_eval(<<-EOS)
+          class #{klass_name} < LdapAspect; self; end
         EOS
+        klass.instance_variable_set(:@handle, aspect_name)
+        klass.instance_variable_set(:@shadow, self)
+        klass.meta_eval do
+          attr_reader :handle, :shadow
+        end
+        klass.class_eval(klass_content) unless klass_content.nil?
       rescue
-        raise PreProcessingError, _("Could not load Aspect plugin '%s'") % aspect_name
+        raise PreProcessingError, _("Could not load Aspect plugin '%s': %s") % [aspect_name, $!]
       end
 
-      @aspects2[aspect_name] = Aspects.const_get(klass_name)
+      @aspects[aspect_name.to_sym] = aspect_def
+      @aspects2[aspect_name] = klass
     end
 
     def get_aspect(aspect_name)
@@ -78,42 +88,39 @@ module LdapShadows
     end
 
     def get_aspect_klass(aspect_name)
-      @aspects2[aspect_name.to_sym]
-    end
-
-    def self.object_name_to_klass_name(object_name)
-      "LdapObject" + object_name.to_s.capitalize
+      @aspects2[aspect_name]
     end
 
     def add_object(object_name, object_def_raw)
       object_def = @config.parse_and_validate(object_name, 'object', object_def_raw)
-
-      object_name = object_name.to_sym
-      klass_name = self.class.object_name_to_klass_name(object_name)
+      klass_name = "LdapObject" + object_name.to_s.capitalize
       klass_content = @config.load_hook_content(@name, 'object', object_name)
 
-      # create class
-      Objects.module_eval(<<-EOS)
-        class #{klass_name} < LdapObject
-          #{klass_content}
+      begin
+        klass = @container.module_eval(<<-EOS)
+          class #{klass_name} < LdapObject; self; end
+        EOS
+        klass.instance_variable_set(:@handle, object_name)
+        klass.instance_variable_set(:@shadow, self)
+        klass.meta_eval do
+          attr_reader :handle, :shadow
         end
-      EOS
+        klass.class_eval(klass_content) unless klass_content.nil?
+      rescue
+        raise PreProcessingError, _("Could not load Object plugin '%s': %s") % [object_name, $!]
+      end
 
       # configure class
-      klass = find_klass(object_name)
-      klass.handle = object_name
       klass.presentation = object_def[:presentation]
-      klass.shadow = self
       klass.ldap_mapping object_def[:mapping]
 
       # store definition for later relations processing
-      @object_definitions[object_name] = object_def
+      @object_definitions[object_name.to_sym] = object_def
+      @objects[object_name] = klass
     end
 
     def find_klass(object_name)
-      klass_name = self.class.object_name_to_klass_name(object_name)
-      return nil unless Objects.const_defined?(klass_name)
-      Objects.const_get(klass_name)
+      @objects[object_name.to_s]
     end
 
     # run it _once_ when all objects are loaded
@@ -162,16 +169,8 @@ module LdapShadows
     end
 
     def objects
-      @object_definitions.keys.collect{|key| key.to_s }.sort
+      @objects.keys.sort
     end
   end
-
-  # default location for mapped objects
-  module Objects
-  end
-
-  # default location for mapped aspects
-  module Aspects
-  end
 end
 
