sluggi 0.1.0 → 0.2.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.
- checksums.yaml +4 -4
- data/.travis.yml +1 -1
- data/README.md +1 -7
- data/lib/sluggi.rb +4 -0
- data/lib/sluggi/history.rb +6 -1
- data/lib/sluggi/model.rb +52 -0
- data/lib/sluggi/slugged.rb +4 -70
- data/lib/sluggi/validate_exclusion_of.rb +32 -0
- data/lib/sluggi/validate_presence.rb +9 -0
- data/lib/sluggi/validate_uniqueness.rb +9 -0
- data/lib/sluggi/version.rb +1 -1
- data/test/model_test.rb +73 -0
- data/test/slugged_test.rb +9 -83
- data/test/validate_presence_test.rb +12 -0
- data/test/validate_uniqueness_test.rb +24 -0
- data/test/validates_exclusion_of_test.rb +25 -0
- metadata +15 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d47ac0cb584d36352b4ac43a1e2f7fc7cde0b85
|
4
|
+
data.tar.gz: a62c76432d186ab0024492c686fc45cb505f6768
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7584d82c191aa1c70e35c8ff16c1d0bc39c286340f9a01fb299e9e542b0fe6099bc89c9d55f3bc1147a45bfdf205b9d58d346b58ede60ef2e26e8c418a096ee0
|
7
|
+
data.tar.gz: f9740626f5c05f675848f399fecd486f296e957420fb52cb726346e47428915e3a185a71dd84261d7e8b834431ac394c3eb755ef802c9a1a1e40ccd4ce3e8a01
|
data/.travis.yml
CHANGED
data/README.md
CHANGED
@@ -20,13 +20,7 @@ gem 'sluggi'
|
|
20
20
|
Add a string column named `slug` to any models you want to slug. You can generate a migration like so:
|
21
21
|
|
22
22
|
```sh
|
23
|
-
rails generate migration AddSlugToCats slug:string
|
24
|
-
```
|
25
|
-
```ruby
|
26
|
-
# edit the migration to add a unique index:
|
27
|
-
add_index :cats, :slug, unique: true
|
28
|
-
```
|
29
|
-
```sh
|
23
|
+
rails generate migration AddSlugToCats slug:string:uniq:index
|
30
24
|
rake db:migrate
|
31
25
|
```
|
32
26
|
|
data/lib/sluggi.rb
CHANGED
@@ -1,5 +1,9 @@
|
|
1
1
|
require "sluggi/version"
|
2
2
|
require "sluggi/slug"
|
3
3
|
require "sluggi/history"
|
4
|
+
require "sluggi/validate_exclusion_of"
|
5
|
+
require "sluggi/validate_presence"
|
6
|
+
require "sluggi/validate_uniqueness"
|
7
|
+
require "sluggi/model"
|
4
8
|
require "sluggi/slugged"
|
5
9
|
require "sluggi/generators/sluggi_generator"
|
data/lib/sluggi/history.rb
CHANGED
@@ -3,7 +3,12 @@ module Sluggi
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
has_many :slugs,
|
6
|
+
has_many :slugs,
|
7
|
+
-> { order('slugs.id DESC') },
|
8
|
+
class_name: 'Sluggi::Slug',
|
9
|
+
as: :sluggable,
|
10
|
+
dependent: :destroy
|
11
|
+
|
7
12
|
after_save :create_slug
|
8
13
|
end
|
9
14
|
|
data/lib/sluggi/model.rb
ADDED
@@ -0,0 +1,52 @@
|
|
1
|
+
module Sluggi
|
2
|
+
module Model
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
NOT_IMPLEMENTED_MESSAGE = 'You must implement #slug_value_changed? '\
|
6
|
+
'and either #slug_value or #slug_candidates'.freeze
|
7
|
+
|
8
|
+
included do
|
9
|
+
before_validation :set_slug
|
10
|
+
end
|
11
|
+
|
12
|
+
def to_param
|
13
|
+
slug_was
|
14
|
+
end
|
15
|
+
|
16
|
+
private
|
17
|
+
|
18
|
+
def clean_slug(value)
|
19
|
+
value.try :parameterize
|
20
|
+
end
|
21
|
+
|
22
|
+
def set_slug
|
23
|
+
return unless new_record? || slug_value_changed?
|
24
|
+
new_slug = clean_slug(slug_value)
|
25
|
+
return if new_slug.blank?
|
26
|
+
self.slug = new_slug
|
27
|
+
end
|
28
|
+
|
29
|
+
# these are generally good to override:
|
30
|
+
|
31
|
+
def slug_value
|
32
|
+
slug_candidates.each do |value|
|
33
|
+
next if value.blank?
|
34
|
+
candidate = clean_slug(value)
|
35
|
+
return candidate if candidate == slug
|
36
|
+
return candidate unless self.class.exists?(slug: candidate)
|
37
|
+
end
|
38
|
+
nil
|
39
|
+
end
|
40
|
+
|
41
|
+
# return an array of candidate slug values
|
42
|
+
# Example:
|
43
|
+
# [first_name, full_name, id_and_full_name]
|
44
|
+
def slug_candidates
|
45
|
+
raise NotImplementedError, NOT_IMPLEMENTED_MESSAGE
|
46
|
+
end
|
47
|
+
|
48
|
+
def slug_value_changed?
|
49
|
+
raise NotImplementedError, NOT_IMPLEMENTED_MESSAGE
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
data/lib/sluggi/slugged.rb
CHANGED
@@ -1,77 +1,11 @@
|
|
1
1
|
module Sluggi
|
2
2
|
module Slugged
|
3
3
|
extend ActiveSupport::Concern
|
4
|
-
|
5
|
-
RESERVED_SLUGS = %w(
|
6
|
-
create
|
7
|
-
edit
|
8
|
-
index
|
9
|
-
new
|
10
|
-
update
|
11
|
-
admin
|
12
|
-
assets
|
13
|
-
images
|
14
|
-
javascripts
|
15
|
-
login
|
16
|
-
logout
|
17
|
-
stylesheets
|
18
|
-
session
|
19
|
-
users
|
20
|
-
)
|
21
|
-
|
22
|
-
NOT_IMPLEMENTED_MESSAGE = 'You must implement #slug_value_changed? and either #slug_value or #slug_candidates'
|
23
|
-
|
24
4
|
included do
|
25
|
-
|
26
|
-
|
27
|
-
|
5
|
+
include Sluggi::ValidatePresence
|
6
|
+
include Sluggi::ValidateUniqueness
|
7
|
+
include Sluggi::ValidateExclusionOf
|
8
|
+
include Sluggi::Model
|
28
9
|
end
|
29
|
-
|
30
|
-
module ClassMethods
|
31
|
-
def reserved_slugs
|
32
|
-
RESERVED_SLUGS
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
def to_param
|
37
|
-
slug_was
|
38
|
-
end
|
39
|
-
|
40
|
-
private
|
41
|
-
|
42
|
-
def clean_slug(value)
|
43
|
-
value.try :parameterize
|
44
|
-
end
|
45
|
-
|
46
|
-
def set_slug
|
47
|
-
return unless new_record? || slug_value_changed?
|
48
|
-
new_slug = clean_slug(slug_value)
|
49
|
-
return if new_slug.blank?
|
50
|
-
self.slug = new_slug
|
51
|
-
end
|
52
|
-
|
53
|
-
# these are generally good to override:
|
54
|
-
|
55
|
-
def slug_value
|
56
|
-
slug_candidates.each do |value|
|
57
|
-
next if value.blank?
|
58
|
-
candidate = clean_slug(value)
|
59
|
-
return candidate if candidate == slug
|
60
|
-
return candidate unless self.class.exists?(slug: candidate)
|
61
|
-
end
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
|
65
|
-
# return an array of candidate slug values
|
66
|
-
# Example:
|
67
|
-
# [first_name, full_name, id_and_full_name]
|
68
|
-
def slug_candidates
|
69
|
-
raise NotImplementedError.new(NOT_IMPLEMENTED_MESSAGE)
|
70
|
-
end
|
71
|
-
|
72
|
-
def slug_value_changed?
|
73
|
-
raise NotImplementedError.new(NOT_IMPLEMENTED_MESSAGE)
|
74
|
-
end
|
75
|
-
|
76
10
|
end
|
77
11
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Sluggi
|
2
|
+
module ValidateExclusionOf
|
3
|
+
extend ActiveSupport::Concern
|
4
|
+
|
5
|
+
RESERVED_SLUGS = %w(
|
6
|
+
admin
|
7
|
+
assets
|
8
|
+
create
|
9
|
+
edit
|
10
|
+
images
|
11
|
+
index
|
12
|
+
javascripts
|
13
|
+
login
|
14
|
+
logout
|
15
|
+
new
|
16
|
+
session
|
17
|
+
stylesheets
|
18
|
+
update
|
19
|
+
users
|
20
|
+
)
|
21
|
+
|
22
|
+
included do
|
23
|
+
validates_exclusion_of :slug, in: ->(_) { reserved_slugs }
|
24
|
+
end
|
25
|
+
|
26
|
+
module ClassMethods
|
27
|
+
def reserved_slugs
|
28
|
+
RESERVED_SLUGS
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
data/lib/sluggi/version.rb
CHANGED
data/test/model_test.rb
ADDED
@@ -0,0 +1,73 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ModelTest < MiniTest::Spec
|
4
|
+
class IncompleteCat < ActiveRecord::Base
|
5
|
+
self.table_name = 'cats'
|
6
|
+
include Sluggi::Model
|
7
|
+
end
|
8
|
+
|
9
|
+
class Cat < ActiveRecord::Base
|
10
|
+
include Sluggi::Model
|
11
|
+
|
12
|
+
def slug_value
|
13
|
+
name
|
14
|
+
end
|
15
|
+
|
16
|
+
def slug_value_changed?
|
17
|
+
name_changed?
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
class CandidateCat < ActiveRecord::Base
|
22
|
+
self.table_name = 'cats'
|
23
|
+
include Sluggi::Model
|
24
|
+
|
25
|
+
def slug_candidates
|
26
|
+
[nil, name]
|
27
|
+
end
|
28
|
+
|
29
|
+
def slug_value_changed?
|
30
|
+
name_changed?
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
it "raises when slug_value is not implemented" do
|
35
|
+
assert_raises(NotImplementedError) do
|
36
|
+
IncompleteCat.new.valid?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
describe "#to_param" do
|
41
|
+
before do
|
42
|
+
Cat.delete_all
|
43
|
+
@cat = Cat.new(name: 'Tuxedo Stan')
|
44
|
+
end
|
45
|
+
|
46
|
+
it "is nil when new" do
|
47
|
+
assert_nil @cat.to_param
|
48
|
+
end
|
49
|
+
|
50
|
+
it "is the slug when persisted" do
|
51
|
+
@cat.save!
|
52
|
+
assert_equal 'tuxedo-stan', @cat.to_param
|
53
|
+
end
|
54
|
+
|
55
|
+
it "is the old slug when changed but not saved" do
|
56
|
+
@cat.save!
|
57
|
+
@cat.slug = 'ketzel'
|
58
|
+
assert_equal 'tuxedo-stan', @cat.to_param
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
it "sets slug from candidates on validation" do
|
63
|
+
cat = CandidateCat.new(name: 'Smokey')
|
64
|
+
assert cat.valid?
|
65
|
+
assert_equal 'smokey', cat.slug
|
66
|
+
end
|
67
|
+
|
68
|
+
it "sets slug on validation" do
|
69
|
+
cat = Cat.new(name: 'Prince Chunk')
|
70
|
+
assert cat.valid?
|
71
|
+
assert_equal 'prince-chunk', cat.slug
|
72
|
+
end
|
73
|
+
end
|
data/test/slugged_test.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
3
|
class SluggedTest < MiniTest::Spec
|
4
|
-
class
|
4
|
+
class Cat < ActiveRecord::Base
|
5
5
|
include Sluggi::Slugged
|
6
6
|
|
7
7
|
def slug_value
|
@@ -13,93 +13,19 @@ class SluggedTest < MiniTest::Spec
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
|
17
|
-
|
18
|
-
include Sluggi::Slugged
|
19
|
-
|
20
|
-
def slug_candidates
|
21
|
-
[nil, name]
|
22
|
-
end
|
23
|
-
|
24
|
-
def slug_value_changed?
|
25
|
-
name_changed?
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class ::IncompleteCat < ActiveRecord::Base
|
30
|
-
self.table_name = 'cats'
|
31
|
-
include Sluggi::Slugged
|
32
|
-
end
|
33
|
-
|
34
|
-
it "raises when slug_value is not implemented" do
|
35
|
-
assert_raises(NotImplementedError) do
|
36
|
-
IncompleteCat.new.valid?
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
describe "#to_param" do
|
41
|
-
before do
|
42
|
-
Cat.delete_all
|
43
|
-
@cat = Cat.new(name: 'Tuxedo Stan')
|
44
|
-
end
|
45
|
-
|
46
|
-
it "is nil when new" do
|
47
|
-
assert_nil @cat.to_param
|
48
|
-
end
|
49
|
-
|
50
|
-
it "is the slug when persisted" do
|
51
|
-
@cat.save!
|
52
|
-
assert_equal 'tuxedo-stan', @cat.to_param
|
53
|
-
end
|
54
|
-
|
55
|
-
it "is the old slug when changed but not saved" do
|
56
|
-
@cat.save!
|
57
|
-
@cat.slug = 'ketzel'
|
58
|
-
assert_equal 'tuxedo-stan', @cat.to_param
|
59
|
-
end
|
16
|
+
it "includes ValidatePresence" do
|
17
|
+
assert Cat.new.is_a? Sluggi::ValidatePresence
|
60
18
|
end
|
61
19
|
|
62
|
-
|
63
|
-
|
64
|
-
it "includes #{word}" do
|
65
|
-
assert_includes Cat.reserved_slugs, word
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
it "does not include valid slug" do
|
70
|
-
refute_includes Cat.reserved_slugs, 'something'
|
71
|
-
end
|
20
|
+
it "includes ValidateUniqueness" do
|
21
|
+
assert Cat.new.is_a? Sluggi::ValidateUniqueness
|
72
22
|
end
|
73
23
|
|
74
|
-
|
75
|
-
|
76
|
-
refute Cat.new(name: 'edit').valid?
|
77
|
-
end
|
78
|
-
|
79
|
-
it "blank slug is invalid" do
|
80
|
-
refute Cat.new(name: '').valid?
|
81
|
-
end
|
82
|
-
|
83
|
-
it "sets slug on validation" do
|
84
|
-
cat = Cat.new(name: 'Prince Chunk')
|
85
|
-
assert cat.valid?
|
86
|
-
assert_equal 'prince-chunk', cat.slug
|
87
|
-
end
|
88
|
-
|
89
|
-
it "is invalid when slug is taken" do
|
90
|
-
Cat.create(slug: 'mrs-chippy')
|
91
|
-
cat = Cat.new(name: 'Mrs. Chippy')
|
92
|
-
refute cat.valid?
|
93
|
-
assert_nil cat.to_param
|
94
|
-
end
|
24
|
+
it "includes ValidateExclusionOf" do
|
25
|
+
assert Cat.new.is_a? Sluggi::ValidateExclusionOf
|
95
26
|
end
|
96
27
|
|
97
|
-
|
98
|
-
|
99
|
-
cat = CandidateCat.new(name: 'Smokey')
|
100
|
-
assert cat.valid?
|
101
|
-
assert_equal 'smokey', cat.slug
|
102
|
-
end
|
28
|
+
it "includes Model" do
|
29
|
+
assert Cat.new.is_a? Sluggi::Model
|
103
30
|
end
|
104
|
-
|
105
31
|
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ValidatePresenceTest < MiniTest::Spec
|
4
|
+
class Cat < ActiveRecord::Base
|
5
|
+
include Sluggi::ValidatePresence
|
6
|
+
end
|
7
|
+
|
8
|
+
it "validates presence of slug" do
|
9
|
+
refute Cat.new(slug: '').valid?
|
10
|
+
assert Cat.new(slug: 'foo').valid?
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ValidateUniquenessTest < MiniTest::Spec
|
4
|
+
class Cat < ActiveRecord::Base
|
5
|
+
include Sluggi::Model
|
6
|
+
include Sluggi::ValidateUniqueness
|
7
|
+
|
8
|
+
def slug_value
|
9
|
+
name
|
10
|
+
end
|
11
|
+
|
12
|
+
def slug_value_changed?
|
13
|
+
name_changed?
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
it "validates slug is unique" do
|
18
|
+
Cat.create(slug: 'mrs-chippy')
|
19
|
+
cat = Cat.new(name: 'Mrs. Chippy')
|
20
|
+
refute cat.valid?
|
21
|
+
assert_nil cat.to_param
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
class ValidatesExclusionOfTest < MiniTest::Spec
|
4
|
+
class Cat < ActiveRecord::Base
|
5
|
+
include Sluggi::ValidateExclusionOf
|
6
|
+
end
|
7
|
+
|
8
|
+
describe ".reserved_slugs" do
|
9
|
+
%w(create login users).each do |word|
|
10
|
+
it "includes #{word}" do
|
11
|
+
assert_includes Cat.reserved_slugs, word
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
it "does not include valid slug" do
|
16
|
+
refute_includes Cat.reserved_slugs, 'something'
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "validation" do
|
21
|
+
it "ensures slug is not a reserved word" do
|
22
|
+
refute Cat.new(slug: 'edit').valid?
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sluggi
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tee Parham
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-
|
11
|
+
date: 2014-12-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -97,15 +97,23 @@ files:
|
|
97
97
|
- lib/sluggi/generators/sluggi_generator.rb
|
98
98
|
- lib/sluggi/history.rb
|
99
99
|
- lib/sluggi/migrations/create_slugs.rb
|
100
|
+
- lib/sluggi/model.rb
|
100
101
|
- lib/sluggi/slug.rb
|
101
102
|
- lib/sluggi/slugged.rb
|
103
|
+
- lib/sluggi/validate_exclusion_of.rb
|
104
|
+
- lib/sluggi/validate_presence.rb
|
105
|
+
- lib/sluggi/validate_uniqueness.rb
|
102
106
|
- lib/sluggi/version.rb
|
103
107
|
- sluggi.gemspec
|
104
108
|
- test/generator_test.rb
|
105
109
|
- test/history_test.rb
|
110
|
+
- test/model_test.rb
|
106
111
|
- test/slug_test.rb
|
107
112
|
- test/slugged_test.rb
|
108
113
|
- test/test_helper.rb
|
114
|
+
- test/validate_presence_test.rb
|
115
|
+
- test/validate_uniqueness_test.rb
|
116
|
+
- test/validates_exclusion_of_test.rb
|
109
117
|
homepage: https://github.com/neighborland/sluggi
|
110
118
|
licenses:
|
111
119
|
- MIT
|
@@ -126,14 +134,18 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
126
134
|
version: '0'
|
127
135
|
requirements: []
|
128
136
|
rubyforge_project:
|
129
|
-
rubygems_version: 2.
|
137
|
+
rubygems_version: 2.4.4
|
130
138
|
signing_key:
|
131
139
|
specification_version: 4
|
132
140
|
summary: Rails Slug Generator
|
133
141
|
test_files:
|
134
142
|
- test/generator_test.rb
|
135
143
|
- test/history_test.rb
|
144
|
+
- test/model_test.rb
|
136
145
|
- test/slug_test.rb
|
137
146
|
- test/slugged_test.rb
|
138
147
|
- test/test_helper.rb
|
148
|
+
- test/validate_presence_test.rb
|
149
|
+
- test/validate_uniqueness_test.rb
|
150
|
+
- test/validates_exclusion_of_test.rb
|
139
151
|
has_rdoc:
|