friendly_id_globalize3 3.2.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. data/Changelog.md +354 -0
  2. data/Contributors.md +43 -0
  3. data/Guide.md +686 -0
  4. data/MIT-LICENSE +19 -0
  5. data/README.md +99 -0
  6. data/Rakefile +75 -0
  7. data/extras/README.txt +3 -0
  8. data/extras/bench.rb +40 -0
  9. data/extras/extras.rb +38 -0
  10. data/extras/prof.rb +19 -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 +93 -0
  16. data/lib/friendly_id/active_record.rb +74 -0
  17. data/lib/friendly_id/active_record_adapter/configuration.rb +68 -0
  18. data/lib/friendly_id/active_record_adapter/finders.rb +148 -0
  19. data/lib/friendly_id/active_record_adapter/relation.rb +165 -0
  20. data/lib/friendly_id/active_record_adapter/simple_model.rb +63 -0
  21. data/lib/friendly_id/active_record_adapter/slug.rb +77 -0
  22. data/lib/friendly_id/active_record_adapter/slugged_model.rb +122 -0
  23. data/lib/friendly_id/active_record_adapter/tasks.rb +72 -0
  24. data/lib/friendly_id/configuration.rb +178 -0
  25. data/lib/friendly_id/datamapper.rb +5 -0
  26. data/lib/friendly_id/railtie.rb +22 -0
  27. data/lib/friendly_id/sequel.rb +5 -0
  28. data/lib/friendly_id/slug_string.rb +25 -0
  29. data/lib/friendly_id/slugged.rb +105 -0
  30. data/lib/friendly_id/status.rb +35 -0
  31. data/lib/friendly_id/test.rb +350 -0
  32. data/lib/friendly_id/version.rb +9 -0
  33. data/lib/generators/friendly_id_generator.rb +25 -0
  34. data/lib/tasks/friendly_id.rake +19 -0
  35. data/rails/init.rb +2 -0
  36. data/test/active_record_adapter/ar_test_helper.rb +150 -0
  37. data/test/active_record_adapter/basic_slugged_model_test.rb +14 -0
  38. data/test/active_record_adapter/cached_slug_test.rb +76 -0
  39. data/test/active_record_adapter/core.rb +138 -0
  40. data/test/active_record_adapter/custom_normalizer_test.rb +20 -0
  41. data/test/active_record_adapter/custom_table_name_test.rb +22 -0
  42. data/test/active_record_adapter/default_scope_test.rb +30 -0
  43. data/test/active_record_adapter/optimistic_locking_test.rb +18 -0
  44. data/test/active_record_adapter/scoped_model_test.rb +119 -0
  45. data/test/active_record_adapter/simple_test.rb +76 -0
  46. data/test/active_record_adapter/slug_test.rb +34 -0
  47. data/test/active_record_adapter/slugged.rb +33 -0
  48. data/test/active_record_adapter/slugged_status_test.rb +28 -0
  49. data/test/active_record_adapter/sti_test.rb +22 -0
  50. data/test/active_record_adapter/support/database.jdbcsqlite3.yml +2 -0
  51. data/test/active_record_adapter/support/database.mysql.yml +4 -0
  52. data/test/active_record_adapter/support/database.postgres.yml +6 -0
  53. data/test/active_record_adapter/support/database.sqlite3.yml +2 -0
  54. data/test/active_record_adapter/support/models.rb +104 -0
  55. data/test/active_record_adapter/tasks_test.rb +82 -0
  56. data/test/friendly_id_test.rb +96 -0
  57. data/test/test_helper.rb +13 -0
  58. metadata +193 -0
@@ -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,30 @@
1
+ require File.expand_path('../ar_test_helper', __FILE__)
2
+
3
+ ActiveRecord::Migration.create_table :articles do |t|
4
+ t.string :name
5
+ t.string :status
6
+ end
7
+
8
+ class Article < ActiveRecord::Base
9
+ has_friendly_id :name, :use_slug => true
10
+ default_scope :conditions => "articles.status = 'published'"
11
+ end
12
+
13
+ module FriendlyId
14
+ module Test
15
+ module ActiveRecordAdapter
16
+ class DefaultScopeTest < ::Test::Unit::TestCase
17
+
18
+ def setup
19
+ Article.delete_all
20
+ Slug.delete_all
21
+ end
22
+
23
+ test "slug should load sluggable without default scope" do
24
+ Article.create!(:name => "hello world", :status => "draft")
25
+ assert_not_nil Slug.first.sluggable
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,18 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module ActiveRecordAdapter
6
+ class OptimisticLockingTest < ::Test::Unit::TestCase
7
+ test "should update the cached slug when updating the slug" do
8
+ region = Region.create! :name => 'some name'
9
+ assert_nothing_raised do
10
+ region.update_attributes(:name => "new name")
11
+ end
12
+ assert_equal region.slug.to_friendly_id, region.cached_slug
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+
@@ -0,0 +1,119 @@
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
+ def setup
9
+ @user = User.create!(:name => "john")
10
+ @house = House.create!(:name => "123 Main", :user => @user)
11
+ @usa = Country.create!(:name => "USA")
12
+ @canada = Country.create!(:name => "Canada")
13
+ @resident = Resident.create!(:name => "John Smith", :country => @usa)
14
+ @resident2 = Resident.create!(:name => "John Smith", :country => @canada)
15
+ @resident3 = Resident.create!(:name => "Jim Beam", :country => @canada)
16
+ @owner = Company.create!(:name => "Acme Events")
17
+ @site = Site.create!(:name => "Downtown Venue", :owner => @owner)
18
+ end
19
+
20
+ def teardown
21
+ Resident.delete_all
22
+ Country.delete_all
23
+ User.delete_all
24
+ House.delete_all
25
+ Slug.delete_all
26
+ Tourist.delete_all
27
+ end
28
+
29
+ test "As of 3.2.0, should raise error if :scope option is passed" do
30
+ assert_raise(RuntimeError) do
31
+ Tourist.find("hello", :scope => "usa")
32
+ end
33
+ end
34
+
35
+ test "should not use cached slug column with scopes" do
36
+ @tourist = Tourist.create!(:name => "John Smith", :country => @usa)
37
+ @tourist2 = Tourist.create!(:name => "John Smith", :country => @canada)
38
+ assert_equal @canada, @canada.residents.find(@tourist2.friendly_id).country
39
+ end
40
+
41
+ test "a slugged model should auto-detect that it is being used as a parent scope" do
42
+ assert_equal [Resident], Country.friendly_id_config.child_scopes
43
+ end
44
+
45
+ test "a slugged model should update its child model's scopes when its friendly_id changes" do
46
+ @usa.update_attributes(:name => "United States")
47
+ assert_equal "united-states", @usa.to_param
48
+ assert_equal "united-states", @resident.slugs(true).first.scope
49
+ end
50
+
51
+ test "a non-slugged model should auto-detect that it is being used as a parent scope" do
52
+ assert_equal [House], User.friendly_id_config.child_scopes
53
+ end
54
+
55
+ test "should update the slug when the scope changes" do
56
+ @resident.update_attributes! :country => Country.create!(:name => "Argentina")
57
+ assert_equal "argentina", @resident.slugs(true).first.scope
58
+ end
59
+
60
+ test "updating only the scope should not append sequence to friendly_id" do
61
+ old_friendly_id = @resident.friendly_id
62
+ @resident.update_attributes! :country => Country.create!(:name => "Argentina")
63
+ assert_equal old_friendly_id, @resident.friendly_id
64
+ end
65
+
66
+ test "updating the scope should increment sequence to avoid conflicts" do
67
+ old_friendly_id = @resident.friendly_id
68
+ @resident.update_attributes! :country => @canada
69
+ assert_equal "#{old_friendly_id}--2", @resident.friendly_id
70
+ assert_equal "canada", @resident.slugs(true).first.scope
71
+ end
72
+
73
+ test "a non-slugged model should update its child model's scopes when its friendly_id changes" do
74
+ @user.update_attributes(:name => "jack")
75
+ assert_equal "jack", @user.to_param
76
+ assert_equal "jack", @house.slugs(true).first.scope
77
+ end
78
+
79
+ test "should should not show the scope in the friendly_id" do
80
+ assert_equal "john-smith", @resident.friendly_id
81
+ assert_equal "john-smith", @resident2.friendly_id
82
+ end
83
+
84
+ test "should find all scoped records without scope" do
85
+ name, sequence = @resident.friendly_id.parse_friendly_id
86
+ assert_equal 2, Resident.find(:all, :joins => :slugs, :conditions => {
87
+ :slugs => {:name => name, :sequence => sequence}}).size
88
+ end
89
+
90
+ test "should find a scoped record by friendly_id" do
91
+ assert Resident.find(@resident.friendly_id)
92
+ end
93
+
94
+ test "should find a scope record as a relation member" do
95
+ assert_equal @resident, @usa.residents.find("john-smith")
96
+ assert_equal @resident2, @canada.residents.find("john-smith")
97
+ end
98
+
99
+ test "should find a single scoped record using slug conditions" do
100
+ assert_equal @resident, Resident.find(@resident.friendly_id, :include => :slugs,
101
+ :conditions => {:slugs => {:scope => @resident.country.to_param}})
102
+ end
103
+
104
+ test "should update the sluggable field when a polymorphic relationship exists" do
105
+ @site.update_attributes(:name => "Uptown Venue")
106
+ assert_equal "Uptown Venue", @site.name
107
+ end
108
+
109
+ test "should not assume that AR's reflect_on_all_associations with return AR classes" do
110
+ reflections = Resident.reflect_on_all_associations
111
+ reflections << Struct.new("Dummy", :options, :klass).new(:options => [], :klass => Struct)
112
+ Resident.expects(:reflect_on_all_associations).returns(reflections)
113
+ assert_nothing_raised do
114
+ Resident.friendly_id_config.send(:associated_friendly_classes)
115
+ end
116
+ end
117
+ end
118
+ end
119
+ 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
@@ -0,0 +1,33 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+ module FriendlyId
4
+ module Test
5
+ module ActiveRecordAdapter
6
+ module Slugged
7
+
8
+ test "should allow eager loading of slugs" do
9
+ assert_nothing_raised do
10
+ klass.find(instance.friendly_id, :include => :slugs)
11
+ end
12
+
13
+ assert_nothing_raised do
14
+ klass.find(instance.friendly_id, :include => :slug)
15
+ end
16
+ end
17
+
18
+ def klass
19
+ Post
20
+ end
21
+
22
+ def other_class
23
+ District
24
+ end
25
+
26
+ def instance
27
+ @instance ||= klass.create! :name => "hello world"
28
+ end
29
+
30
+ end
31
+ end
32
+ end
33
+ end
@@ -0,0 +1,28 @@
1
+ require File.expand_path("../ar_test_helper", __FILE__)
2
+
3
+
4
+ module FriendlyId
5
+ module Test
6
+ module ActiveRecordAdapter
7
+
8
+ class StatusTest < ::Test::Unit::TestCase
9
+
10
+ include FriendlyId::Test::Status
11
+ include FriendlyId::Test::SluggedStatus
12
+
13
+ def klass
14
+ Post
15
+ end
16
+
17
+ def instance
18
+ @instance ||= klass.create! :name => "hello world"
19
+ end
20
+
21
+ def find_method
22
+ :find
23
+ end
24
+
25
+ end
26
+ end
27
+ end
28
+ 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 StiTest < ::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
+ Novel
16
+ end
17
+
18
+ end
19
+
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,2 @@
1
+ adapter: jdbcsqlite3
2
+ database: ":memory:"
@@ -0,0 +1,4 @@
1
+ adapter: mysql
2
+ database: friendly_id_test
3
+ username: root
4
+ hostname: 127.0.0.1
@@ -0,0 +1,6 @@
1
+ adapter: postgresql
2
+ host: localhost
3
+ port: 5432
4
+ username: postgres
5
+ database: friendly_id_test
6
+ encoding: utf8
@@ -0,0 +1,2 @@
1
+ adapter: sqlite3
2
+ database: ":memory:"
@@ -0,0 +1,104 @@
1
+ class CreateSupportModels < ActiveRecord::Migration
2
+ def self.up
3
+
4
+ create_table :authors do |t|
5
+ t.string :name
6
+ end
7
+
8
+ create_table :blocks do |t|
9
+ t.string :name
10
+ t.string :note
11
+ end
12
+
13
+ create_table :books do |t|
14
+ t.string :name
15
+ t.string :type
16
+ t.string :note
17
+ end
18
+
19
+ create_table :cities do |t|
20
+ t.string :name
21
+ t.string :my_slug
22
+ t.integer :population
23
+ end
24
+ add_index :cities, :my_slug, :unique => true
25
+
26
+ create_table :regions do |t|
27
+ t.string :name
28
+ t.string :cached_slug
29
+ t.string :note
30
+ t.integer :lock_version, :null => false, :default => 0
31
+ end
32
+ add_index :regions, :cached_slug, :unique => true
33
+
34
+ create_table :countries do |t|
35
+ t.string :name
36
+ end
37
+
38
+ create_table :districts do |t|
39
+ t.string :name
40
+ t.string :note
41
+ t.string :cached_slug
42
+ end
43
+ add_index :districts, :cached_slug, :unique => true
44
+
45
+ create_table :events do |t|
46
+ t.string :name
47
+ t.datetime :event_date
48
+ end
49
+
50
+ create_table :houses do |t|
51
+ t.string :name
52
+ t.integer :user_id
53
+ end
54
+
55
+ create_table :legacy_table do |t|
56
+ t.string :name
57
+ t.string :note
58
+ end
59
+
60
+ create_table :people do |t|
61
+ t.string :name
62
+ t.string :note
63
+ end
64
+
65
+ create_table :posts do |t|
66
+ t.string :name
67
+ t.boolean :published
68
+ t.string :note
69
+ end
70
+
71
+ create_table :residents do |t|
72
+ t.string :name
73
+ t.integer :country_id
74
+ end
75
+
76
+ create_table :tourists do |t|
77
+ t.string :name
78
+ t.integer :country_id
79
+ t.string :cached_slug
80
+ end
81
+
82
+ create_table :users do |t|
83
+ t.string :name
84
+ end
85
+ add_index :users, :name, :unique => true
86
+
87
+ create_table :sites do |t|
88
+ t.string :name
89
+ t.integer :owner_id
90
+ t.string :owner_type
91
+ end
92
+
93
+ create_table :companies do |t|
94
+ t.string :name
95
+ end
96
+
97
+ create_table :unfriendlies do |t|
98
+ t.string :name
99
+ end
100
+ end
101
+
102
+ def self.down
103
+ end
104
+ end