friendly_id 1.9.9

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.
Files changed (56) hide show
  1. data.tar.gz.sig +0 -0
  2. data/History.txt +81 -0
  3. data/MIT-LICENSE +19 -0
  4. data/Manifest.txt +53 -0
  5. data/README.rdoc +313 -0
  6. data/Rakefile +43 -0
  7. data/coverage/index.html +409 -0
  8. data/coverage/lib-friendly_id-non_sluggable_class_methods_rb.html +646 -0
  9. data/coverage/lib-friendly_id-non_sluggable_instance_methods_rb.html +638 -0
  10. data/coverage/lib-friendly_id-shoulda_macros_rb.html +641 -0
  11. data/coverage/lib-friendly_id-sluggable_class_methods_rb.html +714 -0
  12. data/coverage/lib-friendly_id-sluggable_instance_methods_rb.html +710 -0
  13. data/coverage/lib-friendly_id-string_helpers_rb.html +685 -0
  14. data/coverage/lib-friendly_id_rb.html +665 -0
  15. data/coverage/lib-slug_rb.html +695 -0
  16. data/coverage/rails-init_rb.html +606 -0
  17. data/friendly_id.gemspec +38 -0
  18. data/generators/friendly_id/friendly_id_generator.rb +12 -0
  19. data/generators/friendly_id/templates/create_slugs.rb +18 -0
  20. data/generators/friendly_id_20_upgrade/friendly_id_20_upgrade_generator.rb +11 -0
  21. data/generators/friendly_id_20_upgrade/templates/upgrade_friendly_id_to_20.rb +19 -0
  22. data/init.rb +1 -0
  23. data/lib/friendly_id.rb +61 -0
  24. data/lib/friendly_id/non_sluggable_class_methods.rb +41 -0
  25. data/lib/friendly_id/non_sluggable_instance_methods.rb +33 -0
  26. data/lib/friendly_id/shoulda_macros.rb +36 -0
  27. data/lib/friendly_id/slug.rb +90 -0
  28. data/lib/friendly_id/sluggable_class_methods.rb +109 -0
  29. data/lib/friendly_id/sluggable_instance_methods.rb +105 -0
  30. data/lib/friendly_id/version.rb +8 -0
  31. data/lib/tasks/friendly_id.rake +48 -0
  32. data/lib/tasks/friendly_id.rb +1 -0
  33. data/test/database.yml +3 -0
  34. data/test/fixtures/countries.yml +4 -0
  35. data/test/fixtures/country.rb +4 -0
  36. data/test/fixtures/people.yml +7 -0
  37. data/test/fixtures/person.rb +6 -0
  38. data/test/fixtures/post.rb +3 -0
  39. data/test/fixtures/posts.yml +19 -0
  40. data/test/fixtures/slugs.yml +45 -0
  41. data/test/fixtures/user.rb +3 -0
  42. data/test/fixtures/users.yml +7 -0
  43. data/test/non_slugged_test.rb +63 -0
  44. data/test/rails/2.x/app/controllers/application.rb +0 -0
  45. data/test/rails/2.x/config/boot.rb +109 -0
  46. data/test/rails/2.x/config/database.yml +3 -0
  47. data/test/rails/2.x/config/environment.rb +7 -0
  48. data/test/rails/2.x/config/environments/test.rb +6 -0
  49. data/test/rails/2.x/config/routes.rb +0 -0
  50. data/test/schema.rb +38 -0
  51. data/test/scoped_model_test.rb +21 -0
  52. data/test/slug_test.rb +87 -0
  53. data/test/sluggable_test.rb +181 -0
  54. data/test/test_helper.rb +35 -0
  55. metadata +155 -0
  56. metadata.gz.sig +1 -0
@@ -0,0 +1,38 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{friendly_id}
3
+ s.version = "1.9.9"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Norman Clarke", "Adrian Mugnolo", "Emilio Tagua"]
7
+ s.cert_chain = ["/Users/norman/.gem/gem-public_cert.pem"]
8
+ s.date = %q{2008-12-16}
9
+ s.description = %q{A comprehensive slugging and pretty-URL plugin for Ruby on Rails.}
10
+ s.email = ["norman@randomba.org", "adrian@randomba.org", "miloops@gmail.com"]
11
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt"]
12
+ s.files = ["History.txt", "MIT-LICENSE", "Manifest.txt", "README.rdoc", "Rakefile", "coverage/index.html", "coverage/lib-friendly_id-non_sluggable_class_methods_rb.html", "coverage/lib-friendly_id-non_sluggable_instance_methods_rb.html", "coverage/lib-friendly_id-shoulda_macros_rb.html", "coverage/lib-friendly_id-sluggable_class_methods_rb.html", "coverage/lib-friendly_id-sluggable_instance_methods_rb.html", "coverage/lib-friendly_id-string_helpers_rb.html", "coverage/lib-friendly_id_rb.html", "coverage/lib-slug_rb.html", "coverage/rails-init_rb.html", "friendly_id.gemspec", "generators/friendly_id/friendly_id_generator.rb", "generators/friendly_id/templates/create_slugs.rb", "init.rb", "lib/friendly_id.rb", "lib/friendly_id/non_sluggable_class_methods.rb", "lib/friendly_id/non_sluggable_instance_methods.rb", "lib/friendly_id/shoulda_macros.rb", "lib/friendly_id/slug.rb", "lib/friendly_id/sluggable_class_methods.rb", "lib/friendly_id/sluggable_instance_methods.rb", "lib/friendly_id/version.rb", "lib/tasks/friendly_id.rake", "lib/tasks/friendly_id.rb", "test/database.yml", "test/fixtures/countries.yml", "test/fixtures/country.rb", "test/fixtures/people.yml", "test/fixtures/person.rb", "test/fixtures/post.rb", "test/fixtures/posts.yml", "test/fixtures/slugs.yml", "test/fixtures/user.rb", "test/fixtures/users.yml", "test/non_slugged_test.rb", "test/rails/2.x/app/controllers/application.rb", "test/rails/2.x/config/boot.rb", "test/rails/2.x/config/database.yml", "test/rails/2.x/config/environment.rb", "test/rails/2.x/config/environments/test.rb", "test/rails/2.x/config/routes.rb", "test/schema.rb", "test/scoped_model_test.rb", "test/slug_test.rb", "test/sluggable_test.rb", "test/test_helper.rb"]
13
+ s.has_rdoc = true
14
+ s.homepage = %q{http://randomba.org}
15
+ s.rdoc_options = ["--main", "README.txt"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = %q{friendly-id}
18
+ s.rubygems_version = %q{1.3.1}
19
+ s.signing_key = %q{/Users/norman/.gem/gem-private_key.pem}
20
+ s.summary = %q{A comprehensive slugging and pretty-URL plugin for Ruby on Rails.}
21
+ s.test_files = ["test/non_slugged_test.rb", "test/scoped_model_test.rb", "test/slug_test.rb", "test/sluggable_test.rb"]
22
+
23
+ if s.respond_to? :specification_version then
24
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
25
+ s.specification_version = 2
26
+
27
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
28
+ s.add_runtime_dependency(%q<unicode>, [">= 0.1"])
29
+ s.add_development_dependency(%q<hoe>, [">= 1.8.2"])
30
+ else
31
+ s.add_dependency(%q<unicode>, [">= 0.1"])
32
+ s.add_dependency(%q<hoe>, [">= 1.8.2"])
33
+ end
34
+ else
35
+ s.add_dependency(%q<unicode>, [">= 0.1"])
36
+ s.add_dependency(%q<hoe>, [">= 1.8.2"])
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ class FriendlyIdGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ unless options[:skip_migration]
5
+ m.migration_template(
6
+ 'create_slugs.rb', 'db/migrate', :migration_file_name => 'create_slugs'
7
+ )
8
+ m.file "/../../../lib/tasks/friendly_id.rake", "lib/tasks/friendly_id.rake"
9
+ end
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,18 @@
1
+ class CreateSlugs < ActiveRecord::Migration
2
+ def self.up
3
+ create_table :slugs do |t|
4
+ t.string :name
5
+ t.integer :sluggable_id
6
+ t.integer :sequence, :null => false, :default => 1
7
+ t.string :sluggable_type, :limit => 40
8
+ t.string :scope, :limit => 40
9
+ t.datetime :created_at
10
+ end
11
+ add_index :slugs, [:name, :sluggable_type, :scope, :sequence], :unique => true
12
+ add_index :slugs, :sluggable_id
13
+ end
14
+
15
+ def self.down
16
+ drop_table :slugs
17
+ end
18
+ end
@@ -0,0 +1,11 @@
1
+ class FriendlyId20UpgradeGenerator < Rails::Generator::Base
2
+ def manifest
3
+ record do |m|
4
+ unless options[:skip_migration]
5
+ m.migration_template(
6
+ 'upgrade_friendly_id_to_20.rb', 'db/migrate', :migration_file_name => 'upgrade_friendly_id_to_20'
7
+ )
8
+ end
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,19 @@
1
+ class UpgradeFriendlyIdTo20 < ActiveRecord::Migration
2
+
3
+ def self.up
4
+ remove_column :slugs, :updated_at
5
+ remove_index :slugs, :column => [:name, :sluggable_type]
6
+ add_column :slugs, :sequence, :integer, :null => false, :default => 1
7
+ add_column :slugs, :scope, :string, :limit => 40
8
+ add_index :slugs, [:name, :sluggable_type, :scope, :sequence], :unique => true, :name => "index_slugs_on_n_s_s_and_s"
9
+ end
10
+
11
+ def self.down
12
+ remove_index :slugs, :name => "index_slugs_on_n_s_s_and_s"
13
+ remove_column :slugs, :scope
14
+ remove_column :slugs, :sequence
15
+ add_column :slugs, :updated_at, :datetime
16
+ add_index :slugs, [:name, :sluggable_type], :unique => true
17
+ end
18
+
19
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require 'friendly_id'
@@ -0,0 +1,61 @@
1
+ require 'unicode'
2
+ require 'friendly_id/slug'
3
+ require 'friendly_id/shoulda_macros'
4
+
5
+ # FriendlyId is a comprehensize Rails plugin/gem for slugging and permalinks.
6
+ module FriendlyId
7
+
8
+ # Load FriendlyId if the gem is included in a Rails app.
9
+ def self.enable
10
+ return if ActiveRecord::Base.methods.include? 'has_friendly_id'
11
+ ActiveRecord::Base.class_eval { extend FriendlyId::ClassMethods }
12
+ Test::Unit::TestCase.class_eval { include FriendlyId::ShouldaMacros }
13
+ end
14
+
15
+ # This error is raised when it's not possible to generate a unique slug.
16
+ class SlugGenerationError < StandardError ; end
17
+
18
+ module ClassMethods
19
+
20
+ # Default options for friendly_id.
21
+ DEFAULT_FRIENDLY_ID_OPTIONS = {:method => nil, :use_slug => false, :max_length => 255, :reserved => [], :strip_diacritics => false, :scope => nil}.freeze
22
+ VALID_FRIENDLY_ID_KEYS = [:use_slug, :max_length, :reserved, :strip_diacritics, :scope].freeze
23
+
24
+ # Set up an ActiveRecord model to use a friendly_id.
25
+ #
26
+ # The column argument can be one of your model's columns, or a method
27
+ # you use to generate the slug.
28
+ #
29
+ # Options:
30
+ # * <tt>:use_slug</tt> - Defaults to false. Use slugs when you want to use a non-unique text field for friendly ids.
31
+ # * <tt>:max_length</tt> - Defaults to 255. The maximum allowed length for a slug.
32
+ # * <tt>:strip_diacritics</tt> - Defaults to false. If true, it will remove accents, umlauts, etc. from western characters.
33
+ # * <tt>:reseved</tt> - Array of words that are reserved and can't be used as slugs. If such a word is used, it will be treated the same as if that slug was already taken (numeric extension will be appended). Defaults to [].
34
+ def has_friendly_id(column, options = {})
35
+ options.assert_valid_keys VALID_FRIENDLY_ID_KEYS
36
+ options = DEFAULT_FRIENDLY_ID_OPTIONS.merge(options).merge(:column => column)
37
+ write_inheritable_attribute :friendly_id_options, options
38
+ class_inheritable_reader :friendly_id_options
39
+
40
+ if options[:use_slug]
41
+ has_many :slugs, :order => 'id DESC', :as => :sluggable, :dependent => :destroy
42
+ require 'friendly_id/sluggable_class_methods'
43
+ require 'friendly_id/sluggable_instance_methods'
44
+ extend SluggableClassMethods
45
+ include SluggableInstanceMethods
46
+ before_save :set_slug
47
+ else
48
+ require 'friendly_id/non_sluggable_class_methods'
49
+ require 'friendly_id/non_sluggable_instance_methods'
50
+ extend NonSluggableClassMethods
51
+ include NonSluggableInstanceMethods
52
+ end
53
+ end
54
+
55
+ end
56
+
57
+ end
58
+
59
+ if defined?(ActiveRecord)
60
+ FriendlyId::enable
61
+ end
@@ -0,0 +1,41 @@
1
+ module FriendlyId::NonSluggableClassMethods
2
+
3
+ def self.extended(base) #:nodoc:#
4
+ class << base
5
+ alias_method_chain :find_one, :friendly
6
+ alias_method_chain :find_some, :friendly
7
+ end
8
+ end
9
+
10
+ protected
11
+
12
+ def find_one_with_friendly(id, options) #:nodoc:#
13
+ if id.is_a?(String) && result = send("find_by_#{ friendly_id_options[:column] }", id, options)
14
+ result.send(:found_using_friendly_id=, true)
15
+ else
16
+ result = find_one_without_friendly id, options
17
+ end
18
+ result
19
+ end
20
+
21
+ def find_some_with_friendly(ids_and_names, options) #:nodoc:#
22
+ results_by_name = with_scope :find => options do
23
+ find :all, :conditions => ["#{ quoted_table_name }.#{ friendly_id_options[:column] } IN (?)", ids_and_names]
24
+ end
25
+
26
+ ids = ids_and_names - results_by_name.map { |r| r[ friendly_id_options[:column] ] }
27
+ results = results_by_name
28
+
29
+ results += with_scope :find => options do
30
+ find :all, :conditions => ["#{ quoted_table_name }.#{ primary_key } IN (?)", ids]
31
+ end unless ids.empty?
32
+
33
+ expected_size = options[:offset] ? ids_and_names.size - options[:offset] : ids_and_names.size
34
+ expected_size = options[:limit] if options[:limit] && expected_size > options[:limit]
35
+
36
+ raise ActiveRecord::RecordNotFound, "Couldn't find all #{ name.pluralize } with IDs (#{ ids_and_names * ', ' }) AND #{ sanitize_sql options[:conditions] } (found #{ results.size } results, but was looking for #{ expected_size })" if results.size != expected_size
37
+
38
+ results_by_name.each { |r| r.send(:found_using_friendly_id=, true) }
39
+ results
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ module FriendlyId::NonSluggableInstanceMethods
2
+
3
+ attr :found_using_friendly_id
4
+
5
+ # Was the record found using one of its friendly ids?
6
+ def found_using_friendly_id?
7
+ @found_using_friendly_id
8
+ end
9
+
10
+ # Was the record found using its numeric id?
11
+ def found_using_numeric_id?
12
+ !@found_using_friendly_id
13
+ end
14
+ alias has_better_id? found_using_numeric_id?
15
+
16
+ # Returns the friendly_id.
17
+ def friendly_id
18
+ send friendly_id_options[:column]
19
+ end
20
+ alias best_id friendly_id
21
+
22
+ # Returns the friendly id, or if none is available, the numeric id.
23
+ def to_param
24
+ friendly_id.to_s || id.to_s
25
+ end
26
+
27
+ private
28
+
29
+ def found_using_friendly_id=(value) #:nodoc#
30
+ @found_using_friendly_id = value
31
+ end
32
+
33
+ end
@@ -0,0 +1,36 @@
1
+ module FriendlyId
2
+
3
+ # A Shoulda[http://www.thoughtbot.com/projects/shoulda/] macros for testing
4
+ # models using FriendlyId.
5
+ module ShouldaMacros
6
+
7
+ # Ensure that a model is using FriendlyId.
8
+ def self.should_have_friendly_id(column, options = {})
9
+
10
+ options.assert_valid_keys(:use_slug)
11
+ klass = self.model_class
12
+
13
+ should "have friendly id for #{method}" do
14
+ assert_respond_to klass, :friendly_id_options,
15
+ "#{klass} does not respond to friendly_id_options"
16
+ assert_equal column, klass.friendly_id_options[:method]
17
+ end
18
+
19
+ if options[:use_slug]
20
+ should "include/extend friendly_id's sluggable modules" do
21
+ assert klass.extended_by.include?(FriendlyId::SluggableClassMethods),
22
+ "#{klass} does not extend FriendlyId::SluggableClassMethods"
23
+ assert klass.include?(FriendlyId::SluggableInstanceMethods),
24
+ "#{klass} not include FriendlyId::SluggableInstanceMethods"
25
+ end
26
+ else
27
+ should "include/extend friendly_id's non-sluggable modules" do
28
+ assert klass.extended_by.include?(FriendlyId::NonSluggableClassMethods),
29
+ "#{klass} does not extend FriendlyId::NonSluggableClassMethods"
30
+ assert klass.include?(FriendlyId::NonSluggableInstanceMethods),
31
+ "#{klass} not include FriendlyId::NonSluggableInstanceMethods"
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,90 @@
1
+ # A Slug is a unique, human-friendly identifier for an ActiveRecord.
2
+ class Slug < ActiveRecord::Base
3
+
4
+ belongs_to :sluggable, :polymorphic => true
5
+ validates_uniqueness_of :name, :scope => [:sluggable_type, :scope, :sequence]
6
+ before_create :set_sequence
7
+ before_save :check_for_blank_name
8
+
9
+ class << self
10
+
11
+ # Sanitizes and dasherizes string to make it safe for URL's.
12
+ #
13
+ # Example:
14
+ #
15
+ # slug.normalize('This... is an example!') # => "this-is-an-example"
16
+ #
17
+ # Note that Rails 2.2.x offers a parameterize method for this. It's not
18
+ # used here because it assumes you want to strip away accented characters,
19
+ # and this may not always be your desire.
20
+ #
21
+ # At the time of writing, it also handles several characters incorrectly,
22
+ # for instance replacing Icelandic's "thorn" character with "y" rather
23
+ # than "d." This might be pedantic, but I don't want to piss off the
24
+ # Vikings. The last time anyone pissed them off, they uleashed a wave of
25
+ # terror in Europe unlike anything ever seen before or after. I'm not
26
+ # taking any chances.
27
+ def normalize(slug_text)
28
+ return "" if slug_text.blank?
29
+ slug_text.
30
+ send(chars_func).
31
+ # For some reason Spanish ¡ and ¿ are not detected as non-word
32
+ # characters. Bug in Ruby?
33
+ normalize.gsub(/[\W|¡|¿]/u, ' ').
34
+ strip.
35
+ gsub(/\s+/u, '-').
36
+ gsub(/-\z/u, '').
37
+ downcase.
38
+ to_s
39
+ end
40
+
41
+ def parse(friendly_id)
42
+ name, sequence = friendly_id.split('--')
43
+ sequence ||= "1"
44
+ return name, sequence
45
+ end
46
+
47
+ # Remove diacritics (accents, umlauts, etc.) from the string.
48
+ def strip_diacritics(string)
49
+ require 'unicode'
50
+ Unicode::normalize_KD(string).unpack('U*').select { |cp|
51
+ cp < 0x300 || cp > 0x036F
52
+ }.pack('U*')
53
+ end
54
+
55
+ private
56
+
57
+ def chars_func
58
+ Rails.version =~ /2.2.[\d]*/ ? :mb_chars : :chars
59
+ rescue NoMethodError
60
+ :chars
61
+ end
62
+
63
+ end
64
+
65
+ # Whether or not this slug is the most recent of its owner's slugs.
66
+ def is_most_recent?
67
+ sluggable.slug == self
68
+ end
69
+
70
+ def to_friendly_id
71
+ sequence > 1 ? "#{name}--#{sequence}" : name
72
+ end
73
+
74
+ protected
75
+
76
+ # Raise a FriendlyId::SlugGenerationError if the slug name is blank.
77
+ def check_for_blank_name #:nodoc:#
78
+ if name.blank?
79
+ raise FriendlyId::SlugGenerationError.new("The slug text is blank.")
80
+ end
81
+ end
82
+
83
+ def set_sequence
84
+ last = Slug.find(:first, :conditions => { :name => name, :scope => scope,
85
+ :sluggable_type => sluggable_type}, :order => "sequence DESC",
86
+ :select => 'sequence')
87
+ self.sequence = last.sequence + 1 if last
88
+ end
89
+
90
+ end
@@ -0,0 +1,109 @@
1
+ module FriendlyId::SluggableClassMethods
2
+
3
+ def self.extended(base) #:nodoc:#
4
+
5
+ class << base
6
+ alias_method_chain :find_one, :friendly
7
+ alias_method_chain :find_some, :friendly
8
+ alias_method_chain :validate_find_options, :friendly
9
+ end
10
+
11
+ end
12
+
13
+ # Finds a single record using the friendly id, or the record's id.
14
+ def find_one_with_friendly(id_or_name, options) #:nodoc:#
15
+
16
+ scope = options.delete(:scope)
17
+ return find_one_without_friendly(id_or_name, options) if id_or_name.is_a?(Fixnum)
18
+
19
+ find_options = {:select => "#{self.table_name}.*"}
20
+ find_options[:joins] = :slugs unless options[:include] && [*options[:include]].flatten.include?(:slugs)
21
+
22
+ name, sequence = Slug.parse(id_or_name)
23
+
24
+ find_options[:conditions] = {
25
+ "#{Slug.table_name}.name" => name,
26
+ "#{Slug.table_name}.scope" => scope,
27
+ "#{Slug.table_name}.sequence" => sequence
28
+ }
29
+
30
+ result = with_scope(:find => find_options) { find_initial(options) }
31
+
32
+ if result
33
+ result.finder_slug_name = id_or_name
34
+ else
35
+ result = find_one_without_friendly id_or_name, options
36
+ end
37
+
38
+ result
39
+
40
+ end
41
+
42
+ # Finds multiple records using the friendly ids, or the records' ids.
43
+ def find_some_with_friendly(ids_and_names, options) #:nodoc:#
44
+
45
+ slugs, ids = get_slugs_and_ids(ids_and_names, options)
46
+ results = []
47
+
48
+ find_options = {:select => "#{self.table_name}.*"}
49
+ find_options[:joins] = :slugs unless options[:include] && [*options[:include]].flatten.include?(:slugs)
50
+ find_options[:conditions] = "#{quoted_table_name}.#{primary_key} IN (#{ids.empty? ? 'NULL' : ids.join(',')}) "
51
+ find_options[:conditions] << "OR #{Slug.quoted_table_name}.#{Slug.primary_key} IN (#{slugs.to_s(:db)})"
52
+
53
+ results = with_scope(:find => find_options) { find_every(options) }
54
+
55
+ # calculate expected size, taken from active_record/base.rb
56
+ expected = expected_size(ids_and_names, options)
57
+ if results.size != expected
58
+ raise ActiveRecord::RecordNotFound, "Couldn't find all #{ name.pluralize } with IDs (#{ ids_and_names * ', ' }) AND #{ sanitize_sql options[:conditions] } (found #{ results.size } results, but was looking for #{ expected })"
59
+ end
60
+
61
+ assign_finder_slugs(slugs, results)
62
+
63
+ results
64
+ end
65
+
66
+ def validate_find_options_with_friendly(options) #:nodoc:#
67
+ options.assert_valid_keys([:conditions, :include, :joins, :limit, :offset,
68
+ :order, :select, :readonly, :group, :from, :lock, :having, :scope])
69
+ end
70
+
71
+ private
72
+
73
+ # Assign finder slugs for the results found in find_some_with_friendly
74
+ def assign_finder_slugs(slugs, results) #:nodoc:#
75
+ slugs.each do |slug|
76
+ results.select { |r| r.id == slug.sluggable_id }.each do |result|
77
+ result.send(:finder_slug=, slug)
78
+ end
79
+ end
80
+ end
81
+
82
+ # Calculate expected result size for find_some_with_friendly
83
+ def expected_size(ids_and_names, options) #:nodoc:#
84
+ size = options[:offset] ? ids_and_names.size - options[:offset] : ids_and_names.size
85
+ size = options[:limit] if options[:limit] && size > options[:limit]
86
+ size
87
+ end
88
+
89
+ # Build arrays of slugs and ids, for the find_some_with_friendly method.
90
+ def get_slugs_and_ids(ids_and_names, options) #:nodoc:#
91
+ scope = options.delete(:scope)
92
+ slugs = []
93
+ ids = []
94
+ ids_and_names.each do |id_or_name|
95
+ name, sequence = Slug.parse id_or_name
96
+ slug = Slug.find(:first, :readonly => true, :conditions => {
97
+ :name => name,
98
+ :scope => scope,
99
+ :sequence => sequence,
100
+ :sluggable_type => base_class.name
101
+ })
102
+ # If the slug was found, add it to the array for later use. If not, and
103
+ # the id_or_name is a number, assume that it is a regular record id.
104
+ slug ? slugs << slug : (ids << id_or_name if id_or_name =~ /\A\d*\z/)
105
+ end
106
+ return slugs, ids
107
+ end
108
+
109
+ end