# File lib/taggable.rb, line 165
        def acts_as_taggable(options = {})

          options = { :collection => :tags, :tag_class_name => 'Tag', :tag_class_column_name => 'name', :normalizer=> Proc.new {|name| name}}.merge(options)
          collection_name = options[:collection]
          tag_model = options[:tag_class_name].constantize
          tag_model_name = options[:tag_class_column_name]
          normalizer = options[:normalizer]
          if tag_model.table_name < self.table_name
            default_join_table = "#{tag_model.table_name}_#{self.table_name}"
          else
            default_join_table = "#{self.table_name}_#{tag_model.table_name}"
          end
          options[:join_table] ||= default_join_table
          options[:foreign_key] ||= self.name.to_s.foreign_key
          options[:association_foreign_key] ||= tag_model.to_s.foreign_key
         
          # not using a simple has_and_belongs_to_many but a full model
          # for joining the tags table and the taggable object table
          if join_class_name = options[:join_class_name]
            Object.class_eval "class #{join_class_name} < ActiveRecord::Base; set_table_name '#{options[:join_table]}' end" unless Object.const_defined?(join_class_name)
            
            join_model = join_class_name.constantize 
            tagged = self
            join_model.class_eval do
              belongs_to :tag, :class_name => tag_model.to_s
              belongs_to :tagged, :class_name => tagged.name.to_s
              define_method(:normalizer, normalizer) 
              define_method(tag_model_name.to_sym) { self[tag_model_name] ||= normalizer(tag.send(tag_model_name.to_sym)) }
            end
            
            
            options[:class_name] ||= join_model.to_s
            tag_pk, tag_fk = tag_model.primary_key, options[:association_foreign_key]
            t, tn, jt = tag_model.table_name, tag_model_name, join_model.table_name
            options[:finder_sql] ||= "SELECT #{jt}.*, #{t}.#{tn} AS #{tn} FROM #{jt}, #{t} WHERE #{jt}.#{tag_fk} = #{t}.#{tag_pk} AND #{jt}.#{options[:foreign_key]} = \#{quoted_id}"
          else
            join_model = nil
          end
          
          # set some class-wide attributes needed in class and instance methods                    
          write_inheritable_attribute(:tag_foreign_key, options[:association_foreign_key])                
          write_inheritable_attribute(:taggable_foreign_key, options[:foreign_key])                
          write_inheritable_attribute(:normalizer, normalizer)                
          write_inheritable_attribute(:tag_collection_name, collection_name)
          write_inheritable_attribute(:tag_model, tag_model)
          write_inheritable_attribute(:tag_model_name, tag_model_name)
          write_inheritable_attribute(:tags_join_model, join_model)
          write_inheritable_attribute(:tags_join_table, options[:join_table])                                      
          write_inheritable_attribute(:tag_options, options)
          
          [ :collection, :tag_class_name, :tag_class_column_name, :join_class_name,:normalizer].each { |key| options.delete(key) } # remove these, we don't need it anymore
          [ :join_table, :association_foreign_key ].each { |key| options.delete(key) } if join_model # dont need this for has_many

          # now, finally add the proper relationships          
          class_eval do
            include ActiveRecord::Acts::Taggable::InstanceMethods
            extend ActiveRecord::Acts::Taggable::SingletonMethods            
            
            class_inheritable_reader :tag_collection_name, :tag_model, :tag_model_name, :tags_join_model, 
                                     :tags_options, :tags_join_table,
                                     :tag_foreign_key, :taggable_foreign_key,:normalizer
            if join_model
              has_many collection_name, options
            else
              has_and_belongs_to_many collection_name, options
            end
          end                     
          
        end