dougcole-friendly_id 2.0.5 → 2.0.6

Sign up to get free protection for your applications and to get access to all the features.
Files changed (43) hide show
  1. data/History.txt +20 -0
  2. data/Manifest.txt +10 -18
  3. data/README.rdoc +34 -5
  4. data/Rakefile +8 -0
  5. data/VERSION.yml +1 -1
  6. data/lib/friendly_id.rb +33 -13
  7. data/lib/friendly_id/non_sluggable_class_methods.rb +3 -3
  8. data/lib/friendly_id/non_sluggable_instance_methods.rb +9 -1
  9. data/lib/friendly_id/slug.rb +14 -12
  10. data/lib/friendly_id/sluggable_class_methods.rb +14 -3
  11. data/lib/friendly_id/sluggable_instance_methods.rb +11 -4
  12. data/lib/friendly_id/version.rb +1 -1
  13. data/test/custom_slug_normalizer_test.rb +35 -0
  14. data/test/models/book.rb +2 -0
  15. data/test/{fixtures → models}/country.rb +0 -0
  16. data/test/models/novel.rb +3 -0
  17. data/test/{fixtures → models}/person.rb +0 -0
  18. data/test/models/post.rb +3 -0
  19. data/test/models/thing.rb +6 -0
  20. data/test/{fixtures → models}/user.rb +0 -0
  21. data/test/non_slugged_test.rb +71 -60
  22. data/test/schema.rb +29 -20
  23. data/test/scoped_model_test.rb +43 -13
  24. data/test/slug_test.rb +93 -74
  25. data/test/slugged_model_test.rb +263 -0
  26. data/test/sti_test.rb +48 -0
  27. data/test/test_helper.rb +30 -29
  28. metadata +15 -20
  29. data/lib/friendly_id/shoulda_macros.rb +0 -36
  30. data/test/database.yml +0 -3
  31. data/test/fixtures/countries.yml +0 -4
  32. data/test/fixtures/people.yml +0 -7
  33. data/test/fixtures/post.rb +0 -3
  34. data/test/fixtures/posts.yml +0 -23
  35. data/test/fixtures/slugs.yml +0 -53
  36. data/test/fixtures/users.yml +0 -7
  37. data/test/rails/2.x/app/controllers/application.rb +0 -0
  38. data/test/rails/2.x/config/boot.rb +0 -109
  39. data/test/rails/2.x/config/database.yml +0 -3
  40. data/test/rails/2.x/config/environment.rb +0 -7
  41. data/test/rails/2.x/config/environments/test.rb +0 -6
  42. data/test/rails/2.x/config/routes.rb +0 -0
  43. data/test/sluggable_test.rb +0 -185
@@ -0,0 +1,2 @@
1
+ class Book < ActiveRecord::Base
2
+ end
File without changes
@@ -0,0 +1,3 @@
1
+ class Novel < Book
2
+ has_friendly_id :title, :use_slug => true
3
+ end
File without changes
@@ -0,0 +1,3 @@
1
+ class Post < ActiveRecord::Base
2
+ has_friendly_id :title, :use_slug => true
3
+ end
@@ -0,0 +1,6 @@
1
+ require 'digest/sha1'
2
+ class Thing < ActiveRecord::Base
3
+ has_friendly_id :name, :use_slug => true do |text|
4
+ Digest::SHA1::hexdigest(text)
5
+ end
6
+ end
File without changes
@@ -2,84 +2,95 @@ require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
3
  class NonSluggedTest < Test::Unit::TestCase
4
4
 
5
- fixtures :users
5
+ context "A non-slugged model with default FriendlyId options" do
6
6
 
7
- def setup
8
- end
7
+ setup do
8
+ User.delete_all
9
+ @user = User.create!(:login => "joe", :email => "joe@example.org")
10
+ end
9
11
 
10
- def test_should_find_user_using_friendly_id
11
- assert User.find(users(:joe).friendly_id)
12
- end
12
+ should "have friendly_id options" do
13
+ assert_not_nil User.friendly_id_options
14
+ end
13
15
 
14
- def test_should_find_users_using_friendly_id
15
- assert User.find([users(:joe).friendly_id])
16
- end
16
+ should "not have a slug" do
17
+ assert !@user.respond_to?(:slug)
18
+ end
17
19
 
18
- def test_to_param_should_return_a_string
19
- assert_equal String, users(:joe).to_param.class
20
- end
20
+ should "be findable by its friendly_id" do
21
+ assert User.find(@user.friendly_id)
22
+ end
21
23
 
22
- def test_should_not_find_users_using_non_existent_friendly_ids
23
- assert_raises ActiveRecord::RecordNotFound do
24
- User.find(['bad', 'bad2'])
24
+ should "be findable by its regular id" do
25
+ assert User.find(@user.id)
25
26
  end
26
- end
27
-
28
- def test_finding_by_array_with_friendly_and_non_friendly_id_for_same_record_raises_error
29
- assert_raises ActiveRecord::RecordNotFound do
30
- User.find([users(:joe).id, "joe"]).size
27
+
28
+ should "respect finder conditions" do
29
+ assert_raises ActiveRecord::RecordNotFound do
30
+ User.find(@user.friendly_id, :conditions => "1 = 2")
31
+ end
31
32
  end
32
- end
33
33
 
34
- def test_finding_with_mixed_array_should_indicate_whether_found_by_numeric_or_friendly
35
- @users = User.find([users(:jane).id, "joe"], :order => "login ASC")
36
- assert @users[0].found_using_numeric_id?
37
- assert @users[1].found_using_friendly_id?
38
- end
34
+ should "indicate if it was found by its friendly id" do
35
+ @user = User.find(@user.friendly_id)
36
+ assert @user.found_using_friendly_id?
37
+ end
39
38
 
40
- def test_finder_options_are_not_ignored
41
- assert_raises ActiveRecord::RecordNotFound do
42
- User.find(users(:joe).friendly_id, :conditions => "1 = 2")
39
+ should "indicate if it was found by its numeric id" do
40
+ @user = User.find(@user.id)
41
+ assert @user.found_using_numeric_id?
43
42
  end
44
- assert_raises ActiveRecord::RecordNotFound do
45
- User.find([users(:joe).friendly_id], :conditions => "1 = 2")
43
+
44
+ should "indicate if it has a better id" do
45
+ @user = User.find(@user.id)
46
+ assert @user.has_better_id?
46
47
  end
47
- end
48
48
 
49
- def test_user_should_have_friendly_id_options
50
- assert_not_nil User.friendly_id_options
51
- end
49
+ should "not validate if the friendly_id text is reserved" do
50
+ @user = User.new(:login => "new", :email => "test@example.org")
51
+ assert !@user.valid?
52
+ end
52
53
 
53
- def test_user_should_not_be_found_using_friendly_id_unless_it_really_was
54
- assert !User.find(users(:joe).id).found_using_friendly_id?
55
- end
54
+ should "have always string for a friendly_id" do
55
+ assert_equal String, @user.to_param.class
56
+ end
56
57
 
57
- def test_users_should_not_be_found_using_friendly_id_unless_they_really_were
58
- @users = User.find([users(:jane).id])
59
- assert @users[0].found_using_numeric_id?
60
- end
58
+ should "return its id if the friendly_id is null" do
59
+ @user.login = nil
60
+ assert_equal @user.id.to_s, @user.to_param
61
+ end
61
62
 
62
- def test_user_should_be_considered_found_by_numeric_id_as_default
63
- @user = User.new
64
- assert @user.found_using_numeric_id?
65
- end
66
63
 
67
- def test_user_should_indicate_if_it_was_found_using_numeric_id
68
- @user = User.find(users(:joe).id)
69
- assert @user.found_using_numeric_id?
70
- assert !@user.found_using_friendly_id?
71
- end
64
+ context "when using an array as the find argument" do
72
65
 
73
- def test_user_should_indicate_if_it_was_found_using_friendly_id
74
- @user = User.find(users(:joe).friendly_id)
75
- assert !@user.found_using_numeric_id?
76
- assert @user.found_using_friendly_id?
77
- end
66
+ setup do
67
+ @user2 = User.create(:login => "jane", :email => "jane@example.org")
68
+ end
69
+
70
+ should "return results" do
71
+ assert_equal 2, User.find([@user.friendly_id, @user2.friendly_id]).size
72
+ end
73
+
74
+ should "not allow mixed friendly and non-friendly ids for the same record" do
75
+ assert_raises ActiveRecord::RecordNotFound do
76
+ User.find([@user.id, @user.friendly_id]).size
77
+ end
78
+ end
79
+
80
+ should "raise an error when all records are not found" do
81
+ assert_raises ActiveRecord::RecordNotFound do
82
+ User.find(['bad', 'bad2'])
83
+ end
84
+ end
85
+
86
+ should "indicate if the results were found using a friendly_id" do
87
+ @users = User.find([@user.id, @user2.friendly_id], :order => "login ASC")
88
+ assert @users[0].found_using_friendly_id?
89
+ assert @users[1].found_using_numeric_id?
90
+ end
91
+
92
+ end
78
93
 
79
- def test_should_indicate_there_is_a_better_id_if_found_by_numeric_id
80
- @user = User.find(users(:joe).id)
81
- assert @user.found_using_numeric_id?
82
- assert @user.has_better_id?
83
94
  end
84
95
 
85
96
  end
data/test/schema.rb CHANGED
@@ -1,35 +1,44 @@
1
- ActiveRecord::Schema.define(:version => 3) do
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+
3
+ create_table "books", :force => true do |t|
4
+ t.column "title", "string"
5
+ t.column "type", "text"
6
+ end
7
+
8
+ create_table "things", :force => true do |t|
9
+ t.column "name", "string"
10
+ end
2
11
 
3
12
  create_table "posts", :force => true do |t|
4
- t.string "name"
5
- t.text "content"
6
- t.datetime "created_at"
7
- t.datetime "updated_at"
13
+ t.column "title", "string"
14
+ t.column "content", "text"
15
+ t.column "created_at", "datetime"
16
+ t.column "updated_at", "datetime"
8
17
  end
9
18
 
10
19
  create_table "users", :force => true do |t|
11
- t.string "login"
12
- t.string "email"
13
- t.datetime "created_at"
14
- t.datetime "updated_at"
20
+ t.column "login", "string"
21
+ t.column "email", "string"
22
+ t.column "created_at", "datetime"
23
+ t.column "updated_at", "datetime"
15
24
  end
16
-
25
+
17
26
  create_table "people", :force => true do |t|
18
- t.string "name"
19
- t.integer "country_id"
27
+ t.column "name", "string"
28
+ t.column "country_id", "integer"
20
29
  end
21
-
30
+
22
31
  create_table "countries", :force => true do |t|
23
- t.string "name"
32
+ t.column "name", "string"
24
33
  end
25
34
 
26
35
  create_table "slugs", :force => true do |t|
27
- t.string "name"
28
- t.integer "sluggable_id"
29
- t.integer "sequence", :null => false, :default => 1
30
- t.string "sluggable_type", :limit => 40
31
- t.string "scope", :limit => 40
32
- t.datetime "created_at"
36
+ t.column "name", "string"
37
+ t.column "sluggable_id", "integer"
38
+ t.column "sequence", "integer", :null => false, :default => 1
39
+ t.column "sluggable_type", "string", :limit => 40
40
+ t.column "scope", "string", :limit => 40
41
+ t.column "created_at", "datetime"
33
42
  end
34
43
 
35
44
  add_index "slugs", ["sluggable_id"], :name => "index_slugs_on_sluggable_id"
@@ -2,20 +2,50 @@ require File.dirname(__FILE__) + '/test_helper'
2
2
 
3
3
  class ScopedModelTest < Test::Unit::TestCase
4
4
 
5
- fixtures :people, :countries, :slugs
6
-
7
- def test_should_find_scoped_records_without_scope
8
- assert_equal 2, Person.find(:all, "john-smith").size
9
- end
5
+ context "A slugged model that uses a scope" do
6
+
7
+ setup do
8
+ Person.delete_all
9
+ Country.delete_all
10
+ Slug.delete_all
11
+ @usa = Country.create!(:name => "USA")
12
+ @canada = Country.create!(:name => "Canada")
13
+ @person = Person.create!(:name => "John Smith", :country => @usa)
14
+ @person2 = Person.create!(:name => "John Smith", :country => @canada)
15
+ end
16
+
17
+ should "find all scoped records without scope" do
18
+ assert_equal 2, Person.find(:all, @person.friendly_id).size
19
+ end
20
+
21
+ should "find a single scoped records with a scope" do
22
+ assert Person.find(@person.friendly_id, :scope => @person.country.to_param)
23
+ end
24
+
25
+ should "raise an error when finding a single scoped record with no scope" do
26
+ assert_raises ActiveRecord::RecordNotFound do
27
+ Person.find(@person.friendly_id)
28
+ end
29
+ end
30
+
31
+ should "append scope error info when missing scope causes a find to fail" do
32
+ begin
33
+ Person.find(@person.friendly_id)
34
+ fail "The find should not have succeeded"
35
+ rescue ActiveRecord::RecordNotFound => e
36
+ assert_match /expected scope/, e.message
37
+ end
38
+ end
39
+
40
+ should "append scope error info when the scope value causes a find to fail" do
41
+ begin
42
+ Person.find(@person.friendly_id, :scope => "badscope")
43
+ fail "The find should not have succeeded"
44
+ rescue ActiveRecord::RecordNotFound => e
45
+ assert_match /scope=badscope/, e.message
46
+ end
47
+ end
10
48
 
11
- def test_should_find_scoped_records_with_scope
12
- assert_equal people(:john_smith), Person.find("john-smith", :scope => "argentina")
13
- assert_equal people(:john_smith2), Person.find("john-smith", :scope => "usa")
14
- end
15
-
16
- def test_should_create_scoped_records_with_scope
17
- person = Person.create!(:name => "Joe Schmoe", :country => countries(:usa))
18
- assert_equal "usa", person.slug.scope
19
49
  end
20
50
 
21
51
  end
data/test/slug_test.rb CHANGED
@@ -1,87 +1,106 @@
1
+ # encoding: utf-8
2
+
1
3
  require File.dirname(__FILE__) + '/test_helper'
2
4
 
3
5
  class SlugTest < Test::Unit::TestCase
4
6
 
5
- fixtures :posts, :slugs
6
-
7
- def test_should_indicate_if_it_is_the_most_recent
8
- assert slugs(:two_new).is_most_recent?
9
- assert !slugs(:two_old).is_most_recent?
10
- end
11
-
12
- def test_parse_should_return_slug_name_and_sequence
13
- assert_equal ["test", "2"], Slug::parse("test--2")
14
- end
15
-
16
- def test_parse_should_return_a_default_sequnce_of_1
17
- assert_equal ["test", "1"], Slug::parse("test")
18
- end
19
-
20
- def test_strip_diacritics_should_strip_diacritics
21
- assert_equal "acai", Slug::strip_diacritics("açaí")
22
- end
23
-
24
- def test_to_friendly_id_should_include_sequence_if_its_greater_than_1
25
- slug = Slug.new(:name => "test", :sequence => 2)
26
- assert_equal "test--2", slug.to_friendly_id
27
- end
28
-
29
- def test_to_friendly_id_should_include_sequence_if_its_than_1
30
- slug = Slug.new(:name => "test", :sequence => 1)
31
- assert_equal "test", slug.to_friendly_id
32
- end
33
-
34
- def test_normalize_should_lowercase_strings
35
- assert_match /abc/, Slug::normalize("ABC")
36
- end
37
-
38
- def test_normalize_should_replace_whitespace_with_dashes
39
- assert_match /a-b/, Slug::normalize("a b")
40
- end
41
-
42
- def test_normalize_should_replace_2spaces_with_1dash
43
- assert_match /a-b/, Slug::normalize("a b")
44
- end
45
-
46
- def test_normalize_should_remove_punctuation
47
- assert_match /abc/, Slug::normalize('abc!@#$%^&*•¶§∞¢££¡¿()><?"":;][]\.,/')
48
- end
49
-
50
- def test_normalize_should_strip_trailing_space
51
- assert_match /ab/, Slug::normalize("ab ")
52
- end
53
-
54
- def test_normalize_should_strip_leading_space
55
- assert_match /ab/, Slug::normalize(" ab")
56
- end
57
-
58
- def test_normalize_should_strip_trailing_slashes
59
- assert_match /ab/, Slug::normalize("ab-")
60
- end
7
+ context "a slug" do
8
+
9
+ setup do
10
+ Slug.delete_all
11
+ Post.delete_all
12
+ end
61
13
 
62
- def test_normalize_should_strip_leading_slashes
63
- assert_match /ab/, Slug::normalize("-ab")
64
- end
14
+ should "indicate if it is the most recent slug" do
15
+ @post = Post.create!(:title => "test title", :content => "test content")
16
+ @post.title = "a new title"
17
+ @post.save!
18
+ assert @post.slugs.last.is_most_recent?
19
+ assert !@post.slugs.first.is_most_recent?
20
+ end
65
21
 
66
- def test_normalize_should_not_modify_valid_name_strings
67
- assert_match /a-b-c-d/, Slug::normalize("a-b-c-d")
68
22
  end
23
+
24
+ context "the Slug class" do
25
+
26
+ should "parse the slug name and sequence" do
27
+ assert_equal ["test", "2"], Slug::parse("test--2")
28
+ end
29
+
30
+ should "parse with a default sequence of 1" do
31
+ assert_equal ["test", "1"], Slug::parse("test")
32
+ end
69
33
 
70
- # These strings are taken from various international Google homepages. I
71
- # would be most grateful if a fluent speaker of any language that uses a
72
- # writing system other than the Roman alphabet could help me make some
73
- # better tests to ensure this is working correctly.
74
- def test_normalize_works_with_non_roman_chars
75
- assert_equal "検-索", Slug::normalize("検 索")
34
+ should "should strip diacritics" do
35
+ assert_equal "acai", Slug::strip_diacritics("açaí")
36
+ end
37
+
38
+ should "strip diacritics correctly " do
39
+ input = "ÀÁÂÃÄÅÆÇÈÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
40
+ output = Slug::strip_diacritics(input).split(//)
41
+ expected = "AAAAAAAECEEEIIIIDNOOOOOOUUUUYThssaaaaaaaeceeeeiiiidnoooooouuuuythy".split(//)
42
+ output.split.each_index do |i|
43
+ assert_equal output[i], expected[i]
44
+ end
45
+ end
46
+
76
47
  end
77
-
78
- def test_strip_diactics_correctly_strips_diacritics
79
- input = "ÀÁÂÃÄÅÆÇÈÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
80
- output = Slug::strip_diacritics(input).split(//)
81
- expected = "AAAAAAAECEEEIIIIDNOOOOOOUUUUYThssaaaaaaaeceeeeiiiidnoooooouuuuythy".split(//)
82
- output.split.each_index do |i|
83
- assert_equal output[i], expected[i]
48
+
49
+ context "the Slug class's to_friendly_id method" do
50
+
51
+ should "include the sequence if the sequence is greater than 1" do
52
+ slug = Slug.new(:name => "test", :sequence => 2)
53
+ assert_equal "test--2", slug.to_friendly_id
84
54
  end
55
+
56
+ should "not include the sequence if the sequence is 1" do
57
+ slug = Slug.new(:name => "test", :sequence => 1)
58
+ assert_equal "test", slug.to_friendly_id
59
+ end
60
+
85
61
  end
86
62
 
63
+ context "the Slug class's normalize method" do
64
+
65
+ should "should lowercase strings" do
66
+ assert_match /abc/, Slug::normalize("ABC")
67
+ end
68
+
69
+ should "should replace whitespace with dashes" do
70
+ assert_match /a-b/, Slug::normalize("a b")
71
+ end
72
+
73
+ should "should replace 2spaces with 1dash" do
74
+ assert_match /a-b/, Slug::normalize("a b")
75
+ end
76
+
77
+ should "should remove punctuation" do
78
+ assert_match /abc/, Slug::normalize('abc!@#$%^&*•¶§∞¢££¡¿()><?"":;][]\.,/')
79
+ end
80
+
81
+ should "should strip trailing space" do
82
+ assert_match /ab/, Slug::normalize("ab ")
83
+ end
84
+
85
+ should "should strip leading space" do
86
+ assert_match /ab/, Slug::normalize(" ab")
87
+ end
88
+
89
+ should "should strip trailing slashes" do
90
+ assert_match /ab/, Slug::normalize("ab-")
91
+ end
92
+
93
+ should "should strip leading slashes" do
94
+ assert_match /ab/, Slug::normalize("-ab")
95
+ end
96
+
97
+ should "should not modify valid name strings" do
98
+ assert_match /a-b-c-d/, Slug::normalize("a-b-c-d")
99
+ end
100
+
101
+ should "work with non roman chars" do
102
+ assert_equal "検-索", Slug::normalize("検 索")
103
+ end
104
+
105
+ end
87
106
  end