friendly_id 2.2.7 → 2.3.0

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 (73) hide show
  1. data/Changelog.md +225 -0
  2. data/Contributors.md +28 -0
  3. data/Guide.md +509 -0
  4. data/LICENSE +1 -1
  5. data/README.md +76 -0
  6. data/Rakefile +48 -15
  7. data/extras/bench.rb +59 -0
  8. data/extras/extras.rb +31 -0
  9. data/extras/prof.rb +14 -0
  10. data/extras/template-gem.rb +1 -1
  11. data/extras/template-plugin.rb +1 -1
  12. data/generators/friendly_id/friendly_id_generator.rb +1 -1
  13. data/generators/friendly_id/templates/create_slugs.rb +2 -2
  14. data/lib/friendly_id.rb +54 -63
  15. data/lib/friendly_id/active_record2.rb +47 -0
  16. data/lib/friendly_id/active_record2/configuration.rb +66 -0
  17. data/lib/friendly_id/active_record2/finders.rb +140 -0
  18. data/lib/friendly_id/active_record2/simple_model.rb +162 -0
  19. data/lib/friendly_id/active_record2/slug.rb +111 -0
  20. data/lib/friendly_id/active_record2/slugged_model.rb +317 -0
  21. data/lib/friendly_id/active_record2/tasks.rb +66 -0
  22. data/lib/friendly_id/active_record2/tasks/friendly_id.rake +19 -0
  23. data/lib/friendly_id/configuration.rb +132 -0
  24. data/lib/friendly_id/finders.rb +106 -0
  25. data/lib/friendly_id/slug_string.rb +292 -0
  26. data/lib/friendly_id/slugged.rb +91 -0
  27. data/lib/friendly_id/status.rb +35 -0
  28. data/lib/friendly_id/test.rb +168 -0
  29. data/lib/friendly_id/version.rb +5 -5
  30. data/rails/init.rb +2 -0
  31. data/test/active_record2/basic_slugged_model_test.rb +14 -0
  32. data/test/active_record2/cached_slug_test.rb +61 -0
  33. data/test/active_record2/core.rb +93 -0
  34. data/test/active_record2/custom_normalizer_test.rb +20 -0
  35. data/test/active_record2/custom_table_name_test.rb +22 -0
  36. data/test/active_record2/scoped_model_test.rb +111 -0
  37. data/test/active_record2/simple_test.rb +59 -0
  38. data/test/active_record2/slug_test.rb +34 -0
  39. data/test/active_record2/slugged.rb +30 -0
  40. data/test/active_record2/slugged_status_test.rb +61 -0
  41. data/test/active_record2/sti_test.rb +22 -0
  42. data/test/active_record2/support/database.mysql.yml +4 -0
  43. data/test/{support/database.yml.postgres → active_record2/support/database.postgres.yml} +0 -0
  44. data/test/{support/database.yml.sqlite3 → active_record2/support/database.sqlite3.yml} +0 -0
  45. data/test/{support → active_record2/support}/models.rb +28 -0
  46. data/test/active_record2/tasks_test.rb +82 -0
  47. data/test/active_record2/test_helper.rb +107 -0
  48. data/test/friendly_id_test.rb +23 -0
  49. data/test/slug_string_test.rb +74 -0
  50. data/test/test_helper.rb +7 -102
  51. metadata +64 -56
  52. data/History.txt +0 -194
  53. data/README.rdoc +0 -385
  54. data/generators/friendly_id_20_upgrade/friendly_id_20_upgrade_generator.rb +0 -12
  55. data/generators/friendly_id_20_upgrade/templates/upgrade_friendly_id_to_20.rb +0 -19
  56. data/init.rb +0 -1
  57. data/lib/friendly_id/helpers.rb +0 -12
  58. data/lib/friendly_id/non_sluggable_class_methods.rb +0 -34
  59. data/lib/friendly_id/non_sluggable_instance_methods.rb +0 -45
  60. data/lib/friendly_id/slug.rb +0 -98
  61. data/lib/friendly_id/sluggable_class_methods.rb +0 -110
  62. data/lib/friendly_id/sluggable_instance_methods.rb +0 -161
  63. data/lib/friendly_id/tasks.rb +0 -56
  64. data/lib/tasks/friendly_id.rake +0 -25
  65. data/lib/tasks/friendly_id.rb +0 -1
  66. data/test/cached_slug_test.rb +0 -109
  67. data/test/custom_slug_normalizer_test.rb +0 -36
  68. data/test/non_slugged_test.rb +0 -99
  69. data/test/scoped_model_test.rb +0 -64
  70. data/test/slug_test.rb +0 -105
  71. data/test/slugged_model_test.rb +0 -348
  72. data/test/sti_test.rb +0 -49
  73. data/test/tasks_test.rb +0 -105
@@ -1,25 +0,0 @@
1
- namespace :friendly_id do
2
- desc "Make slugs for a model."
3
- task :make_slugs => :environment do
4
- validate_model_given
5
- FriendlyId::Tasks.make_slugs(ENV["MODEL"]) do |r|
6
- puts "%s(%d) friendly_id set to '%s'" % [r.class.to_s, r.id, r.slug.name]
7
- end
8
- end
9
-
10
- desc "Regenereate slugs for a model."
11
- task :redo_slugs => :environment do
12
- validate_model_given
13
- FriendlyId::Tasks.delete_slugs_for(ENV["MODEL"])
14
- Rake::Task["friendly_id:make_slugs"].invoke
15
- end
16
-
17
- desc "Kill obsolete slugs older than DAYS=45 days."
18
- task :remove_old_slugs => :environment do
19
- FriendlyId::Tasks.delete_old_slugs(ENV["DAYS"], ENV["MODEL"])
20
- end
21
- end
22
-
23
- def validate_model_given
24
- raise 'USAGE: rake friendly_id:make_slugs MODEL=MyModelName' if ENV["MODEL"].nil?
25
- end
@@ -1 +0,0 @@
1
- load 'tasks/friendly_id.rake'
@@ -1,109 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class CachedSlugModelTest < Test::Unit::TestCase
4
-
5
- context "A slugged model with a cached_slugs column" do
6
-
7
- setup do
8
- @paris = City.new(:name => "Paris")
9
- @paris.save!
10
- end
11
-
12
- teardown do
13
- City.delete_all
14
- Slug.delete_all
15
- end
16
-
17
- should "have a slug" do
18
- assert_not_nil @paris.slug
19
- end
20
-
21
- should "have a cached slug" do
22
- assert_not_nil @paris.my_slug
23
- end
24
-
25
- should "have a to_param method that returns the cached slug" do
26
- assert_equal "paris", @paris.to_param
27
- end
28
-
29
- should "protect the cached slug value" do
30
- @paris.update_attributes(:my_slug => "Madrid")
31
- @paris.reload
32
- assert_equal "paris", @paris.my_slug
33
- end
34
-
35
- should "cache the incremented sequence for duplicate slug names" do
36
- paris2 = City.create!(:name => "Paris")
37
- assert_equal 2, paris2.slug.sequence
38
- assert_equal "paris--2", paris2.my_slug
39
- end
40
-
41
- should "not update the cached slug column if it has not changed" do
42
- @paris.population = 10_000_000
43
- @paris.expects(:my_slug=).never
44
- @paris.save
45
- end
46
-
47
-
48
- context "found by its friendly id" do
49
-
50
- setup do
51
- @paris = City.find(@paris.friendly_id)
52
- end
53
-
54
- should "not indicate that it has a better id" do
55
- assert !@paris.has_better_id?
56
- end
57
-
58
- end
59
-
60
- context "found by its numeric id" do
61
-
62
- setup do
63
- @paris = City.find(@paris.id)
64
- end
65
-
66
- should "indicate that it has a better id" do
67
- assert @paris.has_better_id?
68
- end
69
-
70
- end
71
-
72
-
73
- context "with a new slug" do
74
-
75
- setup do
76
- @paris.name = "Paris, France"
77
- @paris.save!
78
- @paris.reload
79
- end
80
-
81
- should "have its cached slug updated" do
82
- assert_equal "paris-france", @paris.my_slug
83
- end
84
-
85
- should "have its cached slug synchronized with its friendly_id" do
86
- assert_equal @paris.my_slug, @paris.friendly_id
87
- end
88
-
89
- end
90
-
91
-
92
- context "with a cached_slug column" do
93
-
94
- setup do
95
- District.delete_all
96
- @district = District.new(:name => "Latin Quarter")
97
- @district.save!
98
- end
99
-
100
- should "have its cached_slug filled automatically" do
101
- assert_equal @district.cached_slug, "latin-quarter"
102
- end
103
-
104
- end
105
-
106
- end
107
-
108
- end
109
-
@@ -1,36 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class CustomSlugNormalizerTest < Test::Unit::TestCase
4
-
5
- context "A slugged model using a custom slug generator" do
6
-
7
- setup do
8
- Person.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :name, :use_slug => true)
9
- end
10
-
11
- teardown do
12
- Person.delete_all
13
- Slug.delete_all
14
- end
15
-
16
- should "invoke the block code" do
17
- @person = Person.create!(:name => "Joe Schmoe")
18
- assert_equal "JOE SCHMOE", @person.friendly_id
19
- end
20
-
21
- should "respect the max_length option" do
22
- Person.friendly_id_options = Person.friendly_id_options.merge(:max_length => 3)
23
- @person = Person.create!(:name => "Joe Schmoe")
24
- assert_equal "JOE", @person.friendly_id
25
- end
26
-
27
- should "respect the reserved option" do
28
- Person.friendly_id_options = Person.friendly_id_options.merge(:reserved => ["JOE"])
29
- assert_raises FriendlyId::SlugGenerationError do
30
- Person.create!(:name => "Joe")
31
- end
32
- end
33
-
34
- end
35
-
36
- end
@@ -1,99 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class NonSluggedTest < Test::Unit::TestCase
4
-
5
- context "A non-slugged model with default FriendlyId options" do
6
-
7
- setup do
8
- @user = User.create!(:name => "joe")
9
- end
10
-
11
- teardown do
12
- User.delete_all
13
- end
14
-
15
- should "have friendly_id options" do
16
- assert_not_nil User.friendly_id_options
17
- end
18
-
19
- should "not have a slug" do
20
- assert !@user.respond_to?(:slug)
21
- end
22
-
23
- should "be findable by its friendly_id" do
24
- assert User.find(@user.friendly_id)
25
- end
26
-
27
- should "be findable by its regular id" do
28
- assert User.find(@user.id)
29
- end
30
-
31
- should "respect finder conditions" do
32
- assert_raises ActiveRecord::RecordNotFound do
33
- User.find(@user.friendly_id, :conditions => "1 = 2")
34
- end
35
- end
36
-
37
- should "indicate if it was found by its friendly id" do
38
- user = User.find(@user.friendly_id)
39
- assert user.found_using_friendly_id?
40
- end
41
-
42
- should "indicate if it was found by its numeric id" do
43
- user = User.find(@user.id)
44
- assert user.found_using_numeric_id?
45
- end
46
-
47
- should "indicate if it has a better id" do
48
- user = User.find(@user.id)
49
- assert user.has_better_id?
50
- end
51
-
52
- should "not validate if the friendly_id text is reserved" do
53
- user = User.new(:name => "new")
54
- assert !user.valid?
55
- end
56
-
57
- should "have always string for a friendly_id" do
58
- assert_equal String, @user.to_param.class
59
- end
60
-
61
- should "return its id if the friendly_id is null" do
62
- @user.name = nil
63
- assert_equal @user.id.to_s, @user.to_param
64
- end
65
-
66
-
67
- context "when using an array as the find argument" do
68
-
69
- setup do
70
- @user2 = User.create(:name => "jane")
71
- end
72
-
73
- should "return results" do
74
- assert_equal 2, User.find([@user.friendly_id, @user2.friendly_id]).size
75
- end
76
-
77
- should "not allow mixed friendly and non-friendly ids for the same record" do
78
- assert_raises ActiveRecord::RecordNotFound do
79
- User.find([@user.id, @user.friendly_id]).size
80
- end
81
- end
82
-
83
- should "raise an error when all records are not found" do
84
- assert_raises ActiveRecord::RecordNotFound do
85
- User.find(['bad', 'bad2'])
86
- end
87
- end
88
-
89
- should "indicate if the results were found using a friendly_id" do
90
- users = User.find([@user.id, @user2.friendly_id], :order => "name ASC")
91
- assert users[0].found_using_friendly_id?
92
- assert users[1].found_using_numeric_id?
93
- end
94
-
95
- end
96
-
97
- end
98
-
99
- end
@@ -1,64 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
-
4
- class ScopedModelTest < Test::Unit::TestCase
5
-
6
- context "A slugged model that uses a scope" do
7
-
8
- setup do
9
- @usa = Country.create!(:name => "USA")
10
- @canada = Country.create!(:name => "Canada")
11
- @resident = Resident.create!(:name => "John Smith", :country => @usa)
12
- @resident2 = Resident.create!(:name => "John Smith", :country => @canada)
13
- end
14
-
15
- teardown do
16
- Resident.delete_all
17
- Country.delete_all
18
- Slug.delete_all
19
- end
20
-
21
- should "should not show the scope in the friendly_id" do
22
- assert_equal "john-smith", @resident.friendly_id
23
- assert_equal "john-smith", @resident2.friendly_id
24
- end
25
-
26
- should "find all scoped records without scope" do
27
- assert_equal 2, Resident.find(:all, @resident.friendly_id).size
28
- end
29
-
30
- should "find a single scoped records with a scope as a string" do
31
- assert Resident.find(@resident.friendly_id, :scope => @resident.country.to_param)
32
- end
33
-
34
- should "find a single scoped records with a scope" do
35
- assert Resident.find(@resident.friendly_id, :scope => @resident.country)
36
- end
37
-
38
- should "raise an error when finding a single scoped record with no scope" do
39
- assert_raises ActiveRecord::RecordNotFound do
40
- Resident.find(@resident.friendly_id)
41
- end
42
- end
43
-
44
- should "append scope error info when missing scope causes a find to fail" do
45
- begin
46
- Resident.find(@resident.friendly_id)
47
- fail "The find should not have succeeded"
48
- rescue ActiveRecord::RecordNotFound => e
49
- assert_match /expected scope/, e.message
50
- end
51
- end
52
-
53
- should "append scope error info when the scope value causes a find to fail" do
54
- begin
55
- Resident.find(@resident.friendly_id, :scope => "badscope")
56
- fail "The find should not have succeeded"
57
- rescue ActiveRecord::RecordNotFound => e
58
- assert_match /scope=badscope/, e.message
59
- end
60
- end
61
-
62
- end
63
-
64
- end
data/test/slug_test.rb DELETED
@@ -1,105 +0,0 @@
1
- # encoding: utf-8
2
- require File.dirname(__FILE__) + '/test_helper'
3
-
4
- class SlugTest < Test::Unit::TestCase
5
-
6
- context "a slug" do
7
-
8
- teardown do
9
- Slug.delete_all
10
- Post.delete_all
11
- end
12
-
13
- should "indicate if it is the most recent slug" do
14
- post = Post.create!(:name => "test title")
15
- post.name = "a new title"
16
- post.save!
17
- assert post.slugs.last.is_most_recent?
18
- assert !post.slugs.first.is_most_recent?
19
- end
20
-
21
- end
22
-
23
- context "the Slug class" do
24
-
25
- should "parse the slug name and sequence" do
26
- assert_equal ["test", "2"], Slug::parse("test--2")
27
- end
28
-
29
- should "parse with a default sequence of 1" do
30
- assert_equal ["test", "1"], Slug::parse("test")
31
- end
32
-
33
- should "should strip diacritics" do
34
- assert_equal "acai", Slug::strip_diacritics("açaí")
35
- end
36
-
37
- should "strip diacritics correctly " do
38
- input = "ÀÁÂÃÄÅÆÇÈÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
39
- output = Slug::strip_diacritics(input).split(//)
40
- expected = "AAAAAAAECEEEIIIIDNOOOOOOUUUUYThssaaaaaaaeceeeeiiiidnoooooouuuuythy".split(//)
41
- output.each_index do |i|
42
- assert_equal expected[i], output[i]
43
- end
44
- end
45
-
46
- end
47
-
48
- context "the Slug class's to_friendly_id method" do
49
-
50
- should "include the sequence if the sequence is greater than 1" do
51
- slug = Slug.new(:name => "test", :sequence => 2)
52
- assert_equal "test--2", slug.to_friendly_id
53
- end
54
-
55
- should "not include the sequence if the sequence is 1" do
56
- slug = Slug.new(:name => "test", :sequence => 1)
57
- assert_equal "test", slug.to_friendly_id
58
- end
59
-
60
- end
61
-
62
- context "the Slug class's normalize method" do
63
-
64
- should "should lowercase strings" do
65
- assert_match /abc/, Slug::normalize("ABC")
66
- end
67
-
68
- should "should replace whitespace with dashes" do
69
- assert_match /a-b/, Slug::normalize("a b")
70
- end
71
-
72
- should "should replace 2spaces with 1dash" do
73
- assert_match /a-b/, Slug::normalize("a b")
74
- end
75
-
76
- should "should remove punctuation" do
77
- assert_match /abc/, Slug::normalize('abc!@#$%^&*•¶§∞¢££¡¿()><?"":;][]\.,/')
78
- end
79
-
80
- should "should strip trailing space" do
81
- assert_match /ab/, Slug::normalize("ab ")
82
- end
83
-
84
- should "should strip leading space" do
85
- assert_match /ab/, Slug::normalize(" ab")
86
- end
87
-
88
- should "should strip trailing slashes" do
89
- assert_match /ab/, Slug::normalize("ab-")
90
- end
91
-
92
- should "should strip leading slashes" do
93
- assert_match /ab/, Slug::normalize("-ab")
94
- end
95
-
96
- should "should not modify valid name strings" do
97
- assert_match /a-b-c-d/, Slug::normalize("a-b-c-d")
98
- end
99
-
100
- should "work with non roman chars" do
101
- assert_equal "検-索", Slug::normalize("検 索")
102
- end
103
-
104
- end
105
- end