slugalicious 1.0.0 → 1.1.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.
- data/LICENSE +1 -1
- data/README.textile +16 -6
- data/lib/slugalicious.rb +10 -6
- data/slugalicious.gemspec +29 -33
- metadata +92 -74
- data/.document +0 -5
- data/.gitignore +0 -26
- data/.rspec +0 -1
- data/Gemfile +0 -17
- data/Gemfile.lock +0 -107
- data/Rakefile +0 -37
- data/VERSION +0 -1
- data/spec/factories.rb +0 -14
- data/spec/slug_spec.rb +0 -65
- data/spec/slugalicious_spec.rb +0 -232
- data/spec/spec_helper.rb +0 -45
data/LICENSE
CHANGED
data/README.textile
CHANGED
@@ -3,7 +3,7 @@ h1. Slugalicious -- Easy and powerful URL slugging for Rails 3
|
|
3
3
|
_*(no monkey-patching required)*_
|
4
4
|
|
5
5
|
| *Author* | Tim Morgan |
|
6
|
-
| *Version* | 1.
|
6
|
+
| *Version* | 1.1 (Aug 13, 2011) |
|
7
7
|
| *License* | Released under the MIT license. |
|
8
8
|
|
9
9
|
h2. About
|
@@ -186,11 +186,21 @@ def find_product
|
|
186
186
|
end
|
187
187
|
</code></pre>
|
188
188
|
|
189
|
-
The old URL will remain indefinitely, but users who hit it will be redirected to
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
189
|
+
The old URL will remain indefinitely, but users who hit it will be redirected to
|
190
|
+
the new URL. Ideally, links to the old URL will be replaced over time with links
|
191
|
+
to the new URL.
|
192
|
+
|
193
|
+
The problem is that even though the old slug is inactive, it's still "taken." If
|
194
|
+
you create a product called "Keyboard", but then rename it to "Piano", the
|
195
|
+
product will claim both the "keyboard" and "piano" slugs. If you had renamed it
|
196
|
+
to make room for a different product called "Keyboard" (like a computer
|
197
|
+
keyboard), you'd find its slug is "keyboard;2" or similar.
|
198
|
+
|
199
|
+
To prevent the slug namespace from becoming more and more polluted over time,
|
200
|
+
websites generally expire inactive slugs after a period of time. To do this in
|
201
|
+
Slugalicious, write a task that periodically checks for and deletes old,
|
202
|
+
inactive @Slug@ records. Such a task could be invoked through a cron job, for
|
203
|
+
instance. An example:
|
194
204
|
|
195
205
|
<pre><code>
|
196
206
|
Slug.inactive.where([ "created_at < ?", 30.days.ago ]).delete_all
|
data/lib/slugalicious.rb
CHANGED
@@ -147,22 +147,26 @@ module Slugalicious
|
|
147
147
|
|
148
148
|
module InstanceMethods
|
149
149
|
|
150
|
+
def slug_object
|
151
|
+
slugs.loaded? ? slugs.detect(&:active) : slugs.active.first
|
152
|
+
end
|
153
|
+
private :slug_object
|
154
|
+
|
150
155
|
# @return [String, nil] The slug for this object, or @nil@ if none has been
|
151
156
|
# assigned.
|
152
157
|
|
153
158
|
def slug
|
154
|
-
|
159
|
+
Rails.cache.fetch("Slug/#{self.class.to_s}/#{id}/slug") do
|
160
|
+
slug_object.try(:slug)
|
161
|
+
end
|
155
162
|
end
|
156
163
|
|
157
164
|
# @return [String, nil] The full slug and path for this object, with scope
|
158
165
|
# included, or @nil@ if none has been assigned.
|
159
166
|
|
160
167
|
def slug_with_path
|
161
|
-
|
162
|
-
|
163
|
-
slug.scope.to_s + slug.slug
|
164
|
-
else
|
165
|
-
nil
|
168
|
+
Rails.cache.fetch("Slug/#{self.class.to_s}/#{id}/slug_with_path") do
|
169
|
+
slug_object ? (slug_object.scope.to_s + slug_object.slug) : nil
|
166
170
|
end
|
167
171
|
end
|
168
172
|
|
data/slugalicious.gemspec
CHANGED
@@ -1,68 +1,64 @@
|
|
1
1
|
# Generated by jeweler
|
2
2
|
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
4
|
# -*- encoding: utf-8 -*-
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{slugalicious}
|
8
|
-
s.version = "1.
|
8
|
+
s.version = "1.1.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
-
s.authors = [
|
12
|
-
s.date = %q{
|
11
|
+
s.authors = [%q{Tim Morgan}]
|
12
|
+
s.date = %q{2011-08-13}
|
13
13
|
s.description = %q{Slugalicious adds simple and powerful slugging to your ActiveRecord models.}
|
14
14
|
s.email = %q{git@timothymorgan.info}
|
15
15
|
s.extra_rdoc_files = [
|
16
16
|
"LICENSE",
|
17
|
-
|
17
|
+
"README.textile"
|
18
18
|
]
|
19
19
|
s.files = [
|
20
|
-
"
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
"Rakefile",
|
28
|
-
"VERSION",
|
29
|
-
"lib/slugalicious.rb",
|
30
|
-
"lib/slugalicious_generator.rb",
|
31
|
-
"slugalicious.gemspec",
|
32
|
-
"spec/factories.rb",
|
33
|
-
"spec/slug_spec.rb",
|
34
|
-
"spec/slugalicious_spec.rb",
|
35
|
-
"spec/spec_helper.rb",
|
36
|
-
"templates/create_slugs.rb",
|
37
|
-
"templates/slug.rb"
|
20
|
+
"LICENSE",
|
21
|
+
"README.textile",
|
22
|
+
"lib/slugalicious.rb",
|
23
|
+
"lib/slugalicious_generator.rb",
|
24
|
+
"slugalicious.gemspec",
|
25
|
+
"templates/create_slugs.rb",
|
26
|
+
"templates/slug.rb"
|
38
27
|
]
|
39
28
|
s.homepage = %q{http://github.com/riscfuture/slugalicious}
|
40
|
-
s.
|
41
|
-
s.require_paths = ["lib"]
|
29
|
+
s.require_paths = [%q{lib}]
|
42
30
|
s.required_ruby_version = Gem::Requirement.new(">= 1.9")
|
43
|
-
s.rubygems_version = %q{1.
|
31
|
+
s.rubygems_version = %q{1.8.7}
|
44
32
|
s.summary = %q{Easy-to-use and powerful slugging for Rails 3}
|
45
|
-
s.test_files = [
|
46
|
-
"spec/factories.rb",
|
47
|
-
"spec/slug_spec.rb",
|
48
|
-
"spec/slugalicious_spec.rb",
|
49
|
-
"spec/spec_helper.rb"
|
50
|
-
]
|
51
33
|
|
52
34
|
if s.respond_to? :specification_version then
|
53
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
54
35
|
s.specification_version = 3
|
55
36
|
|
56
37
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
57
38
|
s.add_runtime_dependency(%q<rails>, [">= 3.0"])
|
58
39
|
s.add_runtime_dependency(%q<stringex>, [">= 0"])
|
40
|
+
s.add_runtime_dependency(%q<jeweler>, [">= 0"])
|
41
|
+
s.add_runtime_dependency(%q<yard>, [">= 0"])
|
42
|
+
s.add_runtime_dependency(%q<RedCloth>, [">= 0"])
|
43
|
+
s.add_runtime_dependency(%q<sqlite3>, [">= 0"])
|
44
|
+
s.add_runtime_dependency(%q<rspec>, [">= 0"])
|
59
45
|
else
|
60
46
|
s.add_dependency(%q<rails>, [">= 3.0"])
|
61
47
|
s.add_dependency(%q<stringex>, [">= 0"])
|
48
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
49
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
50
|
+
s.add_dependency(%q<RedCloth>, [">= 0"])
|
51
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
52
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
62
53
|
end
|
63
54
|
else
|
64
55
|
s.add_dependency(%q<rails>, [">= 3.0"])
|
65
56
|
s.add_dependency(%q<stringex>, [">= 0"])
|
57
|
+
s.add_dependency(%q<jeweler>, [">= 0"])
|
58
|
+
s.add_dependency(%q<yard>, [">= 0"])
|
59
|
+
s.add_dependency(%q<RedCloth>, [">= 0"])
|
60
|
+
s.add_dependency(%q<sqlite3>, [">= 0"])
|
61
|
+
s.add_dependency(%q<rspec>, [">= 0"])
|
66
62
|
end
|
67
63
|
end
|
68
64
|
|
metadata
CHANGED
@@ -1,112 +1,130 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: slugalicious
|
3
|
-
version: !ruby/object:Gem::Version
|
4
|
-
|
5
|
-
|
6
|
-
- 1
|
7
|
-
- 0
|
8
|
-
- 0
|
9
|
-
version: 1.0.0
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 1.1.0
|
5
|
+
prerelease:
|
10
6
|
platform: ruby
|
11
|
-
authors:
|
7
|
+
authors:
|
12
8
|
- Tim Morgan
|
13
9
|
autorequire:
|
14
10
|
bindir: bin
|
15
11
|
cert_chain: []
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
dependencies:
|
20
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-08-13 00:00:00.000000000Z
|
13
|
+
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
21
15
|
name: rails
|
22
|
-
requirement: &
|
16
|
+
requirement: &2162887120 !ruby/object:Gem::Requirement
|
23
17
|
none: false
|
24
|
-
requirements:
|
25
|
-
- -
|
26
|
-
- !ruby/object:Gem::Version
|
27
|
-
|
28
|
-
- 3
|
29
|
-
- 0
|
30
|
-
version: "3.0"
|
18
|
+
requirements:
|
19
|
+
- - ! '>='
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.0'
|
31
22
|
type: :runtime
|
32
23
|
prerelease: false
|
33
|
-
version_requirements: *
|
34
|
-
- !ruby/object:Gem::Dependency
|
24
|
+
version_requirements: *2162887120
|
25
|
+
- !ruby/object:Gem::Dependency
|
35
26
|
name: stringex
|
36
|
-
requirement: &
|
27
|
+
requirement: &2162886240 !ruby/object:Gem::Requirement
|
28
|
+
none: false
|
29
|
+
requirements:
|
30
|
+
- - ! '>='
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '0'
|
33
|
+
type: :runtime
|
34
|
+
prerelease: false
|
35
|
+
version_requirements: *2162886240
|
36
|
+
- !ruby/object:Gem::Dependency
|
37
|
+
name: jeweler
|
38
|
+
requirement: &2162884900 !ruby/object:Gem::Requirement
|
39
|
+
none: false
|
40
|
+
requirements:
|
41
|
+
- - ! '>='
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: '0'
|
44
|
+
type: :runtime
|
45
|
+
prerelease: false
|
46
|
+
version_requirements: *2162884900
|
47
|
+
- !ruby/object:Gem::Dependency
|
48
|
+
name: yard
|
49
|
+
requirement: &2162884020 !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ! '>='
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
type: :runtime
|
56
|
+
prerelease: false
|
57
|
+
version_requirements: *2162884020
|
58
|
+
- !ruby/object:Gem::Dependency
|
59
|
+
name: RedCloth
|
60
|
+
requirement: &2162883400 !ruby/object:Gem::Requirement
|
61
|
+
none: false
|
62
|
+
requirements:
|
63
|
+
- - ! '>='
|
64
|
+
- !ruby/object:Gem::Version
|
65
|
+
version: '0'
|
66
|
+
type: :runtime
|
67
|
+
prerelease: false
|
68
|
+
version_requirements: *2162883400
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
requirement: &2162882740 !ruby/object:Gem::Requirement
|
72
|
+
none: false
|
73
|
+
requirements:
|
74
|
+
- - ! '>='
|
75
|
+
- !ruby/object:Gem::Version
|
76
|
+
version: '0'
|
77
|
+
type: :runtime
|
78
|
+
prerelease: false
|
79
|
+
version_requirements: *2162882740
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: rspec
|
82
|
+
requirement: &2162882100 !ruby/object:Gem::Requirement
|
37
83
|
none: false
|
38
|
-
requirements:
|
39
|
-
- -
|
40
|
-
- !ruby/object:Gem::Version
|
41
|
-
|
42
|
-
- 0
|
43
|
-
version: "0"
|
84
|
+
requirements:
|
85
|
+
- - ! '>='
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: '0'
|
44
88
|
type: :runtime
|
45
89
|
prerelease: false
|
46
|
-
version_requirements: *
|
90
|
+
version_requirements: *2162882100
|
47
91
|
description: Slugalicious adds simple and powerful slugging to your ActiveRecord models.
|
48
92
|
email: git@timothymorgan.info
|
49
93
|
executables: []
|
50
|
-
|
51
94
|
extensions: []
|
52
|
-
|
53
|
-
extra_rdoc_files:
|
95
|
+
extra_rdoc_files:
|
54
96
|
- LICENSE
|
55
97
|
- README.textile
|
56
|
-
files:
|
57
|
-
- .document
|
58
|
-
- .gitignore
|
59
|
-
- .rspec
|
60
|
-
- Gemfile
|
61
|
-
- Gemfile.lock
|
98
|
+
files:
|
62
99
|
- LICENSE
|
63
100
|
- README.textile
|
64
|
-
- Rakefile
|
65
|
-
- VERSION
|
66
101
|
- lib/slugalicious.rb
|
67
102
|
- lib/slugalicious_generator.rb
|
68
103
|
- slugalicious.gemspec
|
69
|
-
- spec/factories.rb
|
70
|
-
- spec/slug_spec.rb
|
71
|
-
- spec/slugalicious_spec.rb
|
72
|
-
- spec/spec_helper.rb
|
73
104
|
- templates/create_slugs.rb
|
74
105
|
- templates/slug.rb
|
75
|
-
has_rdoc: true
|
76
106
|
homepage: http://github.com/riscfuture/slugalicious
|
77
107
|
licenses: []
|
78
|
-
|
79
108
|
post_install_message:
|
80
|
-
rdoc_options:
|
81
|
-
|
82
|
-
require_paths:
|
109
|
+
rdoc_options: []
|
110
|
+
require_paths:
|
83
111
|
- lib
|
84
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
85
113
|
none: false
|
86
|
-
requirements:
|
87
|
-
- -
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
|
90
|
-
|
91
|
-
- 9
|
92
|
-
version: "1.9"
|
93
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ! '>='
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '1.9'
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
94
119
|
none: false
|
95
|
-
requirements:
|
96
|
-
- -
|
97
|
-
- !ruby/object:Gem::Version
|
98
|
-
|
99
|
-
- 0
|
100
|
-
version: "0"
|
120
|
+
requirements:
|
121
|
+
- - ! '>='
|
122
|
+
- !ruby/object:Gem::Version
|
123
|
+
version: '0'
|
101
124
|
requirements: []
|
102
|
-
|
103
125
|
rubyforge_project:
|
104
|
-
rubygems_version: 1.
|
126
|
+
rubygems_version: 1.8.7
|
105
127
|
signing_key:
|
106
128
|
specification_version: 3
|
107
129
|
summary: Easy-to-use and powerful slugging for Rails 3
|
108
|
-
test_files:
|
109
|
-
- spec/factories.rb
|
110
|
-
- spec/slug_spec.rb
|
111
|
-
- spec/slugalicious_spec.rb
|
112
|
-
- spec/spec_helper.rb
|
130
|
+
test_files: []
|
data/.document
DELETED
data/.gitignore
DELETED
@@ -1,26 +0,0 @@
|
|
1
|
-
## MAC OS
|
2
|
-
.DS_Store
|
3
|
-
|
4
|
-
## TEXTMATE
|
5
|
-
*.tmproj
|
6
|
-
tmtags
|
7
|
-
|
8
|
-
## EMACS
|
9
|
-
*~
|
10
|
-
\#*
|
11
|
-
.\#*
|
12
|
-
|
13
|
-
## VIM
|
14
|
-
*.swp
|
15
|
-
|
16
|
-
## PROJECT::GENERAL
|
17
|
-
coverage
|
18
|
-
rdoc
|
19
|
-
pkg
|
20
|
-
.bundle
|
21
|
-
.rvmrc
|
22
|
-
test.sqlite
|
23
|
-
|
24
|
-
## PROJECT::DOCUMENTATION
|
25
|
-
.yardoc
|
26
|
-
doc
|
data/.rspec
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
-cfs
|
data/Gemfile
DELETED
@@ -1,17 +0,0 @@
|
|
1
|
-
source :rubygems
|
2
|
-
|
3
|
-
# DEPENDENCIES
|
4
|
-
gem 'rails', '>= 3.0'
|
5
|
-
gem 'stringex'
|
6
|
-
|
7
|
-
# DEVELOPMENT
|
8
|
-
gem 'jeweler'
|
9
|
-
gem 'yard'
|
10
|
-
gem 'RedCloth', require: 'redcloth'
|
11
|
-
gem 'sqlite3'
|
12
|
-
|
13
|
-
# TEST
|
14
|
-
gem 'rspec'
|
15
|
-
group :test do
|
16
|
-
gem 'factory_girl'
|
17
|
-
end
|
data/Gemfile.lock
DELETED
@@ -1,107 +0,0 @@
|
|
1
|
-
GEM
|
2
|
-
remote: http://rubygems.org/
|
3
|
-
specs:
|
4
|
-
RedCloth (4.2.3)
|
5
|
-
abstract (1.0.0)
|
6
|
-
actionmailer (3.0.1)
|
7
|
-
actionpack (= 3.0.1)
|
8
|
-
mail (~> 2.2.5)
|
9
|
-
actionpack (3.0.1)
|
10
|
-
activemodel (= 3.0.1)
|
11
|
-
activesupport (= 3.0.1)
|
12
|
-
builder (~> 2.1.2)
|
13
|
-
erubis (~> 2.6.6)
|
14
|
-
i18n (~> 0.4.1)
|
15
|
-
rack (~> 1.2.1)
|
16
|
-
rack-mount (~> 0.6.12)
|
17
|
-
rack-test (~> 0.5.4)
|
18
|
-
tzinfo (~> 0.3.23)
|
19
|
-
activemodel (3.0.1)
|
20
|
-
activesupport (= 3.0.1)
|
21
|
-
builder (~> 2.1.2)
|
22
|
-
i18n (~> 0.4.1)
|
23
|
-
activerecord (3.0.1)
|
24
|
-
activemodel (= 3.0.1)
|
25
|
-
activesupport (= 3.0.1)
|
26
|
-
arel (~> 1.0.0)
|
27
|
-
tzinfo (~> 0.3.23)
|
28
|
-
activeresource (3.0.1)
|
29
|
-
activemodel (= 3.0.1)
|
30
|
-
activesupport (= 3.0.1)
|
31
|
-
activesupport (3.0.1)
|
32
|
-
arel (1.0.1)
|
33
|
-
activesupport (~> 3.0.0)
|
34
|
-
builder (2.1.2)
|
35
|
-
diff-lcs (1.1.2)
|
36
|
-
erubis (2.6.6)
|
37
|
-
abstract (>= 1.0.0)
|
38
|
-
factory_girl (1.3.2)
|
39
|
-
ffi (0.6.3)
|
40
|
-
rake (>= 0.8.7)
|
41
|
-
gemcutter (0.6.1)
|
42
|
-
git (1.2.5)
|
43
|
-
i18n (0.4.2)
|
44
|
-
jeweler (1.4.0)
|
45
|
-
gemcutter (>= 0.1.0)
|
46
|
-
git (>= 1.2.5)
|
47
|
-
rubyforge (>= 2.0.0)
|
48
|
-
json_pure (1.4.6)
|
49
|
-
mail (2.2.9)
|
50
|
-
activesupport (>= 2.3.6)
|
51
|
-
i18n (~> 0.4.1)
|
52
|
-
mime-types (~> 1.16)
|
53
|
-
treetop (~> 1.4.8)
|
54
|
-
mime-types (1.16)
|
55
|
-
polyglot (0.3.1)
|
56
|
-
rack (1.2.1)
|
57
|
-
rack-mount (0.6.13)
|
58
|
-
rack (>= 1.0.0)
|
59
|
-
rack-test (0.5.6)
|
60
|
-
rack (>= 1.0)
|
61
|
-
rails (3.0.1)
|
62
|
-
actionmailer (= 3.0.1)
|
63
|
-
actionpack (= 3.0.1)
|
64
|
-
activerecord (= 3.0.1)
|
65
|
-
activeresource (= 3.0.1)
|
66
|
-
activesupport (= 3.0.1)
|
67
|
-
bundler (~> 1.0.0)
|
68
|
-
railties (= 3.0.1)
|
69
|
-
railties (3.0.1)
|
70
|
-
actionpack (= 3.0.1)
|
71
|
-
activesupport (= 3.0.1)
|
72
|
-
rake (>= 0.8.4)
|
73
|
-
thor (~> 0.14.0)
|
74
|
-
rake (0.8.7)
|
75
|
-
rspec (2.0.1)
|
76
|
-
rspec-core (~> 2.0.1)
|
77
|
-
rspec-expectations (~> 2.0.1)
|
78
|
-
rspec-mocks (~> 2.0.1)
|
79
|
-
rspec-core (2.0.1)
|
80
|
-
rspec-expectations (2.0.1)
|
81
|
-
diff-lcs (>= 1.1.2)
|
82
|
-
rspec-mocks (2.0.1)
|
83
|
-
rspec-core (~> 2.0.1)
|
84
|
-
rspec-expectations (~> 2.0.1)
|
85
|
-
rubyforge (2.0.4)
|
86
|
-
json_pure (>= 1.1.7)
|
87
|
-
sqlite3 (0.1.1)
|
88
|
-
ffi (>= 0.6.3)
|
89
|
-
stringex (1.2.0)
|
90
|
-
thor (0.14.3)
|
91
|
-
treetop (1.4.8)
|
92
|
-
polyglot (>= 0.3.1)
|
93
|
-
tzinfo (0.3.23)
|
94
|
-
yard (0.6.1)
|
95
|
-
|
96
|
-
PLATFORMS
|
97
|
-
ruby
|
98
|
-
|
99
|
-
DEPENDENCIES
|
100
|
-
RedCloth
|
101
|
-
factory_girl
|
102
|
-
jeweler
|
103
|
-
rails (>= 3.0)
|
104
|
-
rspec
|
105
|
-
sqlite3
|
106
|
-
stringex
|
107
|
-
yard
|
data/Rakefile
DELETED
@@ -1,37 +0,0 @@
|
|
1
|
-
require 'rake'
|
2
|
-
begin
|
3
|
-
require 'bundler'
|
4
|
-
rescue LoadError
|
5
|
-
puts "Bundler is not installed; install with `gem install bundler`."
|
6
|
-
exit 1
|
7
|
-
end
|
8
|
-
|
9
|
-
Bundler.require :default
|
10
|
-
|
11
|
-
Jeweler::Tasks.new do |gem|
|
12
|
-
gem.name = "slugalicious"
|
13
|
-
gem.summary = %Q{Easy-to-use and powerful slugging for Rails 3}
|
14
|
-
gem.description = %Q{Slugalicious adds simple and powerful slugging to your ActiveRecord models.}
|
15
|
-
gem.email = "git@timothymorgan.info"
|
16
|
-
gem.homepage = "http://github.com/riscfuture/slugalicious"
|
17
|
-
gem.authors = [ "Tim Morgan" ]
|
18
|
-
gem.required_ruby_version = '>= 1.9'
|
19
|
-
gem.add_dependency "rails", ">= 3.0"
|
20
|
-
gem.add_dependency 'stringex'
|
21
|
-
end
|
22
|
-
Jeweler::GemcutterTasks.new
|
23
|
-
|
24
|
-
require 'rspec/core/rake_task'
|
25
|
-
RSpec::Core::RakeTask.new
|
26
|
-
|
27
|
-
YARD::Rake::YardocTask.new('doc') do |doc|
|
28
|
-
doc.options << "-m" << "textile"
|
29
|
-
doc.options << "--protected"
|
30
|
-
doc.options << "-r" << "README.textile"
|
31
|
-
doc.options << "-o" << "doc"
|
32
|
-
doc.options << "--title" << "Slugalicious Documentation".inspect
|
33
|
-
|
34
|
-
doc.files = [ 'lib/**/*', 'README.textile', 'templates/slug.rb' ]
|
35
|
-
end
|
36
|
-
|
37
|
-
task(default: :spec)
|
data/VERSION
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
1.0.0
|
data/spec/factories.rb
DELETED
@@ -1,14 +0,0 @@
|
|
1
|
-
Factory.define :slug do |f|
|
2
|
-
f.sequence(:slug) { |n| "slug-#{n}" }
|
3
|
-
f.active true
|
4
|
-
end
|
5
|
-
|
6
|
-
Factory.define :user do |f|
|
7
|
-
f.first_name "Doctor"
|
8
|
-
f.last_name "Spaceman"
|
9
|
-
end
|
10
|
-
|
11
|
-
Factory.define :abuser do |f|
|
12
|
-
f.first_name "Doctor"
|
13
|
-
f.last_name "Spaceman"
|
14
|
-
end
|
data/spec/slug_spec.rb
DELETED
@@ -1,65 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Slug do
|
4
|
-
before :each do
|
5
|
-
@record = Factory(:user)
|
6
|
-
Slug.delete_all
|
7
|
-
end
|
8
|
-
|
9
|
-
describe "validation" do
|
10
|
-
it "should not allow an active slug to be created if one already exists" do
|
11
|
-
Factory(:slug, sluggable: @record)
|
12
|
-
slug = Factory.build(:slug, sluggable: @record)
|
13
|
-
slug.should_not be_valid
|
14
|
-
slug.errors[:active].should_not be_empty
|
15
|
-
end
|
16
|
-
|
17
|
-
it "should not allow a slug to be made active if one already exists" do
|
18
|
-
Factory(:slug, sluggable: @record)
|
19
|
-
slug = Factory(:slug, sluggable: @record, active: false)
|
20
|
-
slug.active = true
|
21
|
-
slug.should_not be_valid
|
22
|
-
slug.errors[:active].should_not be_empty
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should allow an active slug to be created if none exists" do
|
26
|
-
slug = Factory.build(:slug, sluggable: @record)
|
27
|
-
slug.should be_valid
|
28
|
-
end
|
29
|
-
|
30
|
-
it "should allow a slug to be made active if none exists" do
|
31
|
-
slug = Factory(:slug, sluggable: @record, active: false)
|
32
|
-
slug.active = true
|
33
|
-
slug.should be_valid
|
34
|
-
end
|
35
|
-
|
36
|
-
it "should allow an inactive slug to be modified if the active field is not changing" do
|
37
|
-
Factory(:slug, sluggable: @record)
|
38
|
-
slug = Factory(:slug, sluggable: @record, active: false)
|
39
|
-
slug.scope = 'test'
|
40
|
-
slug.should be_valid
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
describe "#activate!" do
|
45
|
-
it "should mark the slug as active" do
|
46
|
-
slug = Factory(:slug, sluggable: Factory(:user), active: false)
|
47
|
-
slug.activate!
|
48
|
-
slug.should be_active
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should deactivate all the record's other slugs" do
|
52
|
-
record = Factory(:user)
|
53
|
-
s1 = Slug.for(record).first
|
54
|
-
s2 = Factory(:slug, sluggable: record, active: false)
|
55
|
-
s3 = Factory(:slug, sluggable: record, active: false)
|
56
|
-
|
57
|
-
slug = Factory(:slug, sluggable: record, active: false)
|
58
|
-
slug.activate!
|
59
|
-
|
60
|
-
s1.reload.should_not be_active
|
61
|
-
s2.reload.should_not be_active
|
62
|
-
s3.reload.should_not be_active
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
data/spec/slugalicious_spec.rb
DELETED
@@ -1,232 +0,0 @@
|
|
1
|
-
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
-
|
3
|
-
describe Slugalicious do
|
4
|
-
before :each do
|
5
|
-
@model = Class.new
|
6
|
-
@model.send :include, ActiveModel::Validations
|
7
|
-
@model.send :include, ActiveModel::Validations::Callbacks
|
8
|
-
@model.send :include, ActiveRecord::Callbacks
|
9
|
-
@model.send :include, ActiveRecord::Validations
|
10
|
-
@model.stub!(:has_many)
|
11
|
-
@model.send :include, Slugalicious
|
12
|
-
end
|
13
|
-
|
14
|
-
describe "#slugged" do
|
15
|
-
it "should raise an error if no generators are given" do
|
16
|
-
expect { @model.send(:slugged, { options: 'here' }) }.to raise_error(ArgumentError)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
describe "#to_param" do
|
21
|
-
it "should return the slug" do
|
22
|
-
user = Factory(:user)
|
23
|
-
user.slug.should_not be_nil
|
24
|
-
user.to_param.should eql(user.slug)
|
25
|
-
end
|
26
|
-
|
27
|
-
it "should return the full slug path when scoped" do
|
28
|
-
User._slug_procs.clear
|
29
|
-
User.send :slugged, :first_name, scope: :last_name
|
30
|
-
|
31
|
-
user = Factory(:user, last_name: 'test/')
|
32
|
-
user.to_param.should eql('test/doctor')
|
33
|
-
end
|
34
|
-
end
|
35
|
-
|
36
|
-
context "slug generation" do
|
37
|
-
before :each do
|
38
|
-
User._slug_procs.clear
|
39
|
-
User._slug_blacklist.clear
|
40
|
-
end
|
41
|
-
|
42
|
-
it "should set the slug according to the generator and apply the slugifier" do
|
43
|
-
User.send :slugged, :first_name
|
44
|
-
object = Factory(:user, first_name: "Sancho", last_name: "Sample")
|
45
|
-
object.slug.should eql("sancho")
|
46
|
-
end
|
47
|
-
|
48
|
-
it "should generate from a proc as well as a symbol" do
|
49
|
-
User.send :slugged, ->(person) { "#{person.first_name} #{person.last_name}" }
|
50
|
-
object = Factory(:user, first_name: "Foo", last_name: "bar")
|
51
|
-
object.slug.should eql("foo-bar")
|
52
|
-
end
|
53
|
-
|
54
|
-
it "should give priority to the first non-nil slug" do
|
55
|
-
User.send :slugged, :gender, :last_name
|
56
|
-
object = Factory(:user, gender: nil, last_name: "Bar")
|
57
|
-
object.slug.should eql("bar")
|
58
|
-
end
|
59
|
-
|
60
|
-
it "should not create a new slug if an existing one matches" do
|
61
|
-
User.send :slugged, :first_name, :last_name
|
62
|
-
object = Factory(:user, first_name: 'Foo', last_name: "Bar")
|
63
|
-
object.slug.should eql("foo")
|
64
|
-
other_slug = Factory(:slug, slug: 'bar', sluggable: object, active: false)
|
65
|
-
|
66
|
-
object.update_attribute :last_name, 'baz'
|
67
|
-
object.slug.should eql("foo")
|
68
|
-
other_slug.reload.active.should be_false
|
69
|
-
end
|
70
|
-
|
71
|
-
it "should ignore slugs from other models" do
|
72
|
-
User.send :slugged, :first_name, :last_name
|
73
|
-
Factory(:abuser, last_name: 'Foo').slug.should eql('foo')
|
74
|
-
Factory(:user, first_name: 'Foo', last_name: 'Foo').slug.should eql('foo')
|
75
|
-
end
|
76
|
-
|
77
|
-
it "should use the last-resort generator if nothing else is unique" do
|
78
|
-
User.send :slugged, :first_name, :last_name
|
79
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar').slug.should eql('foo')
|
80
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar').slug.should eql('bar')
|
81
|
-
user = Factory(:user, first_name: 'Foo', last_name: 'Bar')
|
82
|
-
user.slug.should eql("foo;#{user.id}")
|
83
|
-
end
|
84
|
-
|
85
|
-
it "should raise an error if all generators return nil" do
|
86
|
-
User.send :slugged, :gender, :birthdate
|
87
|
-
-> { Factory(:user, gender: nil, birthdate: nil) }.should raise_error
|
88
|
-
end
|
89
|
-
|
90
|
-
it "should use the first non-nil slug for the last-resort generator" do
|
91
|
-
User.send :slugged, :gender, :first_name, :last_name
|
92
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar', gender: nil)
|
93
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar', gender: nil)
|
94
|
-
user = Factory(:user, first_name: 'Foo', last_name: 'Bar', gender: nil)
|
95
|
-
user.slug.should eql("foo;#{user.id}")
|
96
|
-
end
|
97
|
-
|
98
|
-
it "should use a custom id separator if given" do
|
99
|
-
User.send :slugged, :first_name, :last_name, id_separator: ':'
|
100
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar')
|
101
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar')
|
102
|
-
user = Factory(:user, first_name: 'Foo', last_name: 'Bar')
|
103
|
-
user.slug.should eql("foo:#{user.id}")
|
104
|
-
end
|
105
|
-
|
106
|
-
it "should avoid blacklisted slugs" do
|
107
|
-
User.send :slugged, :first_name, :last_name
|
108
|
-
Factory(:user, first_name: 'New', last_name: 'Bar').slug.should eql('bar')
|
109
|
-
end
|
110
|
-
|
111
|
-
it "should use a custom blacklist" do
|
112
|
-
User.send :slugged, :first_name, :last_name, blacklist: %w( foo bar )
|
113
|
-
Factory(:user, first_name: 'Foo', last_name: 'Baz').slug.should eql('baz')
|
114
|
-
end
|
115
|
-
|
116
|
-
it "should wrap the blacklist array" do
|
117
|
-
User.send :slugged, :first_name, :last_name, blacklist: 'foo'
|
118
|
-
Factory(:user, first_name: 'Foo', last_name: 'Baz').slug.should eql('baz')
|
119
|
-
end
|
120
|
-
|
121
|
-
it "should only search for available slugs inside the scope if given" do
|
122
|
-
User.send :slugged, :first_name, :last_name, scope: :callsign
|
123
|
-
|
124
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar', callsign: 'One').slug.should eql('foo')
|
125
|
-
Factory(:user, first_name: 'Foo', last_name: 'Baz', callsign: 'One').slug.should eql('baz')
|
126
|
-
Factory(:user, first_name: 'Boo', last_name: 'Bar', callsign: 'One').slug.should eql('boo')
|
127
|
-
|
128
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar', callsign: 'Two').slug.should eql('foo')
|
129
|
-
Factory(:user, first_name: 'Foo', last_name: 'Baz', callsign: 'Two').slug.should eql('baz')
|
130
|
-
end
|
131
|
-
|
132
|
-
it "should accept a proc for a scope" do
|
133
|
-
User.send :slugged, :first_name, :last_name, scope: ->(object) { object.callsign[0] }
|
134
|
-
|
135
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar', callsign: 'One').slug.should eql('foo')
|
136
|
-
Factory(:user, first_name: 'Foo', last_name: 'Baz', callsign: 'Only').slug.should eql('baz')
|
137
|
-
Factory(:user, first_name: 'Boo', last_name: 'Bar', callsign: 'Ocho').slug.should eql('boo')
|
138
|
-
|
139
|
-
Factory(:user, first_name: 'Foo', last_name: 'Bar', callsign: 'Two').slug.should eql('foo')
|
140
|
-
Factory(:user, first_name: 'Foo', last_name: 'Baz', callsign: 'Tres').slug.should eql('baz')
|
141
|
-
end
|
142
|
-
|
143
|
-
it "should enforce a maximum length of 126 characters" do
|
144
|
-
User.send :slugged, :first_name
|
145
|
-
|
146
|
-
user = Factory(:user)
|
147
|
-
user.first_name = 'A'*500
|
148
|
-
user.save(validate: false)
|
149
|
-
user.slug.should eql('a'*126)
|
150
|
-
end
|
151
|
-
|
152
|
-
it "should shorten left of the ID separator" do
|
153
|
-
User.send :slugged, :first_name
|
154
|
-
|
155
|
-
user1 = Factory(:user)
|
156
|
-
user1.first_name = 'A'*500
|
157
|
-
user1.save(validate: false)
|
158
|
-
|
159
|
-
user2 = Factory(:user)
|
160
|
-
user2.first_name = 'A'*500
|
161
|
-
user2.save(validate: false)
|
162
|
-
|
163
|
-
user2.slug.size.should eql(126)
|
164
|
-
user2.slug.should match(/^a+;#{user2.id}$/)
|
165
|
-
end
|
166
|
-
|
167
|
-
it "should raise an error if no unique slugs are available" do
|
168
|
-
old_length = Slugalicious::MAX_SLUG_LENGTH
|
169
|
-
Slugalicious::MAX_SLUG_LENGTH = 1
|
170
|
-
|
171
|
-
User.send :slugged, ->(object) { 'f' }, blacklist: 'f'
|
172
|
-
-> { Factory(:user, first_name: 'Foo', last_name: 'Bar') }.should raise_error
|
173
|
-
|
174
|
-
Slugalicious::MAX_SLUG_LENGTH = old_length
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
describe "#find_from_slug" do
|
179
|
-
it "should return a Slug object for a slug" do
|
180
|
-
User.send :slugged, :first_name, :last_name
|
181
|
-
user1 = Factory(:user, first_name: "FN1", last_name: "LN1")
|
182
|
-
User.find_from_slug('fn1').should eql(user1)
|
183
|
-
end
|
184
|
-
|
185
|
-
it "should exclude slugs of other models" do
|
186
|
-
User.send :slugged, :first_name, :last_name
|
187
|
-
user1 = Factory(:user, first_name: "FN1", last_name: "LN1")
|
188
|
-
Factory(:abuser, first_name: 'FN1')
|
189
|
-
User.find_from_slug('fn1').should eql(user1)
|
190
|
-
end
|
191
|
-
|
192
|
-
it "should locate an object within a given scope" do
|
193
|
-
User.send :slugged, :first_name, scope: :last_name
|
194
|
-
user1 = Factory(:user, first_name: "FN1", last_name: "LN1")
|
195
|
-
user2 = Factory(:user, first_name: "FN1", last_name: "LN2")
|
196
|
-
User.find_from_slug('fn1', 'LN1').should eql(user1)
|
197
|
-
User.find_from_slug('fn1', 'LN2').should eql(user2)
|
198
|
-
end
|
199
|
-
|
200
|
-
it "should raise ActiveRecord::RecordNotFound if the slug does not exist" do
|
201
|
-
-> { User.find_from_slug('nonexist') }.should raise_error(ActiveRecord::RecordNotFound)
|
202
|
-
end
|
203
|
-
|
204
|
-
it "should raise ActiveRecord::RecordNotFound if the slug does not exist in scope" do
|
205
|
-
User.send :slugged, :first_name, scope: :last_name
|
206
|
-
Factory(:user, first_name: "FN1", last_name: "LN1")
|
207
|
-
Factory(:user, first_name: "FN2", last_name: "LN2")
|
208
|
-
-> { User.find_from_slug('fn2', 'ln1') }.should raise_error(ActiveRecord::RecordNotFound)
|
209
|
-
end
|
210
|
-
|
211
|
-
it "should find inactive slugs" do
|
212
|
-
User.send :slugged, :first_name
|
213
|
-
user = Factory(:user, first_name: 'New')
|
214
|
-
Factory(:slug, sluggable: user, slug: 'old', active: false)
|
215
|
-
User.find_from_slug('old').should eql(user)
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
describe "#find_from_slug_path" do
|
220
|
-
it "should call #find_from_slug with the slug and no scope for unscoped models" do
|
221
|
-
User.send :slugged, :first_name
|
222
|
-
User.should_receive(:find_from_slug).once.with("test", '')
|
223
|
-
User.find_from_slug_path("test")
|
224
|
-
end
|
225
|
-
|
226
|
-
it "should call #find_from_slug with the slug and scope for scoped models" do
|
227
|
-
User.send :slugged, :first_name, scope: :last_name
|
228
|
-
User.should_receive(:find_from_slug).once.with("test", "path/to/")
|
229
|
-
User.find_from_slug_path("path/to/test")
|
230
|
-
end
|
231
|
-
end
|
232
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,45 +0,0 @@
|
|
1
|
-
Bundler.require :default, :test
|
2
|
-
require 'active_support'
|
3
|
-
require 'active_record'
|
4
|
-
|
5
|
-
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
6
|
-
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
7
|
-
|
8
|
-
require 'slugalicious'
|
9
|
-
|
10
|
-
ActiveRecord::Base.establish_connection(
|
11
|
-
adapter: 'sqlite3',
|
12
|
-
database: 'test.sqlite'
|
13
|
-
)
|
14
|
-
require "#{File.dirname __FILE__}/../templates/slug"
|
15
|
-
|
16
|
-
class User < ActiveRecord::Base
|
17
|
-
include Slugalicious
|
18
|
-
slugged :last_name, ->(user) { "#{user.first_name} #{user.last_name}" }
|
19
|
-
end
|
20
|
-
class Abuser < ActiveRecord::Base
|
21
|
-
include Slugalicious
|
22
|
-
slugged :last_name, ->(user) { "#{user.first_name} #{user.last_name}" }
|
23
|
-
end
|
24
|
-
|
25
|
-
require "#{File.dirname __FILE__}/factories"
|
26
|
-
|
27
|
-
RSpec.configure do |config|
|
28
|
-
config.before(:each) do
|
29
|
-
Slug.connection.execute "DROP TABLE IF EXISTS slugs"
|
30
|
-
Slug.connection.execute <<-SQL
|
31
|
-
CREATE TABLE slugs (
|
32
|
-
id INTEGER PRIMARY KEY ASC,
|
33
|
-
sluggable_type VARCHAR(126) NOT NULL,
|
34
|
-
sluggable_id INTEGER NOT NULL,
|
35
|
-
active BOOLEAN NOT NULL DEFAULT 1,
|
36
|
-
slug VARCHAR(126) NOT NULL,
|
37
|
-
scope VARCHAR(126)
|
38
|
-
)
|
39
|
-
SQL
|
40
|
-
User.connection.execute "DROP TABLE IF EXISTS users"
|
41
|
-
User.connection.execute "CREATE TABLE users (id INTEGER PRIMARY KEY ASC, first_name TEXT, last_name TEXT, callsign TEXT, gender VARCHAR(7))"
|
42
|
-
Abuser.connection.execute "DROP TABLE IF EXISTS abusers"
|
43
|
-
Abuser.connection.execute "CREATE TABLE abusers (id INTEGER PRIMARY KEY ASC, first_name TEXT, last_name TEXT, callsign TEXT, gender VARCHAR(7))"
|
44
|
-
end
|
45
|
-
end
|