friendly_id_globalize3 3.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.
- data/Changelog.md +354 -0
- data/Contributors.md +43 -0
- data/Guide.md +686 -0
- data/MIT-LICENSE +19 -0
- data/README.md +99 -0
- data/Rakefile +75 -0
- data/extras/README.txt +3 -0
- data/extras/bench.rb +40 -0
- data/extras/extras.rb +38 -0
- data/extras/prof.rb +19 -0
- data/extras/template-gem.rb +26 -0
- data/extras/template-plugin.rb +28 -0
- data/generators/friendly_id/friendly_id_generator.rb +30 -0
- data/generators/friendly_id/templates/create_slugs.rb +18 -0
- data/lib/friendly_id.rb +93 -0
- data/lib/friendly_id/active_record.rb +74 -0
- data/lib/friendly_id/active_record_adapter/configuration.rb +68 -0
- data/lib/friendly_id/active_record_adapter/finders.rb +148 -0
- data/lib/friendly_id/active_record_adapter/relation.rb +165 -0
- data/lib/friendly_id/active_record_adapter/simple_model.rb +63 -0
- data/lib/friendly_id/active_record_adapter/slug.rb +77 -0
- data/lib/friendly_id/active_record_adapter/slugged_model.rb +122 -0
- data/lib/friendly_id/active_record_adapter/tasks.rb +72 -0
- data/lib/friendly_id/configuration.rb +178 -0
- data/lib/friendly_id/datamapper.rb +5 -0
- data/lib/friendly_id/railtie.rb +22 -0
- data/lib/friendly_id/sequel.rb +5 -0
- data/lib/friendly_id/slug_string.rb +25 -0
- data/lib/friendly_id/slugged.rb +105 -0
- data/lib/friendly_id/status.rb +35 -0
- data/lib/friendly_id/test.rb +350 -0
- data/lib/friendly_id/version.rb +9 -0
- data/lib/generators/friendly_id_generator.rb +25 -0
- data/lib/tasks/friendly_id.rake +19 -0
- data/rails/init.rb +2 -0
- data/test/active_record_adapter/ar_test_helper.rb +150 -0
- data/test/active_record_adapter/basic_slugged_model_test.rb +14 -0
- data/test/active_record_adapter/cached_slug_test.rb +76 -0
- data/test/active_record_adapter/core.rb +138 -0
- data/test/active_record_adapter/custom_normalizer_test.rb +20 -0
- data/test/active_record_adapter/custom_table_name_test.rb +22 -0
- data/test/active_record_adapter/default_scope_test.rb +30 -0
- data/test/active_record_adapter/optimistic_locking_test.rb +18 -0
- data/test/active_record_adapter/scoped_model_test.rb +119 -0
- data/test/active_record_adapter/simple_test.rb +76 -0
- data/test/active_record_adapter/slug_test.rb +34 -0
- data/test/active_record_adapter/slugged.rb +33 -0
- data/test/active_record_adapter/slugged_status_test.rb +28 -0
- data/test/active_record_adapter/sti_test.rb +22 -0
- data/test/active_record_adapter/support/database.jdbcsqlite3.yml +2 -0
- data/test/active_record_adapter/support/database.mysql.yml +4 -0
- data/test/active_record_adapter/support/database.postgres.yml +6 -0
- data/test/active_record_adapter/support/database.sqlite3.yml +2 -0
- data/test/active_record_adapter/support/models.rb +104 -0
- data/test/active_record_adapter/tasks_test.rb +82 -0
- data/test/friendly_id_test.rb +96 -0
- data/test/test_helper.rb +13 -0
- metadata +193 -0
@@ -0,0 +1,22 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
class Railtie < Rails::Railtie
|
3
|
+
|
4
|
+
initializer "friendly_id.configure_rails_initialization" do |app|
|
5
|
+
# Experimental Sequel support. See: http://github.com/norman/friendly_id_sequel
|
6
|
+
if app.config.generators.rails[:orm] == :sequel
|
7
|
+
require "friendly_id/sequel"
|
8
|
+
# Experimental DataMapper support. See: http://github.com/myabc/friendly_id_datamapper
|
9
|
+
elsif app.config.generators.rails[:orm] == :data_mapper
|
10
|
+
require 'friendly_id/datamapper'
|
11
|
+
else
|
12
|
+
# AR is the default.
|
13
|
+
require "friendly_id/active_record"
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
rake_tasks do
|
18
|
+
load "tasks/friendly_id.rake"
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
module FriendlyId
|
3
|
+
|
4
|
+
class SlugString < Babosa::Identifier
|
5
|
+
# Normalize the string for a given {FriendlyId::Configuration}.
|
6
|
+
# @param config [FriendlyId::Configuration]
|
7
|
+
# @return String
|
8
|
+
def normalize_for!(config)
|
9
|
+
normalize!(config.babosa_options)
|
10
|
+
end
|
11
|
+
|
12
|
+
# Validate that the slug string is not blank or reserved, and truncate
|
13
|
+
# it to the max length if necessary.
|
14
|
+
# @param config [FriendlyId::Configuration]
|
15
|
+
# @return String
|
16
|
+
# @raise FriendlyId::BlankError
|
17
|
+
# @raise FriendlyId::ReservedError
|
18
|
+
def validate_for!(config)
|
19
|
+
truncate_bytes!(config.max_length)
|
20
|
+
raise FriendlyId::BlankError if empty?
|
21
|
+
raise FriendlyId::ReservedError if config.reserved?(self)
|
22
|
+
self
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,105 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
module Slugged
|
3
|
+
|
4
|
+
class Status < FriendlyId::Status
|
5
|
+
|
6
|
+
attr_accessor :sequence, :slug
|
7
|
+
|
8
|
+
# Did the find operation use the best possible id? True if +id+ is
|
9
|
+
# numeric, but the model has no slug, or +id+ is friendly and current
|
10
|
+
def best?
|
11
|
+
current? || (numeric? && !record.slug)
|
12
|
+
end
|
13
|
+
|
14
|
+
# Did the find operation use the current slug?
|
15
|
+
def current?
|
16
|
+
!! slug && slug.current?
|
17
|
+
end
|
18
|
+
|
19
|
+
# Did the find operation use a friendly id?
|
20
|
+
def friendly?
|
21
|
+
!! (name or slug)
|
22
|
+
end
|
23
|
+
|
24
|
+
def friendly_id=(friendly_id)
|
25
|
+
@name, @sequence = friendly_id.parse_friendly_id(record.friendly_id_config.sequence_separator)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Did the find operation use an outdated slug?
|
29
|
+
def outdated?
|
30
|
+
!current?
|
31
|
+
end
|
32
|
+
|
33
|
+
# The slug that was used to find the model.
|
34
|
+
def slug
|
35
|
+
@slug ||= record.find_slug(name, sequence)
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
module Model
|
41
|
+
attr_accessor :slug
|
42
|
+
|
43
|
+
def find_slug
|
44
|
+
raise NotImplementedError
|
45
|
+
end
|
46
|
+
|
47
|
+
def friendly_id_config
|
48
|
+
self.class.friendly_id_config
|
49
|
+
end
|
50
|
+
|
51
|
+
# Get the {FriendlyId::Status} after the find has been performed.
|
52
|
+
def friendly_id_status
|
53
|
+
@friendly_id_status ||= Status.new(:record => self)
|
54
|
+
end
|
55
|
+
|
56
|
+
# The friendly id.
|
57
|
+
# @param
|
58
|
+
def friendly_id(skip_cache = false)
|
59
|
+
if friendly_id_config.cache_column? && !skip_cache
|
60
|
+
friendly_id = send(friendly_id_config.cache_column)
|
61
|
+
end
|
62
|
+
friendly_id || (slug.to_friendly_id if slug?)
|
63
|
+
end
|
64
|
+
|
65
|
+
# Clean up the string before setting it as the friendly_id. You can override
|
66
|
+
# this method to add your own custom normalization routines.
|
67
|
+
# @param string An instance of {FriendlyId::SlugString}.
|
68
|
+
# @return [String]
|
69
|
+
def normalize_friendly_id(string)
|
70
|
+
string.normalize_for!(friendly_id_config).to_s
|
71
|
+
end
|
72
|
+
|
73
|
+
# Does the instance have a slug?
|
74
|
+
def slug?
|
75
|
+
!! slug
|
76
|
+
end
|
77
|
+
|
78
|
+
private
|
79
|
+
|
80
|
+
# Get the processed string used as the basis of the friendly id.
|
81
|
+
def slug_text
|
82
|
+
base = send(friendly_id_config.method)
|
83
|
+
unless base.nil? && friendly_id_config.allow_nil?
|
84
|
+
text = normalize_friendly_id(SlugString.new(base))
|
85
|
+
SlugString.new(text.to_s).validate_for!(friendly_id_config).to_s
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# Has the slug text changed?
|
90
|
+
def slug_text_changed?
|
91
|
+
slug_text != slug.name
|
92
|
+
end
|
93
|
+
|
94
|
+
# Has the basis of our friendly id changed, requiring the generation of a
|
95
|
+
# new slug?
|
96
|
+
def new_slug_needed?
|
97
|
+
if friendly_id_config.allow_nil?
|
98
|
+
(!slug? && !slug_text.blank?) || (slug? && slug_text_changed?)
|
99
|
+
else
|
100
|
+
!slug? || slug_text_changed?
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module FriendlyId
|
2
|
+
|
3
|
+
# FriendlyId::Status presents information about the status of the
|
4
|
+
# id that was used to find the model. This class can be useful for figuring
|
5
|
+
# out when to redirect to a new URL.
|
6
|
+
class Status
|
7
|
+
|
8
|
+
# The id or name used as the finder argument
|
9
|
+
attr_accessor :name
|
10
|
+
|
11
|
+
# The found result, if any
|
12
|
+
attr_accessor :record
|
13
|
+
|
14
|
+
def initialize(options={})
|
15
|
+
options.each {|key, value| self.send("#{key}=".to_sym, value)}
|
16
|
+
end
|
17
|
+
|
18
|
+
# Did the find operation use a friendly id?
|
19
|
+
def friendly?
|
20
|
+
!! name
|
21
|
+
end
|
22
|
+
|
23
|
+
# Did the find operation use a numeric id?
|
24
|
+
def numeric?
|
25
|
+
!friendly?
|
26
|
+
end
|
27
|
+
|
28
|
+
# Did the find operation use the best available id?
|
29
|
+
def best?
|
30
|
+
record.friendly_id ? friendly? : true
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
end
|
@@ -0,0 +1,350 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
Module.send :include, Module.new {
|
3
|
+
def test(name, &block)
|
4
|
+
define_method("test_#{name.gsub(/[^a-z0-9]/i, "_")}".to_sym, &block)
|
5
|
+
end
|
6
|
+
alias :should :test
|
7
|
+
}
|
8
|
+
|
9
|
+
module FriendlyId
|
10
|
+
module Test
|
11
|
+
|
12
|
+
# Tests for any model that implements FriendlyId. Any test that tests model
|
13
|
+
# features should include this module.
|
14
|
+
module Generic
|
15
|
+
|
16
|
+
def setup
|
17
|
+
klass.send delete_all_method
|
18
|
+
end
|
19
|
+
|
20
|
+
def teardown
|
21
|
+
klass.send delete_all_method
|
22
|
+
end
|
23
|
+
|
24
|
+
def instance
|
25
|
+
raise NotImplementedError
|
26
|
+
end
|
27
|
+
|
28
|
+
def klass
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
|
32
|
+
def other_class
|
33
|
+
raise NotImplementedError
|
34
|
+
end
|
35
|
+
|
36
|
+
def find_method
|
37
|
+
raise NotImplementedError
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_method
|
41
|
+
raise NotImplementedError
|
42
|
+
end
|
43
|
+
|
44
|
+
def update_method
|
45
|
+
raise NotImplementedError
|
46
|
+
end
|
47
|
+
|
48
|
+
def validation_exceptions
|
49
|
+
return RuntimeError
|
50
|
+
end
|
51
|
+
|
52
|
+
def assert_validation_error
|
53
|
+
if validation_exceptions
|
54
|
+
assert_raise(*[validation_exceptions].flatten) do
|
55
|
+
yield
|
56
|
+
end
|
57
|
+
else # DataMapper does not raise Validation Errors
|
58
|
+
i = yield
|
59
|
+
if i.kind_of?(TrueClass) || i.kind_of?(FalseClass)
|
60
|
+
assert !i
|
61
|
+
else
|
62
|
+
instance = i
|
63
|
+
assert !instance.errors.empty?
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
test "models should have a friendly id config" do
|
69
|
+
assert_not_nil klass.friendly_id_config
|
70
|
+
end
|
71
|
+
|
72
|
+
test "instances should have a friendly id by default" do
|
73
|
+
assert_not_nil instance.friendly_id
|
74
|
+
end
|
75
|
+
|
76
|
+
test "instances should have a friendly id status" do
|
77
|
+
assert_not_nil instance.friendly_id_status
|
78
|
+
end
|
79
|
+
|
80
|
+
test "instances should be findable by their friendly id" do
|
81
|
+
assert_equal instance, klass.send(find_method, instance.friendly_id)
|
82
|
+
end
|
83
|
+
|
84
|
+
test "instances should be findable by their numeric id as an integer" do
|
85
|
+
assert_equal instance, klass.send(find_method, instance.id.to_i)
|
86
|
+
end
|
87
|
+
|
88
|
+
test "instances should be findable by their numeric id as a string" do
|
89
|
+
assert_equal instance, klass.send(find_method, instance.id.to_s)
|
90
|
+
end
|
91
|
+
|
92
|
+
test "instances should be findable by a numeric friendly_id" do
|
93
|
+
instance = klass.send(create_method, :name => "206")
|
94
|
+
assert_equal instance, klass.send(find_method, "206")
|
95
|
+
end
|
96
|
+
|
97
|
+
test "creation should raise an error if the friendly_id text is reserved" do
|
98
|
+
assert_validation_error do
|
99
|
+
klass.send(create_method, :name => "new")
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
test "creation should raise an error if the friendly_id text is an empty string" do
|
104
|
+
assert_validation_error do
|
105
|
+
klass.send(create_method, :name => "")
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
test "creation should raise an error if the friendly_id text is a blank string" do
|
110
|
+
assert_validation_error do
|
111
|
+
klass.send(create_method, :name => " ")
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
test "creation should raise an error if the friendly_id text is nil and allow_nil is false" do
|
116
|
+
assert_validation_error do
|
117
|
+
klass.send(create_method, :name => nil)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
test "creation should succeed if the friendly_id text is nil and allow_nil is true" do
|
122
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
123
|
+
assert klass.send(create_method, :name => nil)
|
124
|
+
end
|
125
|
+
|
126
|
+
test "should allow the same friendly_id across models" do
|
127
|
+
other_instance = other_class.send(create_method, :name => instance.name)
|
128
|
+
assert_equal other_instance.friendly_id, instance.friendly_id
|
129
|
+
end
|
130
|
+
|
131
|
+
test "reserved words can be specified as a regular expression" do
|
132
|
+
klass.friendly_id_config.stubs(:reserved_words).returns(/jo/)
|
133
|
+
assert_validation_error do
|
134
|
+
klass.send(create_method, :name => "joe")
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
test "should not raise reserved error unless regexp matches" do
|
139
|
+
klass.friendly_id_config.stubs(:reserved_words).returns(/ddsadad/)
|
140
|
+
assert_nothing_raised do
|
141
|
+
klass.send(create_method, :name => "joe")
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
module Simple
|
148
|
+
|
149
|
+
test "should allow friendly_id to be nillable if allow_nil is true" do
|
150
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
151
|
+
instance = klass.send(create_method, :name => "hello")
|
152
|
+
assert instance.friendly_id
|
153
|
+
instance.name = nil
|
154
|
+
assert instance.send(save_method)
|
155
|
+
end
|
156
|
+
|
157
|
+
end
|
158
|
+
|
159
|
+
# Tests for any model that implements slugs.
|
160
|
+
module Slugged
|
161
|
+
|
162
|
+
test "should have a slug" do
|
163
|
+
assert_not_nil instance.slug
|
164
|
+
end
|
165
|
+
|
166
|
+
test "should not make a new slug unless the friendly_id method value has changed" do
|
167
|
+
instance.note = instance.note.to_s << " updated"
|
168
|
+
instance.send save_method
|
169
|
+
assert_equal 1, instance.slugs.size
|
170
|
+
end
|
171
|
+
|
172
|
+
test "should make a new slug if the friendly_id method value has changed" do
|
173
|
+
instance.name = "Changed title"
|
174
|
+
instance.send save_method
|
175
|
+
slugs = if instance.slugs.respond_to?(:reload)
|
176
|
+
instance.slugs.reload
|
177
|
+
else
|
178
|
+
instance.slugs(true)
|
179
|
+
end
|
180
|
+
assert_equal 2, slugs.size
|
181
|
+
end
|
182
|
+
|
183
|
+
test "should be able to reuse an old friendly_id without incrementing the sequence" do
|
184
|
+
old_title = instance.name
|
185
|
+
old_friendly_id = instance.friendly_id
|
186
|
+
instance.name = "A changed title"
|
187
|
+
instance.send save_method
|
188
|
+
instance.name = old_title
|
189
|
+
instance.send save_method
|
190
|
+
assert_equal old_friendly_id, instance.friendly_id
|
191
|
+
end
|
192
|
+
|
193
|
+
test "should increment the slug sequence for duplicate friendly ids" do
|
194
|
+
instance2 = klass.send(create_method, :name => instance.name)
|
195
|
+
assert_match(/2\z/, instance2.friendly_id)
|
196
|
+
end
|
197
|
+
|
198
|
+
test "should find instance with a sequenced friendly_id" do
|
199
|
+
instance2 = klass.send(create_method, :name => instance.name)
|
200
|
+
assert_equal instance2, klass.send(find_method, instance2.friendly_id)
|
201
|
+
end
|
202
|
+
|
203
|
+
test "should indicate correct status when found with a sequence" do
|
204
|
+
instance2 = klass.send(create_method, :name => instance.name)
|
205
|
+
instance2 = klass.send(find_method, instance2.friendly_id)
|
206
|
+
assert instance2.friendly_id_status.best?
|
207
|
+
end
|
208
|
+
|
209
|
+
test "should indicate correct status when found by a numeric friendly_id" do
|
210
|
+
instance = klass.send(create_method, :name => "100")
|
211
|
+
instance2 = klass.send(find_method, "100")
|
212
|
+
assert instance2.friendly_id_status.best?, "status expected to be best but isn't."
|
213
|
+
assert instance2.friendly_id_status.current?, "status expected to be current but isn't."
|
214
|
+
end
|
215
|
+
|
216
|
+
test "should remain findable by previous slugs" do
|
217
|
+
old_friendly_id = instance.friendly_id
|
218
|
+
instance.name = "#{old_friendly_id} updated"
|
219
|
+
instance.send(save_method)
|
220
|
+
assert_not_equal old_friendly_id, instance.friendly_id
|
221
|
+
assert_equal instance, klass.send(find_method, old_friendly_id)
|
222
|
+
end
|
223
|
+
|
224
|
+
test "should not create a slug when allow_nil is true and friendy_id text is blank" do
|
225
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
226
|
+
instance = klass.send(create_method, :name => nil)
|
227
|
+
assert_nil instance.slug
|
228
|
+
end
|
229
|
+
|
230
|
+
test "should not allow friendly_id to be nillable even if allow_nil is true" do
|
231
|
+
klass.friendly_id_config.stubs(:allow_nil?).returns(true)
|
232
|
+
instance = klass.send(create_method, :name => "hello")
|
233
|
+
assert instance.friendly_id
|
234
|
+
instance.name = nil
|
235
|
+
assert_validation_error do
|
236
|
+
instance.send(save_method)
|
237
|
+
end
|
238
|
+
end
|
239
|
+
|
240
|
+
test "should approximate ascii if configured" do
|
241
|
+
klass.friendly_id_config.stubs(:approximate_ascii?).returns(true)
|
242
|
+
instance = klass.send(create_method, :name => "Cañón")
|
243
|
+
assert_equal "canon", instance.friendly_id
|
244
|
+
end
|
245
|
+
|
246
|
+
test "should approximate ascii with options if configured" do
|
247
|
+
klass.friendly_id_config.stubs(:approximate_ascii?).returns(true)
|
248
|
+
klass.friendly_id_config.stubs(:ascii_approximation_options).returns(:spanish)
|
249
|
+
instance = klass.send(create_method, :name => "Cañón")
|
250
|
+
assert_equal "canion", instance.friendly_id
|
251
|
+
end
|
252
|
+
end
|
253
|
+
|
254
|
+
# Tests for FriendlyId::Status.
|
255
|
+
module Status
|
256
|
+
|
257
|
+
test "should default to not friendly" do
|
258
|
+
assert !status.friendly?
|
259
|
+
end
|
260
|
+
|
261
|
+
test "should default to numeric" do
|
262
|
+
assert status.numeric?
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|
266
|
+
|
267
|
+
# Tests for FriendlyId::Status for a model that uses slugs.
|
268
|
+
module SluggedStatus
|
269
|
+
|
270
|
+
test "should be friendly if slug is set" do
|
271
|
+
status.slug = Slug.new
|
272
|
+
assert status.friendly?
|
273
|
+
end
|
274
|
+
|
275
|
+
test "should be friendly if name is set" do
|
276
|
+
status.name = "name"
|
277
|
+
assert status.friendly?
|
278
|
+
end
|
279
|
+
|
280
|
+
test "should be current if current slug is set" do
|
281
|
+
status.slug = instance.slug
|
282
|
+
assert status.current?
|
283
|
+
end
|
284
|
+
|
285
|
+
test "should not be current if non-current slug is set" do
|
286
|
+
status.slug = Slug.new(:sluggable => instance)
|
287
|
+
assert !status.current?
|
288
|
+
end
|
289
|
+
|
290
|
+
test "should be best if it is current" do
|
291
|
+
status.slug = instance.slug
|
292
|
+
assert status.best?
|
293
|
+
end
|
294
|
+
|
295
|
+
test "should be best if it is numeric, but record has no slug" do
|
296
|
+
instance.slugs = []
|
297
|
+
instance.slug = nil
|
298
|
+
assert status.best?
|
299
|
+
end
|
300
|
+
|
301
|
+
[:record, :name].each do |symbol|
|
302
|
+
test "should have #{symbol} after find using friendly_id" do
|
303
|
+
instance2 = klass.send(find_method, instance.friendly_id)
|
304
|
+
assert_not_nil instance2.friendly_id_status.send(symbol)
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
def status
|
309
|
+
@status ||= instance.friendly_id_status
|
310
|
+
end
|
311
|
+
|
312
|
+
def klass
|
313
|
+
raise NotImplementedError
|
314
|
+
end
|
315
|
+
|
316
|
+
def instance
|
317
|
+
raise NotImplementedError
|
318
|
+
end
|
319
|
+
|
320
|
+
end
|
321
|
+
|
322
|
+
# Tests for models to ensure that they properly implement using the
|
323
|
+
# +normalize_friendly_id+ method to allow developers to hook into the
|
324
|
+
# slug string generation.
|
325
|
+
module CustomNormalizer
|
326
|
+
|
327
|
+
test "should invoke the custom normalizer" do
|
328
|
+
assert_equal "JOE SCHMOE", klass.send(create_method, :name => "Joe Schmoe").friendly_id
|
329
|
+
end
|
330
|
+
|
331
|
+
test "should respect the max_length option" do
|
332
|
+
klass.friendly_id_config.stubs(:max_length).returns(3)
|
333
|
+
assert_equal "JOE", klass.send(create_method, :name => "Joe Schmoe").friendly_id
|
334
|
+
end
|
335
|
+
|
336
|
+
test "should raise an error if the friendly_id text is reserved" do
|
337
|
+
klass.friendly_id_config.stubs(:reserved_words).returns(["JOE"])
|
338
|
+
if validation_exceptions
|
339
|
+
assert_raise(*[validation_exceptions].flatten) do
|
340
|
+
klass.send(create_method, :name => "Joe")
|
341
|
+
end
|
342
|
+
else # DataMapper does not raise Validation Errors
|
343
|
+
instance = klass.send(create_method, :name => "Joe")
|
344
|
+
assert !instance.errors.empty?
|
345
|
+
end
|
346
|
+
end
|
347
|
+
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|