friendly_id 2.3.3 → 2.3.4

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 CHANGED
@@ -6,6 +6,13 @@ suggestions, ideas and improvements to FriendlyId.
6
6
  * Table of Contents
7
7
  {:toc}
8
8
 
9
+ ## 2.3.4 (2010-03-22)
10
+
11
+ * Made slugged status use the slug sequence. This fixes problems with #best?
12
+ returning false when finding with a sequenced slug.
13
+ * Doc fixes. (Juan Schiwndt)
14
+ * Misc cleanups.
15
+
9
16
  ## 2.3.3 (2010-03-10)
10
17
 
11
18
  * Fixed sequence regexp to grab all trailing digits. (Nash Kabbara)
data/Contributors.md CHANGED
@@ -13,15 +13,21 @@ community, in particular from the following people:
13
13
  * David Ramalho
14
14
  * Diego Carrion
15
15
  * Diego R. V.
16
- * Florian Aßmann
16
+ * Eric Lindvall
17
+ * Florian Aßmanqn
17
18
  * Harry Love
18
19
  * Ian Stewart
19
20
  * Jesse Crouch
20
21
  * Joe Van Dyk
21
22
  * Johan Kok
22
23
  * Josh Nichols
24
+ * Juan Schwindt
25
+ * Kamal Fariz Mahyuddin
26
+ * Louis T.
23
27
  * Mikhail Shirkov
24
28
  * Nathan Phelps
29
+ * Nash Kabbara
30
+ * Ramon Soares
25
31
  * Rdavila
26
32
  * Rob Ingram
27
33
  * Sean Abrahams
data/Guide.md CHANGED
@@ -22,7 +22,7 @@ column with no spaces or special characters, and that is seldom or never
22
22
  updated. The most common example of this is a user name or login column:
23
23
 
24
24
  class User < ActiveRecord::Base
25
- :validates_format_of :login, :with => /\A[a-z0-9]\z/i
25
+ validates_format_of :login, :with => /\A[a-z0-9]+\z/i
26
26
  has_friendly_id :login
27
27
  end
28
28
 
@@ -506,4 +506,4 @@ enabled. But if it is, then your patches would be very welcome!
506
506
  find unslugged model using friendly id, then to_param x10000 | 4.608 | 55% |
507
507
  find slugged model using friendly id, then to_param x10000 | 12.589 | 323% |
508
508
  find cached slugged model using friendly id, then to_param x10000 | 5.037 | 69% |
509
- ------------------------------------------------------------------------------------------------
509
+ ------------------------------------------------------------------------------------------------
data/lib/friendly_id.rb CHANGED
@@ -61,7 +61,7 @@ end
61
61
  class String
62
62
  def parse_friendly_id(separator = nil)
63
63
  separator ||= FriendlyId::Configuration::DEFAULTS[:sequence_separator]
64
- name, sequence = split(/#{Regexp.escape(separator)}(\d+)*\z/)
64
+ name, sequence = split(/#{Regexp.escape(separator)}(\d+)?\z/)
65
65
  return name, sequence ||= "1"
66
66
  end
67
67
  end
@@ -7,6 +7,12 @@ module FriendlyId
7
7
  def slugs_included?
8
8
  [*(options[:include] or [])].flatten.include?(:slugs)
9
9
  end
10
+
11
+ def handle_friendly_result
12
+ raise ::ActiveRecord::RecordNotFound.new unless @result
13
+ @result.friendly_id_status.friendly_id = id
14
+ end
15
+
10
16
  end
11
17
 
12
18
  class MultipleFinder
@@ -26,14 +32,10 @@ module FriendlyId
26
32
  private
27
33
 
28
34
  def find_conditions
29
- slugs
30
- # [unfriendly_find_conditions, friendly_find_conditions].compact.join(" OR ")
31
- ids = (unfriendly_ids + sluggable_ids).join(",")
32
- "%s IN (%s)" % ["#{quoted_table_name}.#{primary_key}", ids]
33
- end
34
-
35
- def friendly_find_conditions
36
- "slugs.id IN (%s)" % slugs.compact.to_s(:db) if slugs?
35
+ "%s IN (%s)" % [
36
+ "#{quoted_table_name}.#{primary_key}",
37
+ (unfriendly_ids + sluggable_ids).join(",")
38
+ ]
37
39
  end
38
40
 
39
41
  def find_options
@@ -42,38 +44,23 @@ module FriendlyId
42
44
  end
43
45
 
44
46
  def sluggable_ids
45
- if !@sluggable_ids
46
- @sluggable_ids ||= []
47
- slugs
48
- end
49
- @sluggable_ids
47
+ @sluggable_ids ||= slugs.map(&:sluggable_id)
50
48
  end
51
49
 
52
50
  def slugs
53
- @sluggable_ids ||= []
54
51
  @slugs ||= friendly_ids.map do |friendly_id|
55
52
  name, sequence = friendly_id.parse_friendly_id(friendly_id_config.sequence_separator)
56
- slug = Slug.first :conditions => {
53
+ Slug.first :conditions => {
57
54
  :name => name,
58
55
  :scope => scope,
59
56
  :sequence => sequence,
60
57
  :sluggable_type => base_class.name
61
58
  }
62
- sluggable_ids << slug.sluggable_id if slug
63
- slug
64
- end
65
- end
66
-
67
- def slugs?
68
- !slugs.empty?
59
+ end.compact
69
60
  end
70
61
 
71
62
  def slug_for(result)
72
- slugs.select {|slug| result.id == slug.sluggable_id}.first
73
- end
74
-
75
- def unfriendly_find_conditions
76
- "%s IN (%s)" % ["#{quoted_table_name}.#{primary_key}", unfriendly_ids.join(",")] if unfriendly_ids?
63
+ slugs.detect {|slug| result.id == slug.sluggable_id}
77
64
  end
78
65
 
79
66
  def unfriendly_ids?
@@ -99,10 +86,9 @@ module FriendlyId
99
86
  include SluggedFinder
100
87
 
101
88
  def find
102
- result = with_scope({:find => find_options}) { find_initial options }
103
- raise ::ActiveRecord::RecordNotFound.new if friendly? and !result
104
- result.friendly_id_status.name = name if result
105
- result
89
+ @result = with_scope({:find => find_options}) { find_initial options }
90
+ handle_friendly_result if friendly?
91
+ @result
106
92
  rescue ::ActiveRecord::RecordNotFound => @error
107
93
  friendly_id_config.scope? ? raise_scoped_error : (raise @error)
108
94
  end
@@ -135,8 +121,12 @@ module FriendlyId
135
121
  # circumstances unless the +:scope+ argument is present.
136
122
  class CachedSingleFinder < SimpleModel::SingleFinder
137
123
 
124
+ include SluggedFinder
125
+
138
126
  def find
139
- super
127
+ @result = with_scope({:find => find_options}) { find_initial options }
128
+ handle_friendly_result if friendly?
129
+ @result
140
130
  rescue ActiveRecord::RecordNotFound
141
131
  SingleFinder.new(id, model_class, options).find
142
132
  end
@@ -238,9 +228,8 @@ module FriendlyId
238
228
  include FriendlyId::Slugged::Model
239
229
  include DeprecatedMethods
240
230
 
241
- def find_slug(name)
242
- separator = friendly_id_config.sequence_separator
243
- slugs.find_by_name_and_sequence(*name.to_s.parse_friendly_id(separator))
231
+ def find_slug(name, sequence)
232
+ slugs.find_by_name_and_sequence(name, sequence)
244
233
  end
245
234
 
246
235
  # The model instance's current {FriendlyId::ActiveRecord2::Slug slug}.
@@ -3,11 +3,17 @@ module FriendlyId
3
3
 
4
4
  class Status < FriendlyId::Status
5
5
 
6
- attr_accessor :slug
6
+ attr_accessor :sequence, :slug
7
7
 
8
- # The slug that was used to find the model.
9
- def slug
10
- @slug ||= record.find_slug(name)
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?
11
17
  end
12
18
 
13
19
  # Did the find operation use a friendly id?
@@ -15,9 +21,8 @@ module FriendlyId
15
21
  !! (name or slug)
16
22
  end
17
23
 
18
- # Did the find operation use the current slug?
19
- def current?
20
- !! slug && slug.current?
24
+ def friendly_id=(friendly_id)
25
+ @name, @sequence = friendly_id.parse_friendly_id(record.friendly_id_config.sequence_separator)
21
26
  end
22
27
 
23
28
  # Did the find operation use an outdated slug?
@@ -25,10 +30,9 @@ module FriendlyId
25
30
  !current?
26
31
  end
27
32
 
28
- # Did the find operation use the best possible id? True if +id+ is
29
- # numeric, but the model has no slug, or +id+ is friendly and current
30
- def best?
31
- current? || (numeric? && !record.slug)
33
+ # The slug that was used to find the model.
34
+ def slug
35
+ @slug ||= record.find_slug(name, sequence)
32
36
  end
33
37
 
34
38
  end
@@ -88,4 +92,4 @@ module FriendlyId
88
92
 
89
93
  end
90
94
  end
91
- end
95
+ end
@@ -32,4 +32,4 @@ module FriendlyId
32
32
 
33
33
  end
34
34
 
35
- end
35
+ end
@@ -139,6 +139,12 @@ module FriendlyId
139
139
  assert_equal instance2, klass.send(find_method, instance2.friendly_id)
140
140
  end
141
141
 
142
+ test "should indicate correct status when found with a sequence" do
143
+ instance2 = klass.send(create_method, :name => instance.name)
144
+ instance2 = klass.send(find_method, instance2.friendly_id)
145
+ assert instance2.friendly_id_status.best?
146
+ end
147
+
142
148
  test "should remain findable by previous slugs" do
143
149
  old_friendly_id = instance.friendly_id
144
150
  instance.update_attributes :name => "#{old_friendly_id} updated"
@@ -148,6 +154,72 @@ module FriendlyId
148
154
 
149
155
  end
150
156
 
157
+ # Tests for FriendlyId::Status.
158
+ module Status
159
+ test "should default to not friendly" do
160
+ assert !status.friendly?
161
+ end
162
+
163
+ test "should default to numeric" do
164
+ assert status.numeric?
165
+ end
166
+ end
167
+
168
+ # Tests for FriendlyId::Status for a model that uses slugs.
169
+ module SluggedStatus
170
+
171
+ test "should be friendly if slug is set" do
172
+ status.slug = Slug.new
173
+ assert status.friendly?
174
+ end
175
+
176
+ test "should be friendly if name is set" do
177
+ status.name = "name"
178
+ assert status.friendly?
179
+ end
180
+
181
+ test "should be current if current slug is set" do
182
+ status.slug = instance.slug
183
+ assert status.current?
184
+ end
185
+
186
+ test "should not be current if non-current slug is set" do
187
+ status.slug = Slug.new(:sluggable => instance)
188
+ assert !status.current?
189
+ end
190
+
191
+ test "should be best if it is current" do
192
+ status.slug = instance.slug
193
+ assert status.best?
194
+ end
195
+
196
+ test "should be best if it is numeric, but record has no slug" do
197
+ instance.slugs = []
198
+ instance.slug = nil
199
+ assert status.best?
200
+ end
201
+
202
+ [:record, :name].each do |symbol|
203
+ test "should have #{symbol} after find using friendly_id" do
204
+ instance2 = klass.find(instance.friendly_id)
205
+ assert_not_nil instance2.friendly_id_status.send(symbol)
206
+ end
207
+ end
208
+
209
+ def status
210
+ @status ||= instance.friendly_id_status
211
+ end
212
+
213
+ def klass
214
+ raise NotImplementedError
215
+ end
216
+
217
+ def instance
218
+ raise NotImplementedError
219
+ end
220
+
221
+ end
222
+
151
223
  # Tests for models to ensure that they properly implement using the
152
224
  # +normalize_friendly_id+ method to allow developers to hook into the
153
225
  # slug string generation.
@@ -172,4 +244,4 @@ module FriendlyId
172
244
 
173
245
  end
174
246
  end
175
- end
247
+ end
@@ -2,7 +2,7 @@ module FriendlyId
2
2
  module Version
3
3
  MAJOR = 2
4
4
  MINOR = 3
5
- TINY = 3
5
+ TINY = 4
6
6
  STRING = [MAJOR, MINOR, TINY].join('.')
7
7
  end
8
8
  end
@@ -7,51 +7,15 @@ module FriendlyId
7
7
 
8
8
  class StatusTest < ::Test::Unit::TestCase
9
9
 
10
- test "should default to not friendly" do
11
- assert !status.friendly?
12
- end
13
-
14
- test "should default to numeric" do
15
- assert status.numeric?
16
- end
17
-
18
- test "should be friendly if slug is set" do
19
- status.slug = Slug.new
20
- assert status.friendly?
21
- end
22
-
23
- test "should be friendly if name is set" do
24
- status.name = "name"
25
- assert status.friendly?
26
- end
10
+ include FriendlyId::Test::Status
11
+ include FriendlyId::Test::SluggedStatus
27
12
 
28
- test "should be current if current slug is set" do
29
- status.slug = instance.slug
30
- assert status.current?
31
- end
32
-
33
- test "should not be current if non-current slug is set" do
34
- status.slug = Slug.new(:sluggable => instance)
35
- assert !status.current?
36
- end
37
-
38
- test "should be best if it is current" do
39
- status.slug = instance.slug
40
- assert status.best?
41
- end
42
-
43
- test "should be best if it is numeric, but record has not slug" do
44
- instance.slugs = []
45
- instance.slug = nil
46
- assert status.best?
13
+ def klass
14
+ Post
47
15
  end
48
16
 
49
17
  def instance
50
- @instance ||= Post.create! :name => "hello world"
51
- end
52
-
53
- def status
54
- @status ||= instance.friendly_id_status
18
+ @instance ||= klass.create! :name => "hello world"
55
19
  end
56
20
 
57
21
  end
@@ -10,16 +10,8 @@ module FriendlyId
10
10
  assert_equal ["test", "2"], "test--2".parse_friendly_id
11
11
  end
12
12
 
13
- test "should parse a friendly_id name and 10 as a sequence" do
14
- assert_equal ["test", "10"], "test--10".parse_friendly_id
15
- end
16
-
17
- test "should parse a friendly_id name and 11 as a sequence" do
18
- assert_equal ["test", "11"], "test--11".parse_friendly_id
19
- end
20
-
21
- test "should parse a friendly_id name and 29 as a sequence" do
22
- assert_equal ["test", "29"], "test--29".parse_friendly_id
13
+ test "should parse a friendly_id name and a double digit sequence" do
14
+ assert_equal ["test", "12"], "test--12".parse_friendly_id
23
15
  end
24
16
 
25
17
  test "should parse with a default sequence of 1" do
@@ -54,6 +46,9 @@ module FriendlyId
54
46
  assert_equal ["test--2--test", "12"], "test--2--test--12".parse_friendly_id
55
47
  end
56
48
 
49
+ test "should parse with a separator and no sequence" do
50
+ assert_equal ["test", "1"], "test--".parse_friendly_id
51
+ end
57
52
 
58
53
  end
59
54
  end
metadata CHANGED
@@ -1,7 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: friendly_id
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.3
4
+ prerelease: false
5
+ segments:
6
+ - 2
7
+ - 3
8
+ - 4
9
+ version: 2.3.4
5
10
  platform: ruby
6
11
  authors:
7
12
  - Norman Clarke
@@ -11,29 +16,35 @@ autorequire:
11
16
  bindir: bin
12
17
  cert_chain: []
13
18
 
14
- date: 2010-03-10 00:00:00 -03:00
19
+ date: 2010-03-22 00:00:00 -03:00
15
20
  default_executable:
16
21
  dependencies:
17
22
  - !ruby/object:Gem::Dependency
18
23
  name: activerecord
19
- type: :runtime
20
- version_requirement:
21
- version_requirements: !ruby/object:Gem::Requirement
24
+ prerelease: false
25
+ requirement: &id001 !ruby/object:Gem::Requirement
22
26
  requirements:
23
27
  - - ">="
24
28
  - !ruby/object:Gem::Version
29
+ segments:
30
+ - 2
31
+ - 2
25
32
  version: "2.2"
26
- version:
33
+ type: :runtime
34
+ version_requirements: *id001
27
35
  - !ruby/object:Gem::Dependency
28
36
  name: activesupport
29
- type: :runtime
30
- version_requirement:
31
- version_requirements: !ruby/object:Gem::Requirement
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
32
39
  requirements:
33
40
  - - ">="
34
41
  - !ruby/object:Gem::Version
42
+ segments:
43
+ - 2
44
+ - 2
35
45
  version: "2.2"
36
- version:
46
+ type: :runtime
47
+ version_requirements: *id002
37
48
  description: " FriendlyId is the \"Swiss Army bulldozer\" of slugging and permalink plugins\n for Ruby on Rails. It allows you to create pretty URL\xE2\x80\x99s and work with\n human-friendly strings as if they were numeric ids for ActiveRecord models.\n"
38
49
  email:
39
50
  - norman@njclarke.com
@@ -46,58 +57,58 @@ extensions: []
46
57
  extra_rdoc_files: []
47
58
 
48
59
  files:
49
- - lib/friendly_id/test.rb
50
- - lib/friendly_id/finders.rb
60
+ - lib/friendly_id/active_record2/configuration.rb
61
+ - lib/friendly_id/active_record2/finders.rb
62
+ - lib/friendly_id/active_record2/simple_model.rb
63
+ - lib/friendly_id/active_record2/slug.rb
64
+ - lib/friendly_id/active_record2/slugged_model.rb
65
+ - lib/friendly_id/active_record2/tasks.rb
66
+ - lib/friendly_id/active_record2.rb
51
67
  - lib/friendly_id/configuration.rb
68
+ - lib/friendly_id/finders.rb
52
69
  - lib/friendly_id/slug_string.rb
70
+ - lib/friendly_id/slugged.rb
53
71
  - lib/friendly_id/status.rb
72
+ - lib/friendly_id/test.rb
54
73
  - lib/friendly_id/version.rb
55
- - lib/friendly_id/slugged.rb
56
- - lib/friendly_id/active_record2.rb
57
- - lib/friendly_id/active_record2/finders.rb
58
- - lib/friendly_id/active_record2/configuration.rb
59
- - lib/friendly_id/active_record2/tasks.rb
60
- - lib/friendly_id/active_record2/slugged_model.rb
61
- - lib/friendly_id/active_record2/slug.rb
62
- - lib/friendly_id/active_record2/simple_model.rb
63
74
  - lib/friendly_id.rb
64
75
  - lib/friendly_id/active_record2/tasks/friendly_id.rake
65
- - Guide.md
66
- - README.md
67
76
  - Changelog.md
68
77
  - Contributors.md
78
+ - Guide.md
79
+ - README.md
69
80
  - LICENSE
70
81
  - Rakefile
71
82
  - rails/init.rb
72
83
  - generators/friendly_id/friendly_id_generator.rb
73
84
  - generators/friendly_id/templates/create_slugs.rb
74
- - test/slug_string_test.rb
75
- - test/test_helper.rb
76
- - test/active_record2/deprecated_test.rb
77
- - test/active_record2/cached_slug_test.rb
78
- - test/active_record2/tasks_test.rb
79
85
  - test/active_record2/basic_slugged_model_test.rb
86
+ - test/active_record2/cached_slug_test.rb
87
+ - test/active_record2/core.rb
88
+ - test/active_record2/custom_normalizer_test.rb
80
89
  - test/active_record2/custom_table_name_test.rb
81
- - test/active_record2/support/database.sqlite3.yml
82
- - test/active_record2/support/database.mysql.yml
83
- - test/active_record2/support/models.rb
84
- - test/active_record2/support/database.postgres.yml
85
- - test/active_record2/slug_test.rb
90
+ - test/active_record2/deprecated_test.rb
86
91
  - test/active_record2/scoped_model_test.rb
87
- - test/active_record2/custom_normalizer_test.rb
92
+ - test/active_record2/simple_test.rb
93
+ - test/active_record2/slug_test.rb
88
94
  - test/active_record2/slugged.rb
89
- - test/active_record2/test_helper.rb
90
- - test/active_record2/core.rb
91
- - test/active_record2/sti_test.rb
92
95
  - test/active_record2/slugged_status_test.rb
93
- - test/active_record2/simple_test.rb
96
+ - test/active_record2/sti_test.rb
97
+ - test/active_record2/support/database.mysql.yml
98
+ - test/active_record2/support/database.postgres.yml
99
+ - test/active_record2/support/database.sqlite3.yml
100
+ - test/active_record2/support/models.rb
101
+ - test/active_record2/tasks_test.rb
102
+ - test/active_record2/test_helper.rb
94
103
  - test/friendly_id_test.rb
104
+ - test/slug_string_test.rb
105
+ - test/test_helper.rb
106
+ - extras/bench.rb
95
107
  - extras/extras.rb
96
108
  - extras/prof.rb
97
- - extras/template-plugin.rb
98
- - extras/template-gem.rb
99
- - extras/bench.rb
100
109
  - extras/README.txt
110
+ - extras/template-gem.rb
111
+ - extras/template-plugin.rb
101
112
  has_rdoc: true
102
113
  homepage: http://norman.github.com/friendly_id
103
114
  licenses: []
@@ -123,32 +134,34 @@ required_ruby_version: !ruby/object:Gem::Requirement
123
134
  requirements:
124
135
  - - ">="
125
136
  - !ruby/object:Gem::Version
137
+ segments:
138
+ - 0
126
139
  version: "0"
127
- version:
128
140
  required_rubygems_version: !ruby/object:Gem::Requirement
129
141
  requirements:
130
142
  - - ">="
131
143
  - !ruby/object:Gem::Version
144
+ segments:
145
+ - 0
132
146
  version: "0"
133
- version:
134
147
  requirements: []
135
148
 
136
149
  rubyforge_project: friendly-id
137
- rubygems_version: 1.3.5
150
+ rubygems_version: 1.3.6
138
151
  signing_key:
139
152
  specification_version: 3
140
153
  summary: A comprehensive slugging and pretty-URL plugin.
141
154
  test_files:
142
- - test/slug_string_test.rb
143
- - test/active_record2/deprecated_test.rb
144
- - test/active_record2/cached_slug_test.rb
145
- - test/active_record2/tasks_test.rb
146
155
  - test/active_record2/basic_slugged_model_test.rb
156
+ - test/active_record2/cached_slug_test.rb
157
+ - test/active_record2/custom_normalizer_test.rb
147
158
  - test/active_record2/custom_table_name_test.rb
148
- - test/active_record2/slug_test.rb
159
+ - test/active_record2/deprecated_test.rb
149
160
  - test/active_record2/scoped_model_test.rb
150
- - test/active_record2/custom_normalizer_test.rb
151
- - test/active_record2/sti_test.rb
152
- - test/active_record2/slugged_status_test.rb
153
161
  - test/active_record2/simple_test.rb
162
+ - test/active_record2/slug_test.rb
163
+ - test/active_record2/slugged_status_test.rb
164
+ - test/active_record2/sti_test.rb
165
+ - test/active_record2/tasks_test.rb
154
166
  - test/friendly_id_test.rb
167
+ - test/slug_string_test.rb