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,348 +0,0 @@
1
- # encoding: utf-8
2
- require File.dirname(__FILE__) + '/test_helper'
3
-
4
- class SluggedModelTest < Test::Unit::TestCase
5
-
6
- context "A slugged model with default FriendlyId options" do
7
-
8
- setup do
9
- Post.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :name, :use_slug => true)
10
- @post = Post.new :name => "Test post", :published => true
11
- @post.save!
12
- end
13
-
14
- teardown do
15
- Post.delete_all
16
- Person.delete_all
17
- Place.delete_all
18
- Slug.delete_all
19
- end
20
-
21
- should "have friendly_id options" do
22
- assert_not_nil Post.friendly_id_options
23
- end
24
-
25
- should "have a slug" do
26
- assert_not_nil @post.slug
27
- end
28
-
29
- should "be findable by its friendly_id" do
30
- assert Post.find(@post.friendly_id)
31
- end
32
-
33
- should "be findable by its regular id" do
34
- assert Post.find(@post.id)
35
- end
36
-
37
- should "be findable by its regular id as a string" do
38
- assert Post.find(@post.id.to_s)
39
- end
40
-
41
- should "be findable by its instance" do
42
- assert Post.find(@post)
43
- end
44
-
45
- should "not be findable by its id if looking for something else" do
46
- assert_raises ActiveRecord::RecordNotFound do
47
- Post.find("#{@post.id}-i-dont-exists")
48
- end
49
- end
50
-
51
- should "generate slug text" do
52
- post = Post.new :name => "Test post"
53
- assert_not_nil post.slug_text
54
- end
55
-
56
- should "respect finder conditions" do
57
- assert_raises ActiveRecord::RecordNotFound do
58
- Post.find(@post.friendly_id, :conditions => "1 = 2")
59
- end
60
- end
61
-
62
- should "raise an error if the friendly_id text is reserved" do
63
- assert_raises(FriendlyId::SlugGenerationError) do
64
- Post.create!(:name => "new")
65
- end
66
- end
67
-
68
- should "raise an error if the friendly_id text is an empty string" do
69
- assert_raises(FriendlyId::SlugGenerationError) do
70
- Post.create(:name => "")
71
- end
72
- end
73
-
74
- should "raise an error if the friendly_id text is nil" do
75
- assert_raises(FriendlyId::SlugGenerationError) do
76
- Post.create(:name => nil)
77
- end
78
- end
79
-
80
- should "raise an error if the normalized friendly id becomes blank" do
81
- assert_raises(FriendlyId::SlugGenerationError) do
82
- post = Post.create!(:name => "-.-")
83
- end
84
- end
85
-
86
- should "not make a new slug unless the friendly_id method value has changed" do
87
- @post.published = !@post.published
88
- @post.save!
89
- assert_equal 1, @post.slugs.size
90
- end
91
-
92
- should "make a new slug if the friendly_id method value has changed" do
93
- @post.name = "Changed title"
94
- @post.save!
95
- assert_equal 2, @post.slugs.size
96
- end
97
-
98
- should "have a slug sequence of 1 by default" do
99
- assert_equal 1, @post.slug.sequence
100
- end
101
-
102
- should "increment sequence for duplicate slug names" do
103
- @post2 = Post.create! :name => @post.name
104
- assert_equal 2, @post2.slug.sequence
105
- end
106
-
107
- should "have a friendly_id that terminates with -- and the slug sequence if the sequence is greater than 1" do
108
- @post2 = Post.create! :name => @post.name
109
- assert_match(/--2\z/, @post2.friendly_id)
110
- end
111
-
112
- should "allow datetime columns to be used as slugs" do
113
- assert Event.create(:name => "Test", :event_date => DateTime.now)
114
- end
115
-
116
- should "not strip diacritics" do
117
- post = Post.new(:name => "¡Feliz año!")
118
- assert_match(/#{'ñ'}/, post.slug_text)
119
- end
120
-
121
- should "not convert to ASCII" do
122
- post = Post.new(:name => "katakana: ゲコゴサザシジ")
123
- assert_equal "katakana-ゲコゴサザシジ", post.slug_text
124
- end
125
-
126
- should "allow the same friendly_id across models" do
127
- district = District.create!(:name => @post.name)
128
- assert_equal district.friendly_id, @post.friendly_id
129
- end
130
-
131
- should "truncate slug text longer than the max length" do
132
- post = Post.new(:name => "a" * (Post.friendly_id_options[:max_length] + 1))
133
- assert_equal post.slug_text.length, Post.friendly_id_options[:max_length]
134
- end
135
-
136
- should "truncate slug in 'right way' when slug is unicode" do
137
- post = Post.new(:name => "ё" * 100 + 'ю' *(Post.friendly_id_options[:max_length] - 100 + 1))
138
- assert_equal post.slug_text.mb_chars[-1], 'ю'
139
- end
140
-
141
- should "be able to reuse an old friendly_id without incrementing the sequence" do
142
- old_title = @post.name
143
- old_friendly_id = @post.friendly_id
144
- @post.name = "A changed title"
145
- @post.save!
146
- @post.name = old_title
147
- @post.save!
148
- assert_equal old_friendly_id, @post.friendly_id
149
- end
150
-
151
- should "allow eager loading of slugs" do
152
- assert_nothing_raised do
153
- Post.find(@post.friendly_id, :include => :slugs)
154
- end
155
- end
156
-
157
- # This emulates a fairly common issue where id's generated by fixtures are very high.
158
- should "continue to admit very large ids" do
159
- Person.connection.execute("INSERT INTO people (id, name) VALUES (2147483647, 'Joe Schmoe')")
160
- assert Person.find(2147483647)
161
- end
162
-
163
- context "and configured to strip diacritics" do
164
- setup do
165
- Post.friendly_id_options = Post.friendly_id_options.merge(:strip_diacritics => true)
166
- end
167
-
168
- should "strip diacritics from Roman alphabet based characters" do
169
- post = Post.new(:name => "¡Feliz año!")
170
- assert_no_match(/#{'ñ'}/, post.slug_text)
171
- end
172
-
173
- should "raise an error if the friendly_id text is an empty string" do
174
- assert_raises(FriendlyId::SlugGenerationError) do
175
- Post.create(:name => "")
176
- end
177
- end
178
-
179
- should "raise an error if the friendly_id text is nil" do
180
- assert_raises(FriendlyId::SlugGenerationError) do
181
- Post.create(:name => nil)
182
- end
183
- end
184
-
185
- end
186
-
187
- context "and configured to convert to ASCII" do
188
- setup do
189
- Post.friendly_id_options = Post.friendly_id_options.merge(:strip_non_ascii => true)
190
- end
191
-
192
- should "strip non-ascii characters" do
193
- post = Post.new(:name => "katakana: ゲコゴサザシジ")
194
- assert_equal "katakana", post.slug_text
195
- end
196
- end
197
-
198
- context "that uses a custom table name" do
199
- should "support normal CRUD operations" do
200
- assert thing = Place.create!(:name => "a name")
201
- thing.name = "a new name"
202
- assert thing.save!
203
- assert thing.destroy
204
- end
205
- end
206
-
207
- context "that doesn't have a slug" do
208
-
209
- setup do
210
- @post.slug.destroy
211
- @post = Post.find(@post.id)
212
- end
213
-
214
- should "have a to_param method that returns the id cast to a string" do
215
- assert_equal @post.id.to_s, @post.to_param
216
- end
217
-
218
- end
219
-
220
- context "when found using its friendly_id" do
221
- setup do
222
- @post = Post.find(@post.friendly_id)
223
- end
224
-
225
- should "indicate that it was found using the friendly_id" do
226
- assert @post.found_using_friendly_id?
227
- end
228
-
229
- should "not indicate that it has a better id" do
230
- assert !@post.has_better_id?
231
- end
232
-
233
- should "not indicate that it was found using its numeric id" do
234
- assert !@post.found_using_numeric_id?
235
- end
236
-
237
- should "have a finder slug" do
238
- assert_not_nil @post.finder_slug
239
- end
240
-
241
- end
242
-
243
- context "when found using its regular id" do
244
- setup do
245
- @post = Post.find(@post.id)
246
- end
247
-
248
- should "indicate that it was not found using the friendly id" do
249
- assert !@post.found_using_friendly_id?
250
- end
251
-
252
- should "indicate that it has a better id" do
253
- assert @post.has_better_id?
254
- end
255
-
256
- should "indicate that it was found using its numeric id" do
257
- assert @post.found_using_numeric_id?
258
- end
259
-
260
- should "not have a finder slug" do
261
- assert_nil @post.finder_slug
262
- end
263
-
264
- end
265
-
266
- context "when found using an outdated friendly id" do
267
- setup do
268
- old_id = @post.friendly_id
269
- @post.name = "Title changed"
270
- @post.save!
271
- @post = Post.find(old_id)
272
- end
273
-
274
- should "indicate that it was found using a friendly_id" do
275
- assert @post.found_using_friendly_id?
276
- end
277
-
278
- should "indicate that it has a better id" do
279
- assert @post.has_better_id?
280
- end
281
-
282
- should "not indicate that it was found using its numeric id" do
283
- assert !@post.found_using_numeric_id?
284
- end
285
-
286
- should "should have a finder slug different from its default slug" do
287
- assert_not_equal @post.slug, @post.finder_slug
288
- end
289
-
290
- end
291
-
292
- context "when table does not exist" do
293
- should "not raise an error when doing friendly_id setup" do
294
- assert_nothing_raised do
295
- Question.has_friendly_id :title, :use_slug => true
296
- end
297
- end
298
- end
299
-
300
- context "when using an array as the find argument" do
301
-
302
- setup do
303
- @post2 = Post.create!(:name => "another post", :published => true)
304
- end
305
-
306
- should "return results when passed an array of non-friendly ids" do
307
- assert_equal 2, Post.find([@post.id, @post2.id]).size
308
- end
309
-
310
- should "return results when passed an array of friendly ids" do
311
- assert_equal 2, Post.find([@post.friendly_id, @post2.friendly_id]).size
312
- end
313
-
314
- should "return results when searching using a named scope" do
315
- assert_equal 2, Post.published.find([@post.id, @post2.id]).size
316
- end
317
-
318
- should "return results when passed a mixed array of friendly and non-friendly ids" do
319
- assert_equal 2, Post.find([@post.friendly_id, @post2.id]).size
320
- end
321
-
322
- should "return results when passed an array of non-friendly ids, of which one represents a record with multiple slugs" do
323
- @post2.update_attributes(:name => 'another post [updated]')
324
- assert_equal 2, Post.find([@post.id, @post2.id]).size
325
- end
326
-
327
- should "indicate that the results were found using a friendly_id" do
328
- @posts = Post.find [@post.friendly_id, @post2.friendly_id]
329
- @posts.each { |p| assert p.found_using_friendly_id? }
330
- end
331
-
332
- should "raise an error when all records are not found" do
333
- assert_raises(ActiveRecord::RecordNotFound) do
334
- Post.find([@post.friendly_id, 'non-existant-slug-record'])
335
- end
336
- end
337
-
338
- should "allow eager loading of slugs" do
339
- assert_nothing_raised do
340
- Post.find([@post.friendly_id, @post2.friendly_id], :include => :slugs)
341
- end
342
- end
343
-
344
- end
345
-
346
- end
347
-
348
- end
data/test/sti_test.rb DELETED
@@ -1,49 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class STIModelTest < Test::Unit::TestCase
4
-
5
- context "A slugged model using single table inheritance" do
6
-
7
- setup do
8
- Novel.friendly_id_options = FriendlyId::DEFAULT_OPTIONS.merge(:method => :name, :use_slug => true)
9
- @novel = Novel.new :name => "Test novel"
10
- @novel.save!
11
- end
12
-
13
- teardown do
14
- Novel.delete_all
15
- Slug.delete_all
16
- end
17
-
18
- should "have a slug" do
19
- assert_not_nil @novel.slug
20
- end
21
-
22
- context "found by its friendly id" do
23
-
24
- setup do
25
- @novel = Novel.find(@novel.friendly_id)
26
- end
27
-
28
- should "not indicate that it has a better id" do
29
- assert !@novel.has_better_id?
30
- end
31
-
32
- end
33
-
34
-
35
- context "found by its numeric id" do
36
-
37
- setup do
38
- @novel = Novel.find(@novel.id)
39
- end
40
-
41
- should "indicate that it has a better id" do
42
- assert @novel.has_better_id?
43
- end
44
-
45
- end
46
-
47
- end
48
-
49
- end
data/test/tasks_test.rb DELETED
@@ -1,105 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
- require "friendly_id/tasks"
3
-
4
- class TasksTest < Test::Unit::TestCase
5
-
6
- context "FriendlyId tasks" do
7
-
8
- should "parse a top-level class name and return a class" do
9
- assert_equal String, FriendlyId::Tasks.parse_class_name("String")
10
- end
11
-
12
- should "parse a namespaced class name and return a class" do
13
- assert_equal Test::Unit, FriendlyId::Tasks.parse_class_name("Test::Unit")
14
- end
15
-
16
- end
17
-
18
- context "The 'make slugs' task" do
19
-
20
- setup do
21
- City.create! :name => "Buenos Aires"
22
- City.create! :name => "Rio de Janeiro"
23
- City.create! :name => "Tokyo"
24
- City.create! :name => "Nairobi"
25
- Slug.delete_all
26
- end
27
-
28
- teardown do
29
- City.delete_all
30
- Slug.delete_all
31
- end
32
-
33
- should "make one slug per model" do
34
- assert_equal 0, Slug.count
35
- FriendlyId::Tasks.make_slugs("City")
36
- assert_equal 4, Slug.count
37
- end
38
-
39
- end
40
-
41
- context "The 'delete_slugs_for' task" do
42
-
43
- setup do
44
- @post = Post.create! :name => "Slugs Considered Harmful"
45
- @city = City.create! :name => "Buenos Aires"
46
- end
47
-
48
- teardown do
49
- Post.delete_all
50
- City.delete_all
51
- Slug.delete_all
52
- end
53
-
54
- should "Delete only slugs for the specified model" do
55
- assert_equal 2, Slug.count
56
- FriendlyId::Tasks.delete_slugs_for("City")
57
- assert_equal 1, Slug.count
58
- end
59
-
60
- should "set the cached_slug column to NULL" do
61
- District.create! :name => "Garment"
62
- FriendlyId::Tasks.delete_slugs_for("District")
63
- assert_nil District.first.cached_slug
64
- end
65
-
66
- end
67
-
68
- context "The 'delete_old_slugs' task" do
69
-
70
- setup do
71
- @post = Post.create! :name => "Slugs Considered Harmful"
72
- @city = City.create! :name => "Buenos Aires"
73
- City.connection.execute "UPDATE slugs SET created_at = '%s' WHERE id = %d" % [
74
- 45.days.ago.strftime("%Y-%m-%d"), @city.slug.id]
75
- @city.name = "Ciudad de Buenos Aires"
76
- @city.save!
77
- end
78
-
79
- teardown do
80
- Post.delete_all
81
- City.delete_all
82
- Slug.delete_all
83
- end
84
-
85
- should "delete slugs older than 45 days by default" do
86
- assert_equal 3, Slug.count
87
- FriendlyId::Tasks.delete_old_slugs
88
- assert_equal 2, Slug.count
89
- end
90
-
91
- should "respect the days argument" do
92
- assert_equal 3, Slug.count
93
- FriendlyId::Tasks.delete_old_slugs(100)
94
- assert_equal 3, Slug.count
95
- end
96
-
97
- should "respect the class argument" do
98
- assert_equal 3, Slug.count
99
- FriendlyId::Tasks.delete_old_slugs(1, "Post")
100
- assert_equal 3, Slug.count
101
- end
102
-
103
- end
104
-
105
- end