friendly_id 2.3.4 → 3.0.0.beta1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/Changelog.md +10 -0
- data/Contributors.md +1 -0
- data/Guide.md +48 -4
- data/README.md +6 -4
- data/Rakefile +1 -1
- data/extras/extras.rb +1 -1
- data/generators/friendly_id/friendly_id_generator.rb +1 -1
- data/lib/friendly_id.rb +4 -6
- data/lib/friendly_id/{active_record2 → acktive_record}/configuration.rb +2 -2
- data/lib/friendly_id/{active_record2 → acktive_record}/finders.rb +24 -10
- data/lib/friendly_id/{active_record2 → acktive_record}/simple_model.rb +12 -50
- data/lib/friendly_id/acktive_record/slug.rb +66 -0
- data/lib/friendly_id/{active_record2 → acktive_record}/slugged_model.rb +9 -85
- data/lib/friendly_id/{active_record2 → acktive_record}/tasks.rb +5 -2
- data/lib/friendly_id/{active_record2 → acktive_record}/tasks/friendly_id.rake +1 -1
- data/lib/friendly_id/{active_record2.rb → active_record.rb} +18 -13
- data/lib/friendly_id/configuration.rb +11 -26
- data/lib/friendly_id/finders.rb +5 -3
- data/lib/friendly_id/slug_string.rb +11 -10
- data/lib/friendly_id/slugged.rb +11 -4
- data/lib/friendly_id/test.rb +46 -5
- data/lib/friendly_id/version.rb +5 -4
- data/lib/generators/friendly_id_generator.rb +32 -0
- data/rails/init.rb +1 -1
- data/test/{active_record2 → acktive_record}/basic_slugged_model_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/cached_slug_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/core.rb +1 -1
- data/test/{active_record2 → acktive_record}/custom_normalizer_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/custom_table_name_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/scoped_model_test.rb +2 -2
- data/test/{active_record2 → acktive_record}/simple_test.rb +4 -1
- data/test/{active_record2 → acktive_record}/slug_test.rb +0 -0
- data/test/{active_record2 → acktive_record}/slugged.rb +1 -1
- data/test/{active_record2 → acktive_record}/slugged_status_test.rb +1 -1
- data/test/{active_record2 → acktive_record}/sti_test.rb +3 -3
- data/test/{active_record2 → acktive_record}/support/database.mysql.yml +0 -0
- data/test/{active_record2 → acktive_record}/support/database.postgres.yml +0 -0
- data/test/{active_record2 → acktive_record}/support/database.sqlite3.yml +0 -0
- data/test/{active_record2 → acktive_record}/support/models.rb +5 -6
- data/test/{active_record2 → acktive_record}/tasks_test.rb +1 -1
- data/test/acktive_record/temp_test.rb +32 -0
- data/test/{active_record2 → acktive_record}/test_helper.rb +4 -10
- data/test/slug_string_test.rb +5 -1
- data/test/test_helper.rb +9 -3
- metadata +48 -44
- data/lib/friendly_id/active_record2/slug.rb +0 -111
- data/test/active_record2/deprecated_test.rb +0 -23
| @@ -1,5 +1,5 @@ | |
| 1 1 | 
             
            module FriendlyId
         | 
| 2 | 
            -
              module  | 
| 2 | 
            +
              module AcktiveRecord
         | 
| 3 3 | 
             
                module SluggedModel
         | 
| 4 4 |  | 
| 5 5 | 
             
                  module SluggedFinder
         | 
| @@ -18,7 +18,7 @@ module FriendlyId | |
| 18 18 | 
             
                  class MultipleFinder
         | 
| 19 19 |  | 
| 20 20 | 
             
                    include FriendlyId::Finders::Base
         | 
| 21 | 
            -
                    include FriendlyId:: | 
| 21 | 
            +
                    include FriendlyId::AcktiveRecord::Finders::Multiple
         | 
| 22 22 | 
             
                    include SluggedFinder
         | 
| 23 23 |  | 
| 24 24 | 
             
                    attr_reader :slugs
         | 
| @@ -86,7 +86,7 @@ module FriendlyId | |
| 86 86 | 
             
                    include SluggedFinder
         | 
| 87 87 |  | 
| 88 88 | 
             
                    def find
         | 
| 89 | 
            -
                      @result =  | 
| 89 | 
            +
                      @result = model_class.scoped(find_options).first(options)
         | 
| 90 90 | 
             
                      handle_friendly_result if friendly?
         | 
| 91 91 | 
             
                      @result
         | 
| 92 92 | 
             
                    rescue ::ActiveRecord::RecordNotFound => @error
         | 
| @@ -109,7 +109,7 @@ module FriendlyId | |
| 109 109 | 
             
                    end
         | 
| 110 110 |  | 
| 111 111 | 
             
                    def raise_scoped_error
         | 
| 112 | 
            -
                      scope_message =  | 
| 112 | 
            +
                      scope_message = scope || "expected, but none given"
         | 
| 113 113 | 
             
                      message = "%s, scope: %s" % [@error.message, scope_message]
         | 
| 114 114 | 
             
                      raise ::ActiveRecord::RecordNotFound, message
         | 
| 115 115 | 
             
                    end
         | 
| @@ -124,7 +124,7 @@ module FriendlyId | |
| 124 124 | 
             
                    include SluggedFinder
         | 
| 125 125 |  | 
| 126 126 | 
             
                    def find
         | 
| 127 | 
            -
                      @result =  | 
| 127 | 
            +
                      @result = model_class.scoped(find_options).first(options)
         | 
| 128 128 | 
             
                      handle_friendly_result if friendly?
         | 
| 129 129 | 
             
                      @result
         | 
| 130 130 | 
             
                    rescue ActiveRecord::RecordNotFound
         | 
| @@ -138,81 +138,6 @@ module FriendlyId | |
| 138 138 |  | 
| 139 139 | 
             
                  end
         | 
| 140 140 |  | 
| 141 | 
            -
                  # The methods in this module override ActiveRecord's +find_one+ and
         | 
| 142 | 
            -
                  # +find_some+ to add FriendlyId's features.
         | 
| 143 | 
            -
                  module FinderMethods
         | 
| 144 | 
            -
             | 
| 145 | 
            -
                    protected
         | 
| 146 | 
            -
             | 
| 147 | 
            -
                    def find_one(id_or_name, options)
         | 
| 148 | 
            -
                      finder = Finders::FinderProxy.new(id_or_name, self, options)
         | 
| 149 | 
            -
                      finder.unfriendly? ? super : finder.find or super
         | 
| 150 | 
            -
                    end
         | 
| 151 | 
            -
             | 
| 152 | 
            -
                    def find_some(ids_and_names, options)
         | 
| 153 | 
            -
                      Finders::FinderProxy.new(ids_and_names, self, options).find
         | 
| 154 | 
            -
                    end
         | 
| 155 | 
            -
             | 
| 156 | 
            -
                    # Since Rails goes out of its way to make these options completely
         | 
| 157 | 
            -
                    # inaccessible, we have to copy them here.
         | 
| 158 | 
            -
                    def validate_find_options(options)
         | 
| 159 | 
            -
                      options.assert_valid_keys([:conditions, :include, :joins, :limit, :offset,
         | 
| 160 | 
            -
                        :order, :select, :readonly, :group, :from, :lock, :having, :scope])
         | 
| 161 | 
            -
                    end
         | 
| 162 | 
            -
             | 
| 163 | 
            -
                  end
         | 
| 164 | 
            -
             | 
| 165 | 
            -
                  # These methods will be removed in FriendlyId 3.0.
         | 
| 166 | 
            -
                  module DeprecatedMethods
         | 
| 167 | 
            -
             | 
| 168 | 
            -
                    # @deprecated Please use #to_param
         | 
| 169 | 
            -
                    def best_id
         | 
| 170 | 
            -
                      warn("best_id is deprecated and will be removed in 3.0. Please use #to_param.")
         | 
| 171 | 
            -
                      to_param
         | 
| 172 | 
            -
                    end
         | 
| 173 | 
            -
             | 
| 174 | 
            -
                    # @deprecated Please use #friendly_id_status.slug.
         | 
| 175 | 
            -
                    def finder_slug
         | 
| 176 | 
            -
                      warn("finder_slug is deprecated and will be removed in 3.0. Please use #friendly_id_status.slug.")
         | 
| 177 | 
            -
                      friendly_id_status.slug
         | 
| 178 | 
            -
                    end
         | 
| 179 | 
            -
             | 
| 180 | 
            -
                    # Was the record found using one of its friendly ids?
         | 
| 181 | 
            -
                    # @deprecated Please use #friendly_id_status.friendly?
         | 
| 182 | 
            -
                    def found_using_friendly_id?
         | 
| 183 | 
            -
                      warn("found_using_friendly_id? is deprecated and will be removed in 3.0. Please use #friendly_id_status.friendly?")
         | 
| 184 | 
            -
                      friendly_id_status.friendly?
         | 
| 185 | 
            -
                    end
         | 
| 186 | 
            -
             | 
| 187 | 
            -
                    # Was the record found using its numeric id?
         | 
| 188 | 
            -
                    # @deprecated Please use #friendly_id_status.numeric?
         | 
| 189 | 
            -
                    def found_using_numeric_id?
         | 
| 190 | 
            -
                      warn("found_using_numeric_id is deprecated and will be removed in 3.0. Please use #friendly_id_status.numeric?")
         | 
| 191 | 
            -
                      friendly_id_status.numeric?
         | 
| 192 | 
            -
                    end
         | 
| 193 | 
            -
             | 
| 194 | 
            -
                    # Was the record found using an old friendly id?
         | 
| 195 | 
            -
                    # @deprecated Please use #friendly_id_status.outdated?
         | 
| 196 | 
            -
                    def found_using_outdated_friendly_id?
         | 
| 197 | 
            -
                      warn("found_using_outdated_friendly_id is deprecated and will be removed in 3.0. Please use #friendly_id_status.outdated?")
         | 
| 198 | 
            -
                      friendly_id_status.outdated?
         | 
| 199 | 
            -
                    end
         | 
| 200 | 
            -
             | 
| 201 | 
            -
                    # Was the record found using an old friendly id, or its numeric id?
         | 
| 202 | 
            -
                    # @deprecated Please use !#friendly_id_status.best?
         | 
| 203 | 
            -
                    def has_better_id?
         | 
| 204 | 
            -
                      warn("has_better_id? is deprecated and will be removed in 3.0. Please use !#friendly_id_status.best?")
         | 
| 205 | 
            -
                      ! friendly_id_status.best?
         | 
| 206 | 
            -
                    end
         | 
| 207 | 
            -
             | 
| 208 | 
            -
                    # @deprecated Please use #slug?
         | 
| 209 | 
            -
                    def has_a_slug?
         | 
| 210 | 
            -
                      warn("has_a_slug? is deprecated and will be removed in 3.0. Please use #slug?")
         | 
| 211 | 
            -
                      slug?
         | 
| 212 | 
            -
                    end
         | 
| 213 | 
            -
             | 
| 214 | 
            -
                  end
         | 
| 215 | 
            -
             | 
| 216 141 | 
             
                  def self.included(base)
         | 
| 217 142 | 
             
                    base.class_eval do
         | 
| 218 143 | 
             
                      has_many :slugs, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
         | 
| @@ -221,18 +146,17 @@ module FriendlyId | |
| 221 146 | 
             
                      after_update :update_scope
         | 
| 222 147 | 
             
                      after_update :update_dependent_scopes
         | 
| 223 148 | 
             
                      protect_friendly_id_attributes
         | 
| 224 | 
            -
                      extend FinderMethods
         | 
| 149 | 
            +
                      extend FriendlyId::AcktiveRecord::FinderMethods
         | 
| 225 150 | 
             
                    end
         | 
| 226 151 | 
             
                  end
         | 
| 227 152 |  | 
| 228 153 | 
             
                  include FriendlyId::Slugged::Model
         | 
| 229 | 
            -
                  include DeprecatedMethods
         | 
| 230 154 |  | 
| 231 155 | 
             
                  def find_slug(name, sequence)
         | 
| 232 156 | 
             
                    slugs.find_by_name_and_sequence(name, sequence)
         | 
| 233 157 | 
             
                  end
         | 
| 234 158 |  | 
| 235 | 
            -
                  # The model instance's current {FriendlyId:: | 
| 159 | 
            +
                  # The model instance's current {FriendlyId::AcktiveRecord::Slug slug}.
         | 
| 236 160 | 
             
                  def slug
         | 
| 237 161 | 
             
                    return @slug if new_record?
         | 
| 238 162 | 
             
                    @slug ||= slugs.first(:order => "id DESC")
         | 
| @@ -273,7 +197,7 @@ module FriendlyId | |
| 273 197 |  | 
| 274 198 | 
             
                  # Reset the cached friendly_id?
         | 
| 275 199 | 
             
                  def new_cache_needed?
         | 
| 276 | 
            -
                    uses_slug_cache? && send(friendly_id_config.cache_column) != slug.to_friendly_id
         | 
| 200 | 
            +
                    uses_slug_cache? && slug? && send(friendly_id_config.cache_column) != slug.to_friendly_id
         | 
| 277 201 | 
             
                  end
         | 
| 278 202 |  | 
| 279 203 | 
             
                  # Reset the cached friendly_id.
         | 
| @@ -285,7 +209,7 @@ module FriendlyId | |
| 285 209 | 
             
                  end
         | 
| 286 210 |  | 
| 287 211 | 
             
                  def update_scope
         | 
| 288 | 
            -
                    return unless scope_changed?
         | 
| 212 | 
            +
                    return unless slug && scope_changed?
         | 
| 289 213 | 
             
                    slug.update_attributes :scope => send(friendly_id_config.scope).to_param
         | 
| 290 214 | 
             
                  rescue ActiveRecord::StatementInvalid
         | 
| 291 215 | 
             
                    slug.update_attributes :sequence => Slug.similar_to(slug).first.sequence.succ
         | 
| @@ -26,13 +26,15 @@ module FriendlyId | |
| 26 26 |  | 
| 27 27 | 
             
                def make_slugs
         | 
| 28 28 | 
             
                  validate_uses_slugs
         | 
| 29 | 
            -
                   | 
| 29 | 
            +
                  cond = "slugs.id IS NULL"
         | 
| 30 | 
            +
                  options = {:limit => 100, :include => :slugs, :conditions => cond, :order => "#{klass.table_name}.id ASC"}.merge(task_options || {})
         | 
| 30 31 | 
             
                  while records = find(:all, options) do
         | 
| 31 32 | 
             
                    break if records.size == 0
         | 
| 32 33 | 
             
                    records.each do |record|
         | 
| 33 34 | 
             
                      record.save!
         | 
| 34 35 | 
             
                      yield(record) if block_given?
         | 
| 35 36 | 
             
                    end
         | 
| 37 | 
            +
                    options[:conditions] = cond + " and #{klass.table_name}.id > #{records.last.id}"
         | 
| 36 38 | 
             
                  end
         | 
| 37 39 | 
             
                end
         | 
| 38 40 |  | 
| @@ -45,7 +47,7 @@ module FriendlyId | |
| 45 47 | 
             
                end
         | 
| 46 48 |  | 
| 47 49 | 
             
                def delete_old_slugs
         | 
| 48 | 
            -
                  conditions = ["created_at < ?", DateTime.now - days | 
| 50 | 
            +
                  conditions = ["created_at < ?", DateTime.now - days]
         | 
| 49 51 | 
             
                  if klass
         | 
| 50 52 | 
             
                    conditions[0] << " AND sluggable_type = ?"
         | 
| 51 53 | 
             
                    conditions << klass.to_s
         | 
| @@ -54,6 +56,7 @@ module FriendlyId | |
| 54 56 | 
             
                end
         | 
| 55 57 |  | 
| 56 58 | 
             
                def validate_uses_slugs
         | 
| 59 | 
            +
                  (raise "You need to pass a MODEL=<model name> argument to rake") if klass.blank?
         | 
| 57 60 | 
             
                  unless friendly_id_config.use_slug?
         | 
| 58 61 | 
             
                    raise "Class '%s' doesn't use slugs" % klass.to_s
         | 
| 59 62 | 
             
                  end
         | 
| @@ -2,7 +2,7 @@ namespace :friendly_id do | |
| 2 2 | 
             
              desc "Make slugs for a model."
         | 
| 3 3 | 
             
              task :make_slugs => :environment do
         | 
| 4 4 | 
             
                FriendlyId::TaskRunner.new.make_slugs do |record|
         | 
| 5 | 
            -
                  puts "%s(%d): friendly_id set to '%s'" % [record.class.to_s, record.id, record.slug.name]
         | 
| 5 | 
            +
                  puts "%s(%d): friendly_id set to '%s'" % [record.class.to_s, record.id, record.slug.name] if record.slug
         | 
| 6 6 | 
             
                end
         | 
| 7 7 | 
             
              end
         | 
| 8 8 |  | 
| @@ -1,20 +1,18 @@ | |
| 1 | 
            -
            require File.join(File.dirname(__FILE__), "active_record2", "configuration")
         | 
| 2 | 
            -
            require File.join(File.dirname(__FILE__), "active_record2", "finders")
         | 
| 3 | 
            -
            require File.join(File.dirname(__FILE__), "active_record2", "simple_model")
         | 
| 4 | 
            -
            require File.join(File.dirname(__FILE__), "active_record2", "slugged_model")
         | 
| 5 | 
            -
            require File.join(File.dirname(__FILE__), "active_record2", "slug")
         | 
| 6 | 
            -
            require File.join(File.dirname(__FILE__), "active_record2", "tasks")
         | 
| 7 | 
            -
             | 
| 8 1 | 
             
            module FriendlyId
         | 
| 9 2 |  | 
| 10 | 
            -
              module  | 
| 3 | 
            +
              module AcktiveRecord
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                module Compat
         | 
| 6 | 
            +
                  def self.scope_method
         | 
| 7 | 
            +
                    ActiveRecord::VERSION::STRING >= "3" ? :scope : :named_scope
         | 
| 8 | 
            +
                  end
         | 
| 9 | 
            +
                end
         | 
| 11 10 |  | 
| 12 11 | 
             
                include FriendlyId::Base
         | 
| 13 12 |  | 
| 14 | 
            -
                def has_friendly_id(method, options = {} | 
| 13 | 
            +
                def has_friendly_id(method, options = {})
         | 
| 15 14 | 
             
                  class_inheritable_accessor :friendly_id_config
         | 
| 16 | 
            -
                  write_inheritable_attribute :friendly_id_config, Configuration.new(self,
         | 
| 17 | 
            -
                    method, options.merge(:normalizer => block))
         | 
| 15 | 
            +
                  write_inheritable_attribute :friendly_id_config, Configuration.new(self, method, options)
         | 
| 18 16 | 
             
                  if friendly_id_config.use_slug?
         | 
| 19 17 | 
             
                    include SluggedModel
         | 
| 20 18 | 
             
                  else
         | 
| @@ -43,5 +41,12 @@ module FriendlyId | |
| 43 41 | 
             
            end
         | 
| 44 42 |  | 
| 45 43 | 
             
            class ActiveRecord::Base
         | 
| 46 | 
            -
              extend FriendlyId:: | 
| 47 | 
            -
            end
         | 
| 44 | 
            +
              extend FriendlyId::AcktiveRecord
         | 
| 45 | 
            +
            end
         | 
| 46 | 
            +
             | 
| 47 | 
            +
            require File.join(File.dirname(__FILE__), "acktive_record", "configuration")
         | 
| 48 | 
            +
            require File.join(File.dirname(__FILE__), "acktive_record", "finders")
         | 
| 49 | 
            +
            require File.join(File.dirname(__FILE__), "acktive_record", "simple_model")
         | 
| 50 | 
            +
            require File.join(File.dirname(__FILE__), "acktive_record", "slugged_model")
         | 
| 51 | 
            +
            require File.join(File.dirname(__FILE__), "acktive_record", "slug")
         | 
| 52 | 
            +
            require File.join(File.dirname(__FILE__), "acktive_record", "tasks")
         | 
| @@ -22,6 +22,7 @@ module FriendlyId | |
| 22 22 | 
             
              class Configuration
         | 
| 23 23 |  | 
| 24 24 | 
             
                DEFAULTS = {
         | 
| 25 | 
            +
                  :allow_nil                   => false,
         | 
| 25 26 | 
             
                  :ascii_approximation_options => [],
         | 
| 26 27 | 
             
                  :max_length                  => 255,
         | 
| 27 28 | 
             
                  :reserved_words              => ["index", "new"],
         | 
| @@ -29,6 +30,12 @@ module FriendlyId | |
| 29 30 | 
             
                  :sequence_separator          => "--"
         | 
| 30 31 | 
             
                }
         | 
| 31 32 |  | 
| 33 | 
            +
                # Whether to allow friendly_id and/or slugs to be nil. This is not
         | 
| 34 | 
            +
                # generally useful on its own, but may allow you greater flexibility to
         | 
| 35 | 
            +
                # customize your application.
         | 
| 36 | 
            +
                attr_accessor :allow_nil
         | 
| 37 | 
            +
                alias :allow_nil? :allow_nil
         | 
| 38 | 
            +
             | 
| 32 39 | 
             
                # Strip diacritics from Western characters.
         | 
| 33 40 | 
             
                attr_accessor :approximate_ascii
         | 
| 34 41 |  | 
| @@ -47,12 +54,6 @@ module FriendlyId | |
| 47 54 | 
             
                attr_reader :method
         | 
| 48 55 | 
             
                alias :column :method
         | 
| 49 56 |  | 
| 50 | 
            -
                # A block or proc through which to filter the friendly_id text.
         | 
| 51 | 
            -
                # This method will be removed from FriendlyId 3.0.
         | 
| 52 | 
            -
                # @deprecated Please override the +normalize_friendly_id+
         | 
| 53 | 
            -
                #   method in your model class rather than passing a block to `has_friendly_id`.
         | 
| 54 | 
            -
                attr_accessor :normalizer
         | 
| 55 | 
            -
             | 
| 56 57 | 
             
                # The message shown when a reserved word is used.
         | 
| 57 58 | 
             
                # @see #reserved_words
         | 
| 58 59 | 
             
                attr_accessor :reserved_message
         | 
| @@ -85,10 +86,8 @@ module FriendlyId | |
| 85 86 | 
             
                  yield self if block_given?
         | 
| 86 87 | 
             
                end
         | 
| 87 88 |  | 
| 88 | 
            -
                def  | 
| 89 | 
            -
                   | 
| 90 | 
            -
                  warn("passing a block to has_friendly_id is deprecated and will be removed from 3.0. Please override #normalize_friendly_id.")
         | 
| 91 | 
            -
                  @normalizer = arg
         | 
| 89 | 
            +
                def forbid_nil?
         | 
| 90 | 
            +
                  !allow_nil?
         | 
| 92 91 | 
             
                end
         | 
| 93 92 |  | 
| 94 93 | 
             
                def reserved_words=(*words)
         | 
| @@ -103,21 +102,7 @@ module FriendlyId | |
| 103 102 | 
             
                  [method, reserved_message % word] if reserved? word
         | 
| 104 103 | 
             
                end
         | 
| 105 104 |  | 
| 106 | 
            -
                 | 
| 107 | 
            -
                # @deprecated Please use {#reserved_words reserved_words}.
         | 
| 108 | 
            -
                def reserved=(*args)
         | 
| 109 | 
            -
                  warn('The "reserved" option is deprecated and will be removed from FriendlyId 3.0. Please use "reserved_words".')
         | 
| 110 | 
            -
                  self.reserved_words = *args
         | 
| 111 | 
            -
                end
         | 
| 112 | 
            -
             | 
| 113 | 
            -
                # This method will be removed from FriendlyId 3.0.
         | 
| 114 | 
            -
                # @deprecated Please use {#approximate_ascii approximate_ascii}.
         | 
| 115 | 
            -
                def strip_diacritics=(*args)
         | 
| 116 | 
            -
                  warn('strip_diacritics is deprecated and will be removed from 3.0. Please use #approximate_ascii')
         | 
| 117 | 
            -
                  self.approximate_ascii = *args
         | 
| 118 | 
            -
                end
         | 
| 119 | 
            -
             | 
| 120 | 
            -
                %w[approximate_ascii normalizer scope strip_non_ascii use_slug].each do |method|
         | 
| 105 | 
            +
                %w[approximate_ascii scope strip_non_ascii use_slug].each do |method|
         | 
| 121 106 | 
             
                  class_eval(<<-EOM)
         | 
| 122 107 | 
             
                    def #{method}?
         | 
| 123 108 | 
             
                      !! #{method}
         | 
| @@ -129,4 +114,4 @@ module FriendlyId | |
| 129 114 |  | 
| 130 115 | 
             
              end
         | 
| 131 116 |  | 
| 132 | 
            -
            end
         | 
| 117 | 
            +
            end
         | 
    
        data/lib/friendly_id/finders.rb
    CHANGED
    
    | @@ -14,7 +14,7 @@ module FriendlyId | |
| 14 14 | 
             
                  # @return [true, false, nil]
         | 
| 15 15 | 
             
                  # @see #unfriendly?
         | 
| 16 16 | 
             
                  def self.friendly?(id)
         | 
| 17 | 
            -
                    if id.is_a?(Integer) or id.class.respond_to? :friendly_id_config
         | 
| 17 | 
            +
                    if id.is_a?(Integer) or id.is_a?(Symbol) or id.class.respond_to? :friendly_id_config
         | 
| 18 18 | 
             
                      return false
         | 
| 19 19 | 
             
                    elsif id.to_i.to_s != id.to_s
         | 
| 20 20 | 
             
                      return true
         | 
| @@ -35,7 +35,7 @@ module FriendlyId | |
| 35 35 | 
             
                    self.ids = ids
         | 
| 36 36 | 
             
                    self.options = options
         | 
| 37 37 | 
             
                    self.model_class = model_class
         | 
| 38 | 
            -
                    self.scope = options | 
| 38 | 
            +
                    self.scope = options.delete :scope
         | 
| 39 39 | 
             
                  end
         | 
| 40 40 |  | 
| 41 41 | 
             
                  def method_missing(*args, &block)
         | 
| @@ -67,7 +67,9 @@ module FriendlyId | |
| 67 67 | 
             
                  alias :id= :ids=
         | 
| 68 68 |  | 
| 69 69 | 
             
                  def scope=(scope)
         | 
| 70 | 
            -
                     | 
| 70 | 
            +
                    unless scope.nil?
         | 
| 71 | 
            +
                      @scope = scope.respond_to?(:to_param) ? scope.to_param : scope.to_s
         | 
| 72 | 
            +
                    end
         | 
| 71 73 | 
             
                  end
         | 
| 72 74 | 
             
                end
         | 
| 73 75 |  | 
| @@ -162,7 +162,7 @@ module FriendlyId | |
| 162 162 | 
             
                  # whitespace characters with a single space.
         | 
| 163 163 | 
             
                  # @return String
         | 
| 164 164 | 
             
                  def clean!
         | 
| 165 | 
            -
                    @wrapped_string = @wrapped_string.gsub(/\A\-|\-\z/,  | 
| 165 | 
            +
                    @wrapped_string = @wrapped_string.gsub(/\A\-|\-\z/, "").gsub(/\s+/u, " ").strip
         | 
| 166 166 | 
             
                  end
         | 
| 167 167 |  | 
| 168 168 | 
             
                  # Lowercases the string. Note that this works for Unicode strings,
         | 
| @@ -198,13 +198,9 @@ module FriendlyId | |
| 198 198 | 
             
                  # @param config [FriendlyId::Configuration]
         | 
| 199 199 | 
             
                  # @return String
         | 
| 200 200 | 
             
                  def normalize_for!(config)
         | 
| 201 | 
            -
                    if config. | 
| 202 | 
            -
             | 
| 203 | 
            -
                     | 
| 204 | 
            -
                      approximate_ascii! if config.approximate_ascii?
         | 
| 205 | 
            -
                      to_ascii! if config.strip_non_ascii?
         | 
| 206 | 
            -
                      normalize!
         | 
| 207 | 
            -
                    end
         | 
| 201 | 
            +
                    approximate_ascii! if config.approximate_ascii?
         | 
| 202 | 
            +
                    to_ascii! if config.strip_non_ascii?
         | 
| 203 | 
            +
                    normalize!
         | 
| 208 204 | 
             
                  end
         | 
| 209 205 |  | 
| 210 206 | 
             
                  alias :normalize_utf8 :normalize rescue NoMethodError
         | 
| @@ -231,7 +227,12 @@ module FriendlyId | |
| 231 227 | 
             
                  # Delete any non-ascii characters.
         | 
| 232 228 | 
             
                  # @return String
         | 
| 233 229 | 
             
                  def to_ascii!
         | 
| 234 | 
            -
                     | 
| 230 | 
            +
                    if ">= 1.9".respond_to?(:force_encoding)
         | 
| 231 | 
            +
                      @wrapped_string.encode!("ASCII", :invalid => :replace, :undef => :replace,
         | 
| 232 | 
            +
                        :replace => "")
         | 
| 233 | 
            +
                    else
         | 
| 234 | 
            +
                      @wrapped_string = tidy_bytes.normalize_utf8(:c).unpack("U*").reject {|char| char > 127}.pack("U*")
         | 
| 235 | 
            +
                    end
         | 
| 235 236 | 
             
                  end
         | 
| 236 237 |  | 
| 237 238 | 
             
                  # Upper-cases the string. Note that this works for Unicode strings,
         | 
| @@ -257,7 +258,7 @@ module FriendlyId | |
| 257 258 | 
             
                  # Replaces whitespace with dashes ("-").
         | 
| 258 259 | 
             
                  # @return String
         | 
| 259 260 | 
             
                  def with_dashes!
         | 
| 260 | 
            -
                    @wrapped_string = @wrapped_string.gsub(/[\s\-]+/u,  | 
| 261 | 
            +
                    @wrapped_string = @wrapped_string.gsub(/[\s\-]+/u, "-")
         | 
| 261 262 | 
             
                  end
         | 
| 262 263 |  | 
| 263 264 | 
             
                  %w[approximate_ascii clean downcase word_chars normalize normalize_for to_ascii
         | 
    
        data/lib/friendly_id/slugged.rb
    CHANGED
    
    | @@ -55,7 +55,7 @@ module FriendlyId | |
| 55 55 |  | 
| 56 56 | 
             
                  # The friendly id.
         | 
| 57 57 | 
             
                  def friendly_id
         | 
| 58 | 
            -
                    slug.to_friendly_id
         | 
| 58 | 
            +
                    slug.to_friendly_id if slug?
         | 
| 59 59 | 
             
                  end
         | 
| 60 60 |  | 
| 61 61 | 
             
                  # Clean up the string before setting it as the friendly_id. You can override
         | 
| @@ -75,8 +75,11 @@ module FriendlyId | |
| 75 75 |  | 
| 76 76 | 
             
                  # Get the processed string used as the basis of the friendly id.
         | 
| 77 77 | 
             
                  def slug_text
         | 
| 78 | 
            -
                     | 
| 79 | 
            -
                     | 
| 78 | 
            +
                    base = send(friendly_id_config.method)
         | 
| 79 | 
            +
                    unless base.nil? && friendly_id_config.allow_nil?
         | 
| 80 | 
            +
                      text = normalize_friendly_id(SlugString.new(base))
         | 
| 81 | 
            +
                      SlugString.new(text.to_s).validate_for!(friendly_id_config).to_s
         | 
| 82 | 
            +
                    end
         | 
| 80 83 | 
             
                  end
         | 
| 81 84 |  | 
| 82 85 | 
             
                  # Has the slug text changed?
         | 
| @@ -87,7 +90,11 @@ module FriendlyId | |
| 87 90 | 
             
                  # Has the basis of our friendly id changed, requiring the generation of a
         | 
| 88 91 | 
             
                  # new slug?
         | 
| 89 92 | 
             
                  def new_slug_needed?
         | 
| 90 | 
            -
                     | 
| 93 | 
            +
                    if friendly_id_config.allow_nil?
         | 
| 94 | 
            +
                      (!slug? && !slug_text.blank?) || (slug? && slug_text_changed?)
         | 
| 95 | 
            +
                    else
         | 
| 96 | 
            +
                      !slug? || slug_text_changed?
         | 
| 97 | 
            +
                    end
         | 
| 91 98 | 
             
                  end
         | 
| 92 99 |  | 
| 93 100 | 
             
                end
         | 
    
        data/lib/friendly_id/test.rb
    CHANGED
    
    | @@ -18,7 +18,6 @@ module FriendlyId | |
| 18 18 |  | 
| 19 19 | 
             
                  def teardown
         | 
| 20 20 | 
             
                    klass.send delete_all_method
         | 
| 21 | 
            -
                    # other_class.delete_all
         | 
| 22 21 | 
             
                  end
         | 
| 23 22 |  | 
| 24 23 | 
             
                  def instance
         | 
| @@ -41,6 +40,10 @@ module FriendlyId | |
| 41 40 | 
             
                    raise NotImplementedError
         | 
| 42 41 | 
             
                  end
         | 
| 43 42 |  | 
| 43 | 
            +
                  def update_method
         | 
| 44 | 
            +
                    raise NotImplementedError
         | 
| 45 | 
            +
                  end
         | 
| 46 | 
            +
             | 
| 44 47 | 
             
                  def validation_exceptions
         | 
| 45 48 | 
             
                    return RuntimeError
         | 
| 46 49 | 
             
                  end
         | 
| @@ -49,7 +52,7 @@ module FriendlyId | |
| 49 52 | 
             
                    assert_not_nil klass.friendly_id_config
         | 
| 50 53 | 
             
                  end
         | 
| 51 54 |  | 
| 52 | 
            -
                  test "instances should have a friendly id" do
         | 
| 55 | 
            +
                  test "instances should have a friendly id by default" do
         | 
| 53 56 | 
             
                    assert_not_nil instance.friendly_id
         | 
| 54 57 | 
             
                  end
         | 
| 55 58 |  | 
| @@ -69,6 +72,11 @@ module FriendlyId | |
| 69 72 | 
             
                    assert_equal instance, klass.send(find_method, instance.id.to_s)
         | 
| 70 73 | 
             
                  end
         | 
| 71 74 |  | 
| 75 | 
            +
                  test "instances should be findable by a numeric friendly_id" do
         | 
| 76 | 
            +
                    instance = klass.send(create_method, :name => "206")
         | 
| 77 | 
            +
                    assert_equal instance, klass.send(find_method, instance.friendly_id)
         | 
| 78 | 
            +
                  end
         | 
| 79 | 
            +
             | 
| 72 80 | 
             
                  test "creation should raise an error if the friendly_id text is reserved" do
         | 
| 73 81 | 
             
                    assert_raise(*[validation_exceptions].flatten) do
         | 
| 74 82 | 
             
                      klass.send(create_method, :name => "new")
         | 
| @@ -87,12 +95,17 @@ module FriendlyId | |
| 87 95 | 
             
                    end
         | 
| 88 96 | 
             
                  end
         | 
| 89 97 |  | 
| 90 | 
            -
                  test "creation should raise an error if the friendly_id text is nil" do
         | 
| 98 | 
            +
                  test "creation should raise an error if the friendly_id text is nil and allow_nil is false" do
         | 
| 91 99 | 
             
                    assert_raise(*[validation_exceptions].flatten) do
         | 
| 92 100 | 
             
                      klass.send(create_method, :name => nil)
         | 
| 93 101 | 
             
                    end
         | 
| 94 102 | 
             
                  end
         | 
| 95 103 |  | 
| 104 | 
            +
                  test "creation should succeed if the friendly_id text is nil and allow_nil is true" do
         | 
| 105 | 
            +
                    klass.friendly_id_config.stubs(:allow_nil?).returns(true)
         | 
| 106 | 
            +
                    assert klass.send(create_method, :name => nil)
         | 
| 107 | 
            +
                  end
         | 
| 108 | 
            +
             | 
| 96 109 | 
             
                  test "should allow the same friendly_id across models" do
         | 
| 97 110 | 
             
                    other_instance = other_class.send(create_method, :name => instance.name)
         | 
| 98 111 | 
             
                    assert_equal other_instance.friendly_id, instance.friendly_id
         | 
| @@ -100,6 +113,18 @@ module FriendlyId | |
| 100 113 |  | 
| 101 114 | 
             
                end
         | 
| 102 115 |  | 
| 116 | 
            +
                module Simple
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                  test "should allow friendly_id to be nillable if allow_nil is true" do
         | 
| 119 | 
            +
                    klass.friendly_id_config.stubs(:allow_nil?).returns(true)
         | 
| 120 | 
            +
                    instance = klass.send(create_method, :name => "hello")
         | 
| 121 | 
            +
                    assert instance.friendly_id
         | 
| 122 | 
            +
                    instance.name = nil
         | 
| 123 | 
            +
                    assert instance.send(save_method)
         | 
| 124 | 
            +
                  end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                end
         | 
| 127 | 
            +
             | 
| 103 128 | 
             
                # Tests for any model that implements slugs.
         | 
| 104 129 | 
             
                module Slugged
         | 
| 105 130 |  | 
| @@ -152,6 +177,22 @@ module FriendlyId | |
| 152 177 | 
             
                    assert_equal instance, klass.find(old_friendly_id)
         | 
| 153 178 | 
             
                  end
         | 
| 154 179 |  | 
| 180 | 
            +
                  test "should not create a slug when allow_nil is true and friendy_id text is blank" do
         | 
| 181 | 
            +
                    klass.friendly_id_config.stubs(:allow_nil?).returns(true)
         | 
| 182 | 
            +
                    instance = klass.send(create_method, :name => nil)
         | 
| 183 | 
            +
                    assert_nil instance.slug
         | 
| 184 | 
            +
                  end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                  test "should not allow friendly_id to be nillable even if allow_nil is true" do
         | 
| 187 | 
            +
                    klass.friendly_id_config.stubs(:allow_nil?).returns(true)
         | 
| 188 | 
            +
                    instance = klass.send(create_method, :name => "hello")
         | 
| 189 | 
            +
                    assert instance.friendly_id
         | 
| 190 | 
            +
                    instance.name = nil
         | 
| 191 | 
            +
                    assert_raise(*[validation_exceptions].flatten) do
         | 
| 192 | 
            +
                      instance.send(save_method)
         | 
| 193 | 
            +
                    end
         | 
| 194 | 
            +
                  end
         | 
| 195 | 
            +
             | 
| 155 196 | 
             
                end
         | 
| 156 197 |  | 
| 157 198 | 
             
                # Tests for FriendlyId::Status.
         | 
| @@ -164,7 +205,7 @@ module FriendlyId | |
| 164 205 | 
             
                    assert status.numeric?
         | 
| 165 206 | 
             
                  end
         | 
| 166 207 | 
             
                end
         | 
| 167 | 
            -
             | 
| 208 | 
            +
             | 
| 168 209 | 
             
                # Tests for FriendlyId::Status for a model that uses slugs.
         | 
| 169 210 | 
             
                module SluggedStatus
         | 
| 170 211 |  | 
| @@ -244,4 +285,4 @@ module FriendlyId | |
| 244 285 |  | 
| 245 286 | 
             
                end
         | 
| 246 287 | 
             
              end
         | 
| 247 | 
            -
            end
         | 
| 288 | 
            +
            end
         |