cmassimo-friendly_id 3.0.4.2

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/Changelog.md +277 -0
  2. data/Contributors.md +39 -0
  3. data/Guide.md +561 -0
  4. data/LICENSE +19 -0
  5. data/README.md +83 -0
  6. data/Rakefile +66 -0
  7. data/extras/README.txt +3 -0
  8. data/extras/bench.rb +36 -0
  9. data/extras/extras.rb +38 -0
  10. data/extras/prof.rb +14 -0
  11. data/extras/template-gem.rb +26 -0
  12. data/extras/template-plugin.rb +28 -0
  13. data/generators/friendly_id/friendly_id_generator.rb +30 -0
  14. data/generators/friendly_id/templates/create_slugs.rb +18 -0
  15. data/lib/friendly_id.rb +73 -0
  16. data/lib/friendly_id/active_record.rb +52 -0
  17. data/lib/friendly_id/active_record_adapter/configuration.rb +67 -0
  18. data/lib/friendly_id/active_record_adapter/finders.rb +156 -0
  19. data/lib/friendly_id/active_record_adapter/simple_model.rb +123 -0
  20. data/lib/friendly_id/active_record_adapter/slug.rb +66 -0
  21. data/lib/friendly_id/active_record_adapter/slugged_model.rb +238 -0
  22. data/lib/friendly_id/active_record_adapter/tasks.rb +69 -0
  23. data/lib/friendly_id/configuration.rb +113 -0
  24. data/lib/friendly_id/finders.rb +109 -0
  25. data/lib/friendly_id/railtie.rb +20 -0
  26. data/lib/friendly_id/sequel.rb +5 -0
  27. data/lib/friendly_id/slug_string.rb +391 -0
  28. data/lib/friendly_id/slugged.rb +102 -0
  29. data/lib/friendly_id/status.rb +35 -0
  30. data/lib/friendly_id/test.rb +291 -0
  31. data/lib/friendly_id/version.rb +9 -0
  32. data/lib/generators/friendly_id_generator.rb +25 -0
  33. data/lib/tasks/friendly_id.rake +19 -0
  34. data/rails/init.rb +2 -0
  35. data/test/active_record_adapter/ar_test_helper.rb +119 -0
  36. data/test/active_record_adapter/basic_slugged_model_test.rb +14 -0
  37. data/test/active_record_adapter/cached_slug_test.rb +61 -0
  38. data/test/active_record_adapter/core.rb +98 -0
  39. data/test/active_record_adapter/custom_normalizer_test.rb +20 -0
  40. data/test/active_record_adapter/custom_table_name_test.rb +22 -0
  41. data/test/active_record_adapter/scoped_model_test.rb +118 -0
  42. data/test/active_record_adapter/simple_test.rb +76 -0
  43. data/test/active_record_adapter/slug_test.rb +34 -0
  44. data/test/active_record_adapter/slugged.rb +30 -0
  45. data/test/active_record_adapter/slugged_status_test.rb +25 -0
  46. data/test/active_record_adapter/sti_test.rb +22 -0
  47. data/test/active_record_adapter/support/database.jdbcsqlite3.yml +2 -0
  48. data/test/active_record_adapter/support/database.mysql.yml +4 -0
  49. data/test/active_record_adapter/support/database.postgres.yml +6 -0
  50. data/test/active_record_adapter/support/database.sqlite3.yml +2 -0
  51. data/test/active_record_adapter/support/models.rb +87 -0
  52. data/test/active_record_adapter/tasks_test.rb +82 -0
  53. data/test/friendly_id_test.rb +55 -0
  54. data/test/slug_string_test.rb +88 -0
  55. data/test/test_helper.rb +15 -0
  56. metadata +168 -0
@@ -0,0 +1,14 @@
1
+ require File.expand_path('../ar_test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module ActiveRecordAdapter
6
+ class BasicSluggedModelTest < ::Test::Unit::TestCase
7
+ include FriendlyId::Test::Generic
8
+ include FriendlyId::Test::Slugged
9
+ include FriendlyId::Test::ActiveRecordAdapter::Slugged
10
+ include FriendlyId::Test::ActiveRecordAdapter::Core
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,61 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module ActiveRecordAdapter
6
+
7
+ class CachedSlugTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::Generic
10
+ include FriendlyId::Test::Slugged
11
+ include FriendlyId::Test::ActiveRecordAdapter::Slugged
12
+ include FriendlyId::Test::ActiveRecordAdapter::Core
13
+
14
+ def klass
15
+ District
16
+ end
17
+
18
+ def other_class
19
+ Post
20
+ end
21
+
22
+ def cached_slug
23
+ instance.send(cache_column)
24
+ end
25
+
26
+ def cache_column
27
+ klass.friendly_id_config.cache_column
28
+ end
29
+
30
+ test "should have a cached_slug" do
31
+ assert_equal cached_slug, instance.slug.to_friendly_id
32
+ end
33
+
34
+ test "should protect the cached slug value" do
35
+ old_value = cached_slug
36
+ instance.update_attributes(cache_column => "Madrid")
37
+ instance.reload
38
+ assert_equal old_value, cached_slug
39
+ end
40
+
41
+ test "should update the cached slug when updating the slug" do
42
+ instance.update_attributes(:name => "new name")
43
+ assert_equal instance.slug.to_friendly_id, cached_slug
44
+ end
45
+
46
+ test "should not update the cached slug column if it has not changed" do
47
+ instance.note = "a note"
48
+ instance.expects("#{cache_column}=".to_sym).never
49
+ instance.save!
50
+ end
51
+
52
+ test "should cache the incremented sequence for duplicate slug names" do
53
+ instance_2 = klass.create!(:name => instance.name)
54
+ assert_match(/2\z/, instance_2.send(cache_column))
55
+ end
56
+
57
+ end
58
+ end
59
+ end
60
+ end
61
+
@@ -0,0 +1,98 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+ module FriendlyId
4
+
5
+ module Test
6
+
7
+ module ActiveRecordAdapter
8
+
9
+ module Core
10
+
11
+ def teardown
12
+ klass.delete_all
13
+ other_class.delete_all
14
+ Slug.delete_all
15
+ end
16
+
17
+ def find_method
18
+ :find
19
+ end
20
+
21
+ def create_method
22
+ :create!
23
+ end
24
+
25
+ def delete_all_method
26
+ :delete_all
27
+ end
28
+
29
+ def save_method
30
+ :save!
31
+ end
32
+
33
+ def validation_exceptions
34
+ [ActiveRecord::RecordInvalid, FriendlyId::ReservedError, FriendlyId::BlankError]
35
+ end
36
+
37
+ test "should return their friendly_id for #to_param" do
38
+ assert_match(instance.friendly_id, instance.to_param)
39
+ end
40
+
41
+ test "instances should be findable by their own instance" do
42
+ assert_equal instance, klass.find(instance)
43
+ end
44
+
45
+ test "instances should be findable by an array of friendly_ids" do
46
+ second = klass.create!(:name => "second_instance")
47
+ third = klass.create!(:name => "third_instance")
48
+ assert_equal 2, klass.find([instance.friendly_id, second.friendly_id]).size
49
+ end
50
+
51
+ test "instances should be findable by an array of numeric ids" do
52
+ second = klass.create!(:name => "second_instance")
53
+ third = klass.create!(:name => "third_instance")
54
+ assert_equal 2, klass.find([instance.id.to_i, second.id.to_i]).size
55
+ end
56
+
57
+ test "instances should be findable by an array of numeric ids as strings" do
58
+ second = klass.create!(:name => "second_instance")
59
+ third = klass.create!(:name => "third_instance")
60
+ assert_equal 2, klass.find([instance.id.to_s, second.id.to_s]).size
61
+ end
62
+
63
+ test "instances should be findable by an array of instances" do
64
+ second = klass.create!(:name => "second_instance")
65
+ third = klass.create!(:name => "third_instance")
66
+ assert_equal 2, klass.find([instance, second]).size
67
+ end
68
+
69
+ test "instances should be findable by an array of mixed types" do
70
+ second = klass.create!(:name => "second_instance")
71
+ third = klass.create!(:name => "third_instance")
72
+ assert_equal 2, klass.find([instance.friendly_id, second]).size
73
+ end
74
+
75
+ test "models should raise an error when not all records are found" do
76
+ assert_raises(ActiveRecord::RecordNotFound) do
77
+ klass.find([instance.friendly_id, 'bad-friendly-id'])
78
+ end
79
+ end
80
+
81
+ test "models should respect finder conditions" do
82
+ assert_raise ActiveRecord::RecordNotFound do
83
+ klass.find(instance.friendly_id, :conditions => "1 = 2")
84
+ end
85
+ end
86
+
87
+ # This emulates a fairly common issue where id's generated by fixtures are very high.
88
+ test "should continue to admit very large ids" do
89
+ klass.connection.execute("INSERT INTO #{klass.table_name} (id, name) VALUES (2047483647, 'An instance')")
90
+ assert_nothing_raised do
91
+ klass.base_class.find(2047483647)
92
+ end
93
+ end
94
+
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,20 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module ActiveRecordAdapter
6
+
7
+ class CustomNormalizerTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::ActiveRecordAdapter::Core
10
+ include FriendlyId::Test::ActiveRecordAdapter::Slugged
11
+ include FriendlyId::Test::CustomNormalizer
12
+
13
+ def klass
14
+ Person
15
+ end
16
+
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,22 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module ActiveRecordAdapter
6
+
7
+ class CustomTableNameTest < ::Test::Unit::TestCase
8
+
9
+ include FriendlyId::Test::Generic
10
+ include FriendlyId::Test::Slugged
11
+ include FriendlyId::Test::ActiveRecordAdapter::Slugged
12
+ include FriendlyId::Test::ActiveRecordAdapter::Core
13
+
14
+ def klass
15
+ Place
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,118 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+
6
+ class ScopedModelTest < ::Test::Unit::TestCase
7
+
8
+ include FriendlyId::Test::Generic
9
+ include FriendlyId::Test::Slugged
10
+ include FriendlyId::Test::ActiveRecordAdapter::Slugged
11
+ include FriendlyId::Test::ActiveRecordAdapter::Core
12
+
13
+ def setup
14
+ @user = User.create!(:name => "john")
15
+ @house = House.create!(:name => "123 Main", :user => @user)
16
+ @usa = Country.create!(:name => "USA")
17
+ @canada = Country.create!(:name => "Canada")
18
+ @resident = Resident.create!(:name => "John Smith", :country => @usa)
19
+ @resident2 = Resident.create!(:name => "John Smith", :country => @canada)
20
+ @owner = Company.create!(:name => "Acme Events")
21
+ @site = Site.create!(:name => "Downtown Venue", :owner => @owner)
22
+ end
23
+
24
+ def teardown
25
+ Resident.delete_all
26
+ Country.delete_all
27
+ User.delete_all
28
+ House.delete_all
29
+ Slug.delete_all
30
+ end
31
+
32
+ test "a slugged model should auto-detect that it is being used as a parent scope" do
33
+ assert_equal [Resident], Country.friendly_id_config.child_scopes
34
+ end
35
+
36
+ test "a slugged model should update its child model's scopes when its friendly_id changes" do
37
+ @usa.update_attributes(:name => "United States")
38
+ assert_equal "united-states", @usa.to_param
39
+ assert_equal "united-states", @resident.slugs(true).first.scope
40
+ end
41
+
42
+ test "a non-slugged model should auto-detect that it is being used as a parent scope" do
43
+ assert_equal [House], User.friendly_id_config.child_scopes
44
+ end
45
+
46
+ test "should update the slug when the scope changes" do
47
+ @resident.update_attributes! :country => Country.create!(:name => "Argentina")
48
+ assert_equal "argentina", @resident.slugs(true).first.scope
49
+ end
50
+
51
+ test "updating only the scope should not append sequence to friendly_id" do
52
+ old_friendly_id = @resident.friendly_id
53
+ @resident.update_attributes! :country => Country.create!(:name => "Argentina")
54
+ assert_equal old_friendly_id, @resident.friendly_id
55
+ end
56
+
57
+ test "updating the scope should increment sequence to avoid conflicts" do
58
+ old_friendly_id = @resident.friendly_id
59
+ @resident.update_attributes! :country => @canada
60
+ assert_equal "#{old_friendly_id}--2", @resident.friendly_id
61
+ assert_equal "canada", @resident.slugs(true).first.scope
62
+ end
63
+
64
+ test "a non-slugged model should update its child model's scopes when its friendly_id changes" do
65
+ @user.update_attributes(:name => "jack")
66
+ assert_equal "jack", @user.to_param
67
+ assert_equal "jack", @house.slugs(true).first.scope
68
+ end
69
+
70
+ test "should should not show the scope in the friendly_id" do
71
+ assert_equal "john-smith", @resident.friendly_id
72
+ assert_equal "john-smith", @resident2.friendly_id
73
+ end
74
+
75
+ test "should find all scoped records without scope" do
76
+ assert_equal 2, Resident.find(:all, @resident.friendly_id).size
77
+ end
78
+
79
+ test "should find a single scoped record with a scope as a string" do
80
+ assert Resident.find(@resident.friendly_id, :scope => @resident.country)
81
+ end
82
+
83
+ test "should find a single scoped record with a scope" do
84
+ assert Resident.find(@resident.friendly_id, :scope => @resident.country)
85
+ end
86
+
87
+ test "should raise an error when finding a single scoped record with no scope" do
88
+ assert_raises ActiveRecord::RecordNotFound do
89
+ Resident.find(@resident.friendly_id)
90
+ end
91
+ end
92
+
93
+ test "should append scope error info when missing scope causes a find to fail" do
94
+ begin
95
+ Resident.find(@resident.friendly_id)
96
+ fail "The find should not have succeeded"
97
+ rescue ActiveRecord::RecordNotFound => e
98
+ assert_match(/scope: expected/, e.message)
99
+ end
100
+ end
101
+
102
+ test "should append scope error info when the scope value causes a find to fail" do
103
+ begin
104
+ Resident.find(@resident.friendly_id, :scope => "badscope")
105
+ fail "The find should not have succeeded"
106
+ rescue ActiveRecord::RecordNotFound => e
107
+ assert_match(/scope: badscope/, e.message)
108
+ end
109
+ end
110
+
111
+ test "should update the sluggable field when a polymorphic relationship exists" do
112
+ @site.update_attributes(:name => "Uptown Venue")
113
+ assert_equal "Uptown Venue", @site.name
114
+ end
115
+
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,76 @@
1
+ require File.expand_path('../ar_test_helper', __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module ActiveRecordAdapter
6
+ module Simple
7
+
8
+ module SimpleTest
9
+ def klass
10
+ @klass ||= User
11
+ end
12
+
13
+ def instance
14
+ @instance ||= User.create! :name => "hello world"
15
+ end
16
+
17
+ def other_class
18
+ Author
19
+ end
20
+ end
21
+
22
+ class StatusTest < ::Test::Unit::TestCase
23
+
24
+ include SimpleTest
25
+
26
+ def setup
27
+ User.delete_all
28
+ end
29
+
30
+ test "should default to not friendly" do
31
+ assert !status.friendly?
32
+ end
33
+
34
+ test "should default to numeric" do
35
+ assert status.numeric?
36
+ end
37
+
38
+ test "should be friendly if name is set" do
39
+ status.name = "name"
40
+ assert status.friendly?
41
+ end
42
+
43
+ test "should be best if it is numeric, but record has no friendly_id" do
44
+ instance.send("#{klass.friendly_id_config.column}=", nil)
45
+ assert status.best?
46
+ end
47
+
48
+ def status
49
+ @status ||= instance.friendly_id_status
50
+ end
51
+
52
+ end
53
+
54
+ class BasicTest < ::Test::Unit::TestCase
55
+ include FriendlyId::Test::Generic
56
+ include FriendlyId::Test::Simple
57
+ include FriendlyId::Test::ActiveRecordAdapter::Core
58
+ include SimpleTest
59
+
60
+ test "status should be friendly when found using friendly id" do
61
+ record = klass.send(find_method, instance.friendly_id)
62
+ assert record.friendly_id_status.friendly?
63
+ end
64
+
65
+ test "status should not be friendly when found using numeric id" do
66
+ record = klass.send(find_method, instance.id)
67
+ assert !record.friendly_id_status.friendly?
68
+ end
69
+
70
+ end
71
+
72
+ end
73
+ end
74
+ end
75
+ end
76
+
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+ require File.expand_path("../ar_test_helper", __FILE__)
3
+
4
+ module FriendlyId
5
+ module Test
6
+
7
+ class SlugTest < ::Test::Unit::TestCase
8
+
9
+ def teardown
10
+ Slug.delete_all
11
+ Post.delete_all
12
+ end
13
+
14
+ test "should indicate if it is the most recent slug" do
15
+ post = Post.create!(:name => "test title")
16
+ post.name = "a new title"
17
+ post.save!
18
+ assert post.slugs.first.current?
19
+ assert !post.slugs.last.current?
20
+ end
21
+
22
+ test "should include the sequence if the sequence is greater than 1" do
23
+ slug = Slug.new(:name => "test", :sluggable => Post.new, :sequence => 2)
24
+ assert_equal "test--2", slug.to_friendly_id
25
+ end
26
+
27
+ test "should not include the sequence if the sequence is 1" do
28
+ slug = Slug.new(:name => "test", :sluggable => Post.new, :sequence => 1)
29
+ assert_equal "test", slug.to_friendly_id
30
+ end
31
+
32
+ end
33
+ end
34
+ end