dougcole-friendly_id 2.0.5 → 2.0.6
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/History.txt +20 -0
- data/Manifest.txt +10 -18
- data/README.rdoc +34 -5
- data/Rakefile +8 -0
- data/VERSION.yml +1 -1
- data/lib/friendly_id.rb +33 -13
- data/lib/friendly_id/non_sluggable_class_methods.rb +3 -3
- data/lib/friendly_id/non_sluggable_instance_methods.rb +9 -1
- data/lib/friendly_id/slug.rb +14 -12
- data/lib/friendly_id/sluggable_class_methods.rb +14 -3
- data/lib/friendly_id/sluggable_instance_methods.rb +11 -4
- data/lib/friendly_id/version.rb +1 -1
- data/test/custom_slug_normalizer_test.rb +35 -0
- data/test/models/book.rb +2 -0
- data/test/{fixtures → models}/country.rb +0 -0
- data/test/models/novel.rb +3 -0
- data/test/{fixtures → models}/person.rb +0 -0
- data/test/models/post.rb +3 -0
- data/test/models/thing.rb +6 -0
- data/test/{fixtures → models}/user.rb +0 -0
- data/test/non_slugged_test.rb +71 -60
- data/test/schema.rb +29 -20
- data/test/scoped_model_test.rb +43 -13
- data/test/slug_test.rb +93 -74
- data/test/slugged_model_test.rb +263 -0
- data/test/sti_test.rb +48 -0
- data/test/test_helper.rb +30 -29
- metadata +15 -20
- data/lib/friendly_id/shoulda_macros.rb +0 -36
- data/test/database.yml +0 -3
- data/test/fixtures/countries.yml +0 -4
- data/test/fixtures/people.yml +0 -7
- data/test/fixtures/post.rb +0 -3
- data/test/fixtures/posts.yml +0 -23
- data/test/fixtures/slugs.yml +0 -53
- data/test/fixtures/users.yml +0 -7
- data/test/rails/2.x/app/controllers/application.rb +0 -0
- data/test/rails/2.x/config/boot.rb +0 -109
- data/test/rails/2.x/config/database.yml +0 -3
- data/test/rails/2.x/config/environment.rb +0 -7
- data/test/rails/2.x/config/environments/test.rb +0 -6
- data/test/rails/2.x/config/routes.rb +0 -0
- data/test/sluggable_test.rb +0 -185
data/test/models/book.rb
ADDED
File without changes
|
File without changes
|
data/test/models/post.rb
ADDED
File without changes
|
data/test/non_slugged_test.rb
CHANGED
@@ -2,84 +2,95 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
2
2
|
|
3
3
|
class NonSluggedTest < Test::Unit::TestCase
|
4
4
|
|
5
|
-
|
5
|
+
context "A non-slugged model with default FriendlyId options" do
|
6
6
|
|
7
|
-
|
8
|
-
|
7
|
+
setup do
|
8
|
+
User.delete_all
|
9
|
+
@user = User.create!(:login => "joe", :email => "joe@example.org")
|
10
|
+
end
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
12
|
+
should "have friendly_id options" do
|
13
|
+
assert_not_nil User.friendly_id_options
|
14
|
+
end
|
13
15
|
|
14
|
-
|
15
|
-
|
16
|
-
|
16
|
+
should "not have a slug" do
|
17
|
+
assert !@user.respond_to?(:slug)
|
18
|
+
end
|
17
19
|
|
18
|
-
|
19
|
-
|
20
|
-
|
20
|
+
should "be findable by its friendly_id" do
|
21
|
+
assert User.find(@user.friendly_id)
|
22
|
+
end
|
21
23
|
|
22
|
-
|
23
|
-
|
24
|
-
User.find(['bad', 'bad2'])
|
24
|
+
should "be findable by its regular id" do
|
25
|
+
assert User.find(@user.id)
|
25
26
|
end
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
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
|
-
|
41
|
-
|
42
|
-
|
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
|
-
|
45
|
-
|
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
|
-
|
50
|
-
|
51
|
-
|
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
|
-
|
54
|
-
|
55
|
-
|
54
|
+
should "have always string for a friendly_id" do
|
55
|
+
assert_equal String, @user.to_param.class
|
56
|
+
end
|
56
57
|
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
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
|
-
|
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
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
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 =>
|
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
|
5
|
-
t.
|
6
|
-
t.
|
7
|
-
t.
|
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.
|
12
|
-
t.
|
13
|
-
t.
|
14
|
-
t.
|
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.
|
19
|
-
t.
|
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.
|
32
|
+
t.column "name", "string"
|
24
33
|
end
|
25
34
|
|
26
35
|
create_table "slugs", :force => true do |t|
|
27
|
-
t.
|
28
|
-
t.
|
29
|
-
t.
|
30
|
-
t.
|
31
|
-
t.
|
32
|
-
t.
|
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"
|
data/test/scoped_model_test.rb
CHANGED
@@ -2,20 +2,50 @@ require File.dirname(__FILE__) + '/test_helper'
|
|
2
2
|
|
3
3
|
class ScopedModelTest < Test::Unit::TestCase
|
4
4
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
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
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
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
|
-
|
63
|
-
|
64
|
-
|
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
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
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
|