friendly_id 2.3.3 → 2.3.4

Sign up to get free protection for your applications and to get access to all the features.
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