slug 0.5.7 → 4.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: b26d7fca3befe175649b0bdbe3b1e145e775ea77191fbe023f017d907cdfd64c
4
+ data.tar.gz: '06786f698b25c0e2d061ca77cbafa382e774bb96ded86a7b246c858909e8a1b5'
5
+ SHA512:
6
+ metadata.gz: 248ca7e65bc8ccc47a9cec02c3843f4c1871aa743078627677078c4a52dbde1666226002033c0d5e4a107b27fdb32feb1f51c3d877c815bdb455cdf8dbe87bbf
7
+ data.tar.gz: dfab8ccf8d2daf51720cbc7ecfb44b9fb3ad5862f85e5e7a44b236170cbb1ac7caeaff52434764d80ed5f62bd0d11b2e104699a1011fe5ca3349e63db868cc16
data/README.rdoc CHANGED
@@ -4,21 +4,21 @@ Slug provides simple, straightforward slugging for your ActiveRecord models.
4
4
 
5
5
  Slug is based on code from Norman Clarke's fantastic {friendly_id}[http://friendly-id.rubyforge.org] project and Nick Zadrozny's {friendly_identifier}[http://code.google.com/p/friendly-identifier/].
6
6
 
7
- Here's what's different:
7
+ What's different:
8
8
 
9
9
  * Unlike friendly_id, slugs are stored directly in your model's table. friendly_id stores its data in a separate sluggable table, which enables cool things like slug versioning--but forces yet another join when trying to do complex find_by_slugs.
10
10
  * Like friendly_id, diacritics (accented characters) are stripped from slug strings.
11
- * Most importantly, there are just two options: source column (for example, headline) and an optional slug column (if for some reason you don't want your slugs stored in a column called slug)
11
+ * The number of options is manageable
12
12
 
13
13
  == INSTALLATION
14
14
 
15
- sudo gem install slug --source http://gemcutter.org
15
+ Add the gem to your Gemfile
16
16
 
17
- then add
17
+ gem 'slug'
18
18
 
19
- config.gem 'slug', :source => 'http://gemcutter.org'
19
+ of your rails project.
20
20
 
21
- to your rails project.
21
+ This is tested with Rails 5.1.4, MRI Ruby 2.4.1
22
22
 
23
23
  == USAGE
24
24
 
@@ -40,11 +40,7 @@ Once your table is migrated, just add
40
40
 
41
41
  to your ActiveRecord model. <tt>:source_field</tt> is the column you'd like to base the slug on--for example, it might be <tt>:headline</tt>.
42
42
 
43
- If you want to save the slug in a database column that isn't called <tt>slug</tt>, just pass the <tt>:column</tt> option. For example
44
-
45
- slug :headline, :column => :web_slug
46
-
47
- would generate a slug based on <tt>headline</tt> and save it to <tt>web_slug</tt>.
43
+ === INSTANCE METHOD AS SOURCE COLUMN
48
44
 
49
45
  The source column isn't limited to just database attributes--you can specify any instance method. This is handy if you need special formatting on your source column before it's slugged, or if you want to base the slug on several attributes.
50
46
 
@@ -57,18 +53,52 @@ For example:
57
53
  "#{headline}-#{publication_date.year}-#{publication_date.month}"
58
54
  end
59
55
  end
60
- end
61
56
 
62
57
  would use headline-pub year-pub month as the slug source.
63
58
 
64
59
  From here, you can work with your slug as if it were a normal column--<tt>find_by_slug</tt> and named scopes will work as they do for any other column.
65
60
 
66
- A few notes:
67
- * Slug validates presence and uniqueness of the slug column. If you pass something that isn't sluggable as the source (for example, say you set the headline to '---'), a validation error will be set.
61
+ == OPTIONS
62
+ There are two options:
63
+ - <tt>:column</tt> is the slug_column, if for some reason you don't want
64
+ your slugs stored in a column called "slug"
65
+ - <tt>:generic_default</tt> is a boolean which, if true, will help you
66
+ avoid <tt>ActiveRecord::ValidationError</tt> exceptions on the slug column.
67
+
68
+ === COLUMN OPTION
69
+ If you want to save the slug in a database column that isn't called
70
+ <tt>slug</tt>, just pass the <tt>:column</tt> option. For example
71
+
72
+ slug :headline, :column => :web_slug
73
+
74
+ would generate a slug based on <tt>headline</tt> and save it to <tt>web_slug</tt>.
75
+
76
+ === GENERIC DEFAULT OPTION
77
+ You can avoid <tt>ActiveRecord::ValidationError</tt> exceptions that can
78
+ occur if the source column is empty, blank, or only contains filtered
79
+ characters. Simply set <tt>generic_default: true</tt>. For example
80
+
81
+ slug :headline, generic_default: true
82
+
83
+ will generate a slug based on your model name if the headline is blank.
84
+
85
+ This is useful if the source column (e.g. headline) is based on user-generated
86
+ input or can be blank (nil or empty).
87
+
88
+ Some prefer to get the exception in this case. Others want to get a good
89
+ slug and move on.
90
+
91
+ == NOTES
92
+ * Slug validates presence and uniqueness of the slug column. If you pass something that isn't sluggable as the source (for example, say you set the headline to '---'), a validation error will be set. (See the <tt>:generic_default</tt> option for avoiding this.
68
93
  * Slug doesn't update the slug if the source column changes. If you really need to regenerate the slug, call <tt>@model.set_slug</tt> before save.
69
94
  * If a slug already exists, Slug will automatically append a '-n' suffix to your slug to make it unique. The second instance of a slug is '-1'.
70
95
  * If you don't like the slug formatting or the accented character stripping doesn't work for you, it's easy to override Slug's formatting functions. Check the source for details.
71
96
 
72
97
  == AUTHOR
73
98
 
74
- Ben Koski, ben.koski@gmail.com
99
+ Ben Koski, ben.koski@gmail.com
100
+
101
+ with generous contributions from:
102
+ - Derek Willis, @derekwillis
103
+ - others listed in the commit history, which can be found in the
104
+ {GitHub contributor list}[https://github.com/wbreeze/slug/graphs/contributors]
data/Rakefile CHANGED
@@ -1,23 +1,6 @@
1
1
  require 'rake'
2
2
 
3
- begin
4
- require 'jeweler'
5
- Jeweler::Tasks.new do |s|
6
- s.name = "slug"
7
- s.summary = %Q{Simple, straightforward slugs for your ActiveRecord models.}
8
- s.email = "ben.koski@gmail.com"
9
- s.homepage = "http://github.com/bkoski/slug"
10
- s.description = "Simple, straightforward slugs for your ActiveRecord models."
11
- s.add_dependency 'activerecord'
12
- s.add_dependency 'activesupport'
13
- s.authors = ["Ben Koski"]
14
- end
15
- Jeweler::GemcutterTasks.new
16
- rescue LoadError
17
- puts "Jeweler not available. Install it with: sudo gem install technicalpickles-jeweler -s http://gems.github.com"
18
- end
19
-
20
- require 'rake/rdoctask'
3
+ require 'rdoc/task'
21
4
  Rake::RDocTask.new do |rdoc|
22
5
  rdoc.rdoc_dir = 'rdoc'
23
6
  rdoc.title = 'slug'
@@ -33,15 +16,4 @@ Rake::TestTask.new(:test) do |t|
33
16
  t.verbose = false
34
17
  end
35
18
 
36
- begin
37
- require 'rcov/rcovtask'
38
- Rcov::RcovTask.new do |t|
39
- t.libs << 'test'
40
- t.test_files = FileList['test/**/*_test.rb']
41
- t.verbose = true
42
- end
43
- rescue LoadError
44
- puts "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
45
- end
46
-
47
19
  task :default => :test
data/VERSION.yml CHANGED
@@ -1,4 +1,4 @@
1
1
  ---
2
- :patch: 7
3
- :major: 0
4
- :minor: 5
2
+ :major: 4
3
+ :minor: 0
4
+ :patch: 1
data/lib/slug/slug.rb CHANGED
@@ -1,6 +1,6 @@
1
1
  module Slug
2
2
  module ClassMethods
3
-
3
+
4
4
  # Call this to set up slug handling on an ActiveRecord model.
5
5
  #
6
6
  # Params:
@@ -8,37 +8,40 @@ module Slug
8
8
  #
9
9
  # Options:
10
10
  # * <tt>:column</tt> - the column the slug will be saved to (defaults to <tt>:slug</tt>)
11
- # * <tt>:validates_uniquness_if</tt> - proc to determine whether uniqueness validation runs, same format as validates_uniquness_of :if
11
+ # * <tt>:validate_uniquness_if</tt> - proc to determine whether uniqueness validation runs, same format as validates_uniquness_of :if
12
12
  #
13
13
  # Slug will take care of validating presence and uniqueness of slug.
14
-
14
+
15
15
  # Before create, Slug will generate and assign the slug if it wasn't explicitly set.
16
16
  # Note that subsequent changes to the source column will have no effect on the slug.
17
17
  # If you'd like to update the slug later on, call <tt>@model.set_slug</tt>
18
18
  def slug source, opts={}
19
- class_inheritable_accessor :slug_source, :slug_column
19
+ class_attribute :slug_source, :slug_column, :generic_default
20
20
  include InstanceMethods
21
-
21
+
22
22
  self.slug_source = source
23
-
24
- self.slug_column = opts.has_key?(:column) ? opts[:column] : :slug
23
+ self.slug_column = opts.fetch(:column, :slug)
24
+ self.generic_default = opts.fetch(:generic_default, false)
25
25
 
26
26
  uniqueness_opts = {}
27
- uniqueness_opts.merge!(:if => opts[:validates_uniqueness_if]) if opts[:validates_uniqueness_if].present?
28
-
29
- validates_presence_of self.slug_column, :message => "cannot be blank. Is #{self.slug_source} sluggable?"
30
- validates_uniqueness_of self.slug_column, uniqueness_opts
31
- validates_format_of self.slug_column, :with => /^[a-z0-9-]+$/, :message => "contains invalid characters. Only downcase letters, numbers, and '-' are allowed."
32
- before_validation_on_create :set_slug
27
+ uniqueness_opts.merge!(:if => opts[:validate_uniqueness_if]) if opts[:validate_uniqueness_if].present?
28
+ validates_uniqueness_of self.slug_column, uniqueness_opts
29
+
30
+ validates_presence_of self.slug_column,
31
+ message: "cannot be blank. Is #{self.slug_source} sluggable?"
32
+ validates_format_of self.slug_column,
33
+ with: /\A[a-z0-9-]+\z/,
34
+ message: "contains invalid characters. Only downcase letters, numbers, and '-' are allowed."
35
+ before_validation :set_slug, :on => :create
33
36
  end
34
37
  end
35
-
38
+
36
39
  module InstanceMethods
37
-
40
+
38
41
  # Sets the slug. Called before create.
39
42
  # By default, set_slug won't change slug if one already exists. Pass :force => true to overwrite.
40
43
  def set_slug(opts={})
41
- validate_slug_columns
44
+ validate_slug_columns
42
45
  return unless self[self.slug_column].blank? || opts[:force] == true
43
46
 
44
47
  original_slug = self[self.slug_column]
@@ -46,23 +49,24 @@ module Slug
46
49
 
47
50
  strip_diacritics_from_slug
48
51
  normalize_slug
52
+ genericize_slug if generic_default
49
53
  assign_slug_sequence unless self[self.slug_column] == original_slug # don't try to increment seq if slug hasn't changed
50
54
  end
51
-
55
+
52
56
  # Overwrite existing slug based on current contents of source column.
53
57
  def reset_slug
54
58
  set_slug(:force => true)
55
59
  end
56
-
60
+
57
61
  # Overrides to_param to return the model's slug.
58
62
  def to_param
59
63
  self[self.slug_column]
60
64
  end
61
-
65
+
62
66
  def self.included(klass)
63
67
  klass.extend(ClassMethods)
64
68
  end
65
-
69
+
66
70
  private
67
71
  # Validates that source and destination methods exist. Invoked at runtime to allow definition
68
72
  # of source/slug methods after <tt>slug</tt> setup in class.
@@ -70,7 +74,7 @@ module Slug
70
74
  raise ArgumentError, "Source column '#{self.slug_source}' does not exist!" if !self.respond_to?(self.slug_source)
71
75
  raise ArgumentError, "Slug column '#{self.slug_column}' does not exist!" if !self.respond_to?("#{self.slug_column}=")
72
76
  end
73
-
77
+
74
78
  # Takes the slug, downcases it and replaces non-word characters with a -.
75
79
  # Feel free to override this method if you'd like different slug formatting.
76
80
  def normalize_slug
@@ -84,7 +88,13 @@ module Slug
84
88
  s.gsub!(/-+/, '-') # get rid of double-dashes
85
89
  self[self.slug_column] = s.to_s
86
90
  end
87
-
91
+
92
+ def genericize_slug
93
+ if self[self.slug_column].blank?
94
+ self[self.slug_column] = self.class.to_s.demodulize.underscore.dasherize
95
+ end
96
+ end
97
+
88
98
  # Converts accented characters to their ASCII equivalents and removes them if they have no equivalent.
89
99
  # Override this with a void function if you don't want accented characters to be stripped.
90
100
  def strip_diacritics_from_slug
@@ -102,26 +112,24 @@ module Slug
102
112
  s = s.pack('U*')
103
113
  self[self.slug_column] = s.to_s
104
114
  end
105
-
115
+
106
116
  # If a slug of the same name already exists, this will append '-n' to the end of the slug to
107
117
  # make it unique. The second instance gets a '-1' suffix.
108
118
  def assign_slug_sequence
109
119
  return if self[self.slug_column].blank?
110
- idx = next_slug_sequence
111
- self[self.slug_column] = "#{self[self.slug_column]}-#{idx}" if idx > 0
120
+ self[self.slug_column] = next_slug_sequence
112
121
  end
113
-
122
+
114
123
  # Returns the next unique index for a slug.
115
124
  def next_slug_sequence
116
- last_in_sequence = self.class.find(:first, :conditions => ["#{self.slug_column} LIKE ?", self[self.slug_column] + '%'],
117
- :order => "CAST(REPLACE(#{self.slug_column},'#{self[self.slug_column]}','') AS UNSIGNED)")
118
- if last_in_sequence.nil?
119
- return 0
120
- else
121
- sequence_match = last_in_sequence[self.slug_column].match(/^#{self[self.slug_column]}(-(\d+))?/)
122
- current = sequence_match.nil? ? 0 : sequence_match[2].to_i
123
- return current + 1
125
+ assoc = self.class.base_class
126
+ base_val = slug_val = self[self.slug_column]
127
+ next_id = 1
128
+ until assoc.where(self.slug_column => slug_val).first.nil? do
129
+ slug_val = base_val + "-#{next_id}"
130
+ next_id = next_id + 1
124
131
  end
132
+ slug_val
125
133
  end
126
134
  end
127
- end
135
+ end
data/lib/slug.rb CHANGED
@@ -3,4 +3,8 @@ require File.join(File.dirname(__FILE__), 'slug', 'ascii_approximations')
3
3
 
4
4
  if defined?(ActiveRecord)
5
5
  ActiveRecord::Base.instance_eval { extend Slug::ClassMethods }
6
+ end
7
+
8
+ if defined?(Rails) && Rails.version.to_i < 3
9
+ raise "This version of slug requires Rails 3 or higher"
6
10
  end
data/slug.gemspec CHANGED
@@ -1,61 +1,60 @@
1
- # Generated by jeweler
2
- # DO NOT EDIT THIS FILE
3
- # Instead, edit Jeweler::Tasks in Rakefile, and run `rake gemspec`
4
1
  # -*- encoding: utf-8 -*-
2
+ # stub: slug 4.0.0 ruby lib
5
3
 
6
4
  Gem::Specification.new do |s|
7
- s.name = %q{slug}
8
- s.version = "0.5.7"
5
+ s.name = "slug"
6
+ s.version = "4.0.1"
9
7
 
10
8
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
9
+ s.require_paths = ["lib"]
11
10
  s.authors = ["Ben Koski"]
12
- s.date = %q{2010-06-25}
13
- s.description = %q{Simple, straightforward slugs for your ActiveRecord models.}
14
- s.email = %q{ben.koski@gmail.com}
11
+ s.date = "2018-11-11"
12
+ s.description = "Simple, straightforward slugs for your ActiveRecord models."
13
+ s.email = "ben.koski@gmail.com"
15
14
  s.extra_rdoc_files = [
16
15
  "LICENSE",
17
- "README.rdoc"
16
+ "README.rdoc"
18
17
  ]
19
18
  s.files = [
20
- ".gitignore",
21
- "LICENSE",
22
- "README.rdoc",
23
- "Rakefile",
24
- "VERSION.yml",
25
- "lib/slug.rb",
26
- "lib/slug/ascii_approximations.rb",
27
- "lib/slug/slug.rb",
28
- "slug.gemspec",
29
- "test/models.rb",
30
- "test/schema.rb",
31
- "test/test_helper.rb",
32
- "test/test_slug.rb"
33
- ]
34
- s.homepage = %q{http://github.com/bkoski/slug}
35
- s.rdoc_options = ["--charset=UTF-8"]
36
- s.require_paths = ["lib"]
37
- s.rubygems_version = %q{1.3.5}
38
- s.summary = %q{Simple, straightforward slugs for your ActiveRecord models.}
39
- s.test_files = [
19
+ "LICENSE",
20
+ "README.rdoc",
21
+ "Rakefile",
22
+ "VERSION.yml",
23
+ "lib/slug.rb",
24
+ "lib/slug/ascii_approximations.rb",
25
+ "lib/slug/slug.rb",
26
+ "slug.gemspec",
40
27
  "test/models.rb",
41
- "test/schema.rb",
42
- "test/test_helper.rb",
43
- "test/test_slug.rb"
28
+ "test/schema.rb",
29
+ "test/test_helper.rb",
30
+ "test/slug_test.rb"
44
31
  ]
32
+ s.homepage = "http://github.com/bkoski/slug"
33
+ s.rubygems_version = "2.2.0"
34
+ s.summary = "Simple, straightforward slugs for your ActiveRecord models."
45
35
 
46
36
  if s.respond_to? :specification_version then
47
- current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
48
- s.specification_version = 3
37
+ s.specification_version = 4
49
38
 
50
- if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
51
- s.add_runtime_dependency(%q<activerecord>, [">= 0"])
52
- s.add_runtime_dependency(%q<activesupport>, [">= 0"])
39
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
40
+ s.add_runtime_dependency(%q<rake>, [">= 0"])
41
+ s.add_development_dependency(%q<minitest>, [">= 0"])
42
+ s.add_development_dependency(%q<sqlite3>, [">= 0"])
43
+ s.add_runtime_dependency(%q<activerecord>, ["> 3.0.0"])
44
+ s.add_runtime_dependency(%q<activesupport>, ["> 3.0.0"])
53
45
  else
54
- s.add_dependency(%q<activerecord>, [">= 0"])
55
- s.add_dependency(%q<activesupport>, [">= 0"])
46
+ s.add_dependency(%q<rake>, [">= 0"])
47
+ s.add_dependency(%q<minitest>, [">= 0"])
48
+ s.add_dependency(%q<sqlite3>, [">= 0"])
49
+ s.add_dependency(%q<activerecord>, ["> 3.0.0"])
50
+ s.add_dependency(%q<activesupport>, ["> 3.0.0"])
56
51
  end
57
52
  else
58
- s.add_dependency(%q<activerecord>, [">= 0"])
59
- s.add_dependency(%q<activesupport>, [">= 0"])
53
+ s.add_dependency(%q<rake>, [">= 0"])
54
+ s.add_dependency(%q<minitest>, [">= 0"])
55
+ s.add_dependency(%q<sqlite3>, [">= 0"])
56
+ s.add_dependency(%q<activerecord>, ["> 3.0.0"])
57
+ s.add_dependency(%q<activesupport>, ["> 3.0.0"])
60
58
  end
61
59
  end
60
+
data/test/models.rb CHANGED
@@ -1,6 +1,9 @@
1
1
  # Used to test slug behavior in general
2
2
  class Article < ActiveRecord::Base
3
- slug :headline
3
+ slug :headline
4
+ end
5
+
6
+ class Storyline < Article
4
7
  end
5
8
 
6
9
  # Used to test alternate slug column
@@ -14,14 +17,20 @@ class Company < ActiveRecord::Base
14
17
  end
15
18
 
16
19
  class Post < ActiveRecord::Base
17
- slug :headline, :validates_uniqueness_if => Proc.new { false }
20
+ slug :headline, :validate_uniqueness_if => Proc.new { false }
18
21
  end
19
22
 
20
23
  # Used to test slugs based on methods rather than database attributes
21
24
  class Event < ActiveRecord::Base
22
25
  slug :title_for_slug
23
-
26
+
24
27
  def title_for_slug
25
28
  "#{title}-#{location}"
26
29
  end
27
- end
30
+ end
31
+
32
+ # Test generation of generic slugs
33
+ class Generation < ActiveRecord::Base
34
+ slug :title, generic_default: true
35
+ end
36
+
data/test/schema.rb CHANGED
@@ -1,30 +1,35 @@
1
1
  ActiveRecord::Schema.define(:version => 1) do
2
-
3
2
  create_table "articles", :force => true do |t|
4
- t.column "headline", "string"
3
+ t.column "headline", "string", null: false
5
4
  t.column "section", "string"
6
- t.column "slug", "string"
5
+ t.column "slug", "string", null: false
6
+ t.column "type", "string"
7
+ t.index ["slug"], name: "index_articles_on_slug", unique: true
7
8
  end
8
-
9
+
9
10
  create_table "people", :force => true do |t|
10
11
  t.column "name", "string"
11
12
  t.column "web_slug", "string"
12
13
  end
13
-
14
+
14
15
  create_table "companies", :force => true do |t|
15
16
  t.column "name", "string"
16
17
  t.column "slug", "string"
17
18
  end
18
-
19
+
19
20
  create_table "posts", :force => true do |t|
20
21
  t.column "headline", "string"
21
22
  t.column "slug", "string"
22
23
  end
23
-
24
+
24
25
  create_table "events", :force => true do |t|
25
26
  t.column "title", "string"
26
27
  t.column "location", "string"
27
28
  t.column "slug", "string"
28
29
  end
29
-
30
- end
30
+
31
+ create_table "generations", :force => true do |t|
32
+ t.column "title", "string"
33
+ t.column "slug", "string", null: false
34
+ end
35
+ end
data/test/slug_test.rb ADDED
@@ -0,0 +1,310 @@
1
+ # encoding: utf-8
2
+ require 'test_helper'
3
+
4
+ describe Slug do
5
+ before do
6
+ Article.delete_all
7
+ end
8
+
9
+ describe 'slug' do
10
+ it "bases slug on specified source column" do
11
+ article = Article.create!(:headline => 'Test Headline')
12
+ assert_equal 'test-headline', article.slug
13
+ end
14
+
15
+ it "bases slug on specified source column, even if it is defined as a method rather than database attribute" do
16
+ article = Event.create!(:title => 'Test Event', :location => 'Portland')
17
+ assert_equal 'test-event-portland', article.slug
18
+ end
19
+
20
+ describe "slug column" do
21
+ it "saves slug to 'slug' column by default" do
22
+ article = Article.create!(:headline => 'Test Headline')
23
+ assert_equal 'test-headline', article.slug
24
+ end
25
+
26
+ it "saves slug to :column specified in options" do
27
+ Person.delete_all
28
+ person = Person.create!(:name => 'Test Person')
29
+ assert_equal 'test-person', person.web_slug
30
+ end
31
+ end
32
+ end
33
+
34
+ describe "column validations" do
35
+ it "raises ArgumentError if an invalid source column is passed" do
36
+ Company.slug(:invalid_source_column)
37
+ assert_raises(ArgumentError) { Company.create! }
38
+ end
39
+
40
+ it "raises an ArgumentError if an invalid slug column is passed" do
41
+ Company.slug(:name, :column => :bad_slug_column)
42
+ assert_raises(ArgumentError) { Company.create! }
43
+ end
44
+ end
45
+
46
+ describe 'generates a generic slug' do
47
+ before do
48
+ Generation.delete_all
49
+ end
50
+
51
+ it "if source column is empty" do
52
+ generation = Generation.create!
53
+ assert_equal 'generation', generation.slug
54
+ end
55
+
56
+ it "if normalization makes source value empty" do
57
+ generation = Generation.create!(:title => '$$$')
58
+ assert_equal 'generation', generation.slug
59
+ end
60
+
61
+ it "if source value contains no Latin characters" do
62
+ generation = Generation.create!(:title => 'ローマ字がない')
63
+ assert_equal 'generation', generation.slug
64
+ end
65
+ end
66
+
67
+ describe 'validation' do
68
+ it "sets validation error if source column is empty" do
69
+ article = Article.create
70
+ assert !article.valid?
71
+ assert article.errors[:slug]
72
+ end
73
+
74
+ it "sets validation error if normalization makes source value empty" do
75
+ article = Article.create(:headline => '$$$')
76
+ assert !article.valid?
77
+ assert article.errors[:slug]
78
+ end
79
+
80
+ it "validates slug format on save" do
81
+ article = Article.create!(:headline => 'Test Headline')
82
+ article.slug = 'A BAD $LUG.'
83
+
84
+ assert !article.valid?
85
+ assert article.errors[:slug].present?
86
+ end
87
+
88
+ it "validates uniqueness of slug by default" do
89
+ Article.create!(:headline => 'Test Headline')
90
+ article2 = Article.create!(:headline => 'Test Headline')
91
+ article2.slug = 'test-headline'
92
+
93
+ assert !article2.valid?
94
+ assert article2.errors[:slug].present?
95
+ end
96
+
97
+ it "uses validate_uniqueness_if proc to decide whether uniqueness validation applies" do
98
+ Post.create!(:headline => 'Test Headline')
99
+ article2 = Post.new
100
+ article2.slug = 'test-headline'
101
+
102
+ assert article2.valid?
103
+ end
104
+ end
105
+
106
+ it "doesn't overwrite slug value on create if it was already specified" do
107
+ a = Article.create!(:headline => 'Test Headline', :slug => 'slug1')
108
+ assert_equal 'slug1', a.slug
109
+ end
110
+
111
+ it "doesn't update the slug even if the source column changes" do
112
+ article = Article.create!(:headline => 'Test Headline')
113
+ article.update_attributes!(:headline => 'New Headline')
114
+ assert_equal 'test-headline', article.slug
115
+ end
116
+
117
+ describe "resetting a slug" do
118
+ before do
119
+ @article = Article.create(:headline => 'test headline')
120
+ @original_slug = @article.slug
121
+ end
122
+
123
+ it "maintains the same slug if slug column hasn't changed" do
124
+ @article.reset_slug
125
+ assert_equal @original_slug, @article.slug
126
+ end
127
+
128
+ it "changes slug if slug column has updated" do
129
+ @article.headline = "donkey"
130
+ @article.reset_slug
131
+ refute_equal(@original_slug, @article.slug)
132
+ end
133
+
134
+ it "maintains sequence" do
135
+ @existing_article = Article.create!(:headline => 'world cup')
136
+ @article.headline = "world cup"
137
+ @article.reset_slug
138
+ assert_equal 'world-cup-1', @article.slug
139
+ end
140
+ end
141
+
142
+ describe "slug normalization" do
143
+ before do
144
+ @article = Article.new
145
+ end
146
+
147
+ it "lowercases strings" do
148
+ @article.headline = 'AbC'
149
+ @article.save!
150
+ assert_equal "abc", @article.slug
151
+ end
152
+
153
+ it "replaces whitespace with dashes" do
154
+ @article.headline = 'a b'
155
+ @article.save!
156
+ assert_equal 'a-b', @article.slug
157
+ end
158
+
159
+ it "replaces 2spaces with 1dash" do
160
+ @article.headline = 'a b'
161
+ @article.save!
162
+ assert_equal 'a-b', @article.slug
163
+ end
164
+
165
+ it "removes punctuation" do
166
+ @article.headline = 'abc!@#$%^&*•¶§∞¢££¡¿()><?""\':;][]\.,/'
167
+ @article.save!
168
+ assert_match 'abc', @article.slug
169
+ end
170
+
171
+ it "strips trailing space" do
172
+ @article.headline = 'ab '
173
+ @article.save!
174
+ assert_equal 'ab', @article.slug
175
+ end
176
+
177
+ it "strips leading space" do
178
+ @article.headline = ' ab'
179
+ @article.save!
180
+ assert_equal 'ab', @article.slug
181
+ end
182
+
183
+ it "strips trailing dashes" do
184
+ @article.headline = 'ab-'
185
+ @article.save!
186
+ assert_match 'ab', @article.slug
187
+ end
188
+
189
+ it "strips leading dashes" do
190
+ @article.headline = '-ab'
191
+ @article.save!
192
+ assert_match 'ab', @article.slug
193
+ end
194
+
195
+ it "remove double-dashes" do
196
+ @article.headline = 'a--b--c'
197
+ @article.save!
198
+ assert_match 'a-b-c', @article.slug
199
+ end
200
+
201
+ it "doesn't modify valid slug strings" do
202
+ @article.headline = 'a-b-c-d'
203
+ @article.save!
204
+ assert_match 'a-b-c-d', @article.slug
205
+ end
206
+
207
+ it "doesn't insert dashes for periods in acronyms, regardless of where they appear in string" do
208
+ @article.headline = "N.Y.P.D. vs. N.S.A. vs. F.B.I."
209
+ @article.save!
210
+ assert_match 'nypd-vs-nsa-vs-fbi', @article.slug
211
+ end
212
+
213
+ it "doesn't insert dashes for apostrophes" do
214
+ @article.headline = "Thomas Jefferson's Papers"
215
+ @article.save!
216
+ assert_match 'thomas-jeffersons-papers', @article.slug
217
+ end
218
+
219
+ it "preserves numbers in slug" do
220
+ @article.headline = "2010 Election"
221
+ @article.save!
222
+ assert_match '2010-election', @article.slug
223
+ end
224
+ end
225
+
226
+ describe "diacritics handling" do
227
+ before do
228
+ @article = Article.new
229
+ end
230
+
231
+ it "strips diacritics" do
232
+ @article.headline = "açaí"
233
+ @article.save!
234
+ assert_equal "acai", @article.slug
235
+ end
236
+
237
+ it "strips diacritics correctly " do
238
+ @article.headline = "ÀÁÂÃÄÅÆÇÈÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
239
+ @article.save!
240
+ expected = "aaaaaaaeceeeiiiidnoooooouuuuythssaaaaaaaeceeeeiiiidnoooooouuuuythy".split(//)
241
+ output = @article.slug.split(//)
242
+ output.each_index do |i|
243
+ assert_equal expected[i], output[i]
244
+ end
245
+ end
246
+ end
247
+
248
+ describe "sequence handling" do
249
+ it "doesn't add a sequence if saving first instance of slug" do
250
+ article = Article.create!(:headline => 'Test Headline')
251
+ assert_equal 'test-headline', article.slug
252
+ end
253
+
254
+ it "assigns a -1 suffix to the second instance of the slug" do
255
+ Article.create!(:headline => 'Test Headline')
256
+ article_2 = Article.create!(:headline => 'Test Headline')
257
+ assert_equal 'test-headline-1', article_2.slug
258
+ end
259
+
260
+ it 'assigns a -2 suffix to the third instance of the slug containing numbers' do
261
+ 2.times { |i| Article.create! :headline => '11111' }
262
+ article_3 = Article.create! :headline => '11111'
263
+ assert_equal '11111-2', article_3.slug
264
+ end
265
+
266
+ it "assigns a -12 suffix to the thirteenth instance of the slug" do
267
+ 12.times { |i| Article.create!(:headline => 'Test Headline') }
268
+ article_13 = Article.create!(:headline => 'Test Headline')
269
+ assert_equal 'test-headline-12', article_13.slug
270
+
271
+ 12.times { |i| Article.create!(:headline => 'latest from lybia') }
272
+ article_13 = Article.create!(:headline => 'latest from lybia')
273
+ assert_equal 'latest-from-lybia-12', article_13.slug
274
+ end
275
+
276
+ it "ignores partial matches when calculating sequence" do
277
+ article_1 = Article.create!(:headline => 'Test Headline')
278
+ assert_equal 'test-headline', article_1.slug
279
+ article_2 = Article.create!(:headline => 'Test')
280
+ assert_equal 'test', article_2.slug
281
+ article_3 = Article.create!(:headline => 'Test')
282
+ assert_equal 'test-1', article_3.slug
283
+ article_4 = Article.create!(:headline => 'Test')
284
+ assert_equal 'test-2', article_4.slug
285
+ end
286
+
287
+ it "knows about single table inheritance" do
288
+ article = Article.create!(:headline => 'Test Headline')
289
+ story = Storyline.create!(:headline => article.headline)
290
+ assert_equal 'test-headline-1', story.slug
291
+ end
292
+
293
+ it "correctly slugs when a slug is a substring of another" do
294
+ rap_metal = Article.create!(:headline => 'Rap Metal')
295
+ assert_equal 'rap-metal', rap_metal.slug
296
+
297
+ rap = Article.create!(:headline => 'Rap')
298
+ assert_equal('rap', rap.slug)
299
+ end
300
+
301
+ it "applies sequence logic correctly when the slug is a substring of another" do
302
+ rap_metal = Article.create!(:headline => 'Rap Metal')
303
+ assert_equal 'rap-metal', rap_metal.slug
304
+
305
+ Article.create!(:headline => 'Rap')
306
+ second_rap = Article.create!(:headline => 'Rap')
307
+ assert_equal('rap-1', second_rap.slug)
308
+ end
309
+ end
310
+ end
data/test/test_helper.rb CHANGED
@@ -1,26 +1,21 @@
1
1
  require 'rubygems'
2
- require 'test/unit'
3
- require 'shoulda'
4
- require 'mocha'
5
-
6
- class Test::Unit::TestCase
7
- end
2
+ require 'minitest/autorun'
3
+ require 'minitest/reporters'
8
4
 
9
5
  # You can use "rake test AR_VERSION=2.0.5" to test against 2.0.5, for example.
10
6
  # The default is to use the latest installed ActiveRecord.
11
7
  if ENV["AR_VERSION"]
12
8
  gem 'activerecord', "#{ENV["AR_VERSION"]}"
13
- gem 'activesupport', "#{ENV["AR_VERSION"]}"
14
9
  end
15
10
  require 'active_record'
16
- require 'active_support'
11
+
12
+ # color test output
13
+ Minitest::Reporters.use! [Minitest::Reporters::DefaultReporter.new(:color => true)]
17
14
 
18
15
  $LOAD_PATH.unshift(File.dirname(__FILE__))
19
16
  require 'slug'
20
17
 
21
18
  ActiveRecord::Base.establish_connection :adapter => "sqlite3", :database => ":memory:"
22
- silence_stream(STDOUT) do
23
- load(File.dirname(__FILE__) + "/schema.rb")
24
- end
19
+ load(File.dirname(__FILE__) + "/schema.rb")
25
20
 
26
21
  require 'models'
metadata CHANGED
@@ -1,48 +1,93 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: slug
3
- version: !ruby/object:Gem::Version
4
- version: 0.5.7
3
+ version: !ruby/object:Gem::Version
4
+ version: 4.0.1
5
5
  platform: ruby
6
- authors:
6
+ authors:
7
7
  - Ben Koski
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
-
12
- date: 2010-06-25 00:00:00 -04:00
13
- default_executable:
14
- dependencies:
15
- - !ruby/object:Gem::Dependency
16
- name: activerecord
11
+ date: 2018-11-11 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rake
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
17
20
  type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
20
- requirements:
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: minitest
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
21
52
  - - ">="
22
- - !ruby/object:Gem::Version
23
- version: "0"
24
- version:
25
- - !ruby/object:Gem::Dependency
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: activerecord
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">"
60
+ - !ruby/object:Gem::Version
61
+ version: 3.0.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">"
67
+ - !ruby/object:Gem::Version
68
+ version: 3.0.0
69
+ - !ruby/object:Gem::Dependency
26
70
  name: activesupport
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - ">"
74
+ - !ruby/object:Gem::Version
75
+ version: 3.0.0
27
76
  type: :runtime
28
- version_requirement:
29
- version_requirements: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: "0"
34
- version:
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - ">"
81
+ - !ruby/object:Gem::Version
82
+ version: 3.0.0
35
83
  description: Simple, straightforward slugs for your ActiveRecord models.
36
84
  email: ben.koski@gmail.com
37
85
  executables: []
38
-
39
86
  extensions: []
40
-
41
- extra_rdoc_files:
87
+ extra_rdoc_files:
42
88
  - LICENSE
43
89
  - README.rdoc
44
- files:
45
- - .gitignore
90
+ files:
46
91
  - LICENSE
47
92
  - README.rdoc
48
93
  - Rakefile
@@ -53,38 +98,29 @@ files:
53
98
  - slug.gemspec
54
99
  - test/models.rb
55
100
  - test/schema.rb
101
+ - test/slug_test.rb
56
102
  - test/test_helper.rb
57
- - test/test_slug.rb
58
- has_rdoc: true
59
103
  homepage: http://github.com/bkoski/slug
60
104
  licenses: []
61
-
105
+ metadata: {}
62
106
  post_install_message:
63
- rdoc_options:
64
- - --charset=UTF-8
65
- require_paths:
107
+ rdoc_options: []
108
+ require_paths:
66
109
  - lib
67
- required_ruby_version: !ruby/object:Gem::Requirement
68
- requirements:
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
69
112
  - - ">="
70
- - !ruby/object:Gem::Version
71
- version: "0"
72
- version:
73
- required_rubygems_version: !ruby/object:Gem::Requirement
74
- requirements:
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
75
117
  - - ">="
76
- - !ruby/object:Gem::Version
77
- version: "0"
78
- version:
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
79
120
  requirements: []
80
-
81
121
  rubyforge_project:
82
- rubygems_version: 1.3.5
122
+ rubygems_version: 2.7.6
83
123
  signing_key:
84
- specification_version: 3
124
+ specification_version: 4
85
125
  summary: Simple, straightforward slugs for your ActiveRecord models.
86
- test_files:
87
- - test/models.rb
88
- - test/schema.rb
89
- - test/test_helper.rb
90
- - test/test_slug.rb
126
+ test_files: []
data/.gitignore DELETED
@@ -1,3 +0,0 @@
1
- *.sw?
2
- .DS_Store
3
- coverage
data/test/test_slug.rb DELETED
@@ -1,246 +0,0 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
-
3
- class TestSlug < Test::Unit::TestCase
4
-
5
- def setup
6
- Article.delete_all
7
- Person.delete_all
8
- end
9
-
10
- should "base slug on specified source column" do
11
- article = Article.create!(:headline => 'Test Headline')
12
- assert_equal 'test-headline', article.slug
13
- end
14
-
15
- should "base slug on specified source column, even if it is defined as a method rather than database attribute" do
16
- article = Event.create!(:title => 'Test Event', :location => 'Portland')
17
- assert_equal 'test-event-portland', article.slug
18
- end
19
-
20
- context "slug column" do
21
- should "save slug to 'slug' column by default" do
22
- article = Article.create!(:headline => 'Test Headline')
23
- assert_equal 'test-headline', article.slug
24
- end
25
-
26
- should "save slug to :column specified in options" do
27
- person = Person.create!(:name => 'Test Person')
28
- assert_equal 'test-person', person.web_slug
29
- end
30
- end
31
-
32
- context "column validations" do
33
- should "raise ArgumentError if an invalid source column is passed" do
34
- Company.slug(:invalid_source_column)
35
- assert_raises(ArgumentError) { Company.create! }
36
- end
37
-
38
- should "raise an ArgumentError if an invalid slug column is passed" do
39
- Company.slug(:name, :column => :bad_slug_column)
40
- assert_raises(ArgumentError) { Company.create! }
41
- end
42
- end
43
-
44
- should "set validation error if source column is empty" do
45
- article = Article.create
46
- assert !article.valid?
47
- require 'ruby-debug'
48
- assert article.errors.on(:slug)
49
- end
50
-
51
- should "set validation error if normalization makes source value empty" do
52
- article = Article.create(:headline => '$$$')
53
- assert !article.valid?
54
- assert article.errors.on(:slug)
55
- end
56
-
57
- should "not update the slug even if the source column changes" do
58
- article = Article.create!(:headline => 'Test Headline')
59
- article.update_attributes!(:headline => 'New Headline')
60
- assert_equal 'test-headline', article.slug
61
- end
62
-
63
- should "validate slug format on save" do
64
- article = Article.create!(:headline => 'Test Headline')
65
- article.slug = 'A BAD $LUG.'
66
-
67
- assert !article.valid?
68
- assert article.errors[:slug].present?
69
- end
70
-
71
- should "validate uniqueness of slug by default" do
72
- article1 = Article.create!(:headline => 'Test Headline')
73
- article2 = Article.create!(:headline => 'Test Headline')
74
- article2.slug = 'test-headline'
75
-
76
- assert !article2.valid?
77
- assert article2.errors[:slug].present?
78
- end
79
-
80
- should "use validate_uniquness_if proc to decide whether uniqueness validation applies" do
81
- article1 = Post.create!(:headline => 'Test Headline')
82
- article2 = Post.new
83
- article2.slug = 'test-headline'
84
-
85
- assert article2.valid?
86
- end
87
-
88
- should "not overwrite slug value on create if it was already specified" do
89
- a = Article.create!(:headline => 'Test Headline', :slug => 'slug1')
90
- assert_equal 'slug1', a.slug
91
- end
92
-
93
- context "resetting a slug" do
94
-
95
- setup do
96
- @article = Article.create(:headline => 'test headline')
97
- @original_slug = @article.slug
98
- end
99
-
100
- should "maintain the same slug if slug column hasn't changed" do
101
- @article.reset_slug
102
- assert_equal @original_slug, @article.slug
103
- end
104
-
105
- should "change slug if slug column has updated" do
106
- @article.headline = "donkey"
107
- @article.reset_slug
108
- assert_not_equal @original_slug, @article.slug
109
- end
110
-
111
- should "maintain sequence" do
112
- @existing_article = Article.create!(:headline => 'world cup')
113
- @article.headline = "world cup"
114
- @article.reset_slug
115
- assert_equal 'world-cup-1', @article.slug
116
- end
117
-
118
- end
119
-
120
-
121
- context "slug normalization" do
122
- setup do
123
- @article = Article.new
124
- end
125
-
126
- should "should lowercase strings" do
127
- @article.headline = 'AbC'
128
- @article.save!
129
- assert_equal "abc", @article.slug
130
- end
131
-
132
- should "should replace whitespace with dashes" do
133
- @article.headline = 'a b'
134
- @article.save!
135
- assert_equal 'a-b', @article.slug
136
- end
137
-
138
- should "should replace 2spaces with 1dash" do
139
- @article.headline = 'a b'
140
- @article.save!
141
- assert_equal 'a-b', @article.slug
142
- end
143
-
144
- should "should remove punctuation" do
145
- @article.headline = 'abc!@#$%^&*•¶§∞¢££¡¿()><?""\':;][]\.,/'
146
- @article.save!
147
- assert_match 'abc', @article.slug
148
- end
149
-
150
- should "should strip trailing space" do
151
- @article.headline = 'ab '
152
- @article.save!
153
- assert_equal 'ab', @article.slug
154
- end
155
-
156
- should "should strip leading space" do
157
- @article.headline = ' ab'
158
- @article.save!
159
- assert_equal 'ab', @article.slug
160
- end
161
-
162
- should "should strip trailing dashes" do
163
- @article.headline = 'ab-'
164
- @article.save!
165
- assert_match 'ab', @article.slug
166
- end
167
-
168
- should "should strip leading dashes" do
169
- @article.headline = '-ab'
170
- @article.save!
171
- assert_match 'ab', @article.slug
172
- end
173
-
174
- should "remove double-dashes" do
175
- @article.headline = 'a--b--c'
176
- @article.save!
177
- assert_match 'a-b-c', @article.slug
178
- end
179
-
180
- should "should not modify valid slug strings" do
181
- @article.headline = 'a-b-c-d'
182
- @article.save!
183
- assert_match 'a-b-c-d', @article.slug
184
- end
185
-
186
- should "not insert dashes for periods in acronyms, regardless of where they appear in string" do
187
- @article.headline = "N.Y.P.D. vs. N.S.A. vs. F.B.I."
188
- @article.save!
189
- assert_match 'nypd-vs-nsa-vs-fbi', @article.slug
190
- end
191
-
192
- should "not insert dashes for apostrophes" do
193
- @article.headline = "Thomas Jefferson's Papers"
194
- @article.save!
195
- assert_match 'thomas-jeffersons-papers', @article.slug
196
- end
197
-
198
- should "preserve numbers in slug" do
199
- @article.headline = "2010 Election"
200
- @article.save!
201
- assert_match '2010-election', @article.slug
202
- end
203
- end
204
-
205
- context "diacritics handling" do
206
- setup do
207
- @article = Article.new
208
- end
209
-
210
- should "should strip diacritics" do
211
- @article.headline = "açaí"
212
- @article.save!
213
- assert_equal "acai", @article.slug
214
- end
215
-
216
- should "strip diacritics correctly " do
217
- @article.headline = "ÀÁÂÃÄÅÆÇÈÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõöøùúûüýþÿ"
218
- @article.save!
219
- expected = "aaaaaaaeceeeiiiidnoooooouuuuythssaaaaaaaeceeeeiiiidnoooooouuuuythy".split(//)
220
- output = @article.slug.split(//)
221
- output.each_index do |i|
222
- assert_equal expected[i], output[i]
223
- end
224
- end
225
- end
226
-
227
- context "sequence handling" do
228
- should "not add a sequence if saving first instance of slug" do
229
- article = Article.create!(:headline => 'Test Headline')
230
- assert_equal 'test-headline', article.slug
231
- end
232
-
233
- should "assign a -1 suffix to the second instance of the slug" do
234
- article_1 = Article.create!(:headline => 'Test Headline')
235
- article_2 = Article.create!(:headline => 'Test Headline')
236
- assert_equal 'test-headline-1', article_2.slug
237
- end
238
-
239
- should "assign a -12 suffix to the thirteenth instance of the slug" do
240
- 12.times { |i| Article.create!(:headline => 'Test Headline') }
241
- article_13 = Article.create!(:headline => 'Test Headline')
242
- assert_equal 'test-headline-12', article_13.slug
243
- end
244
- end
245
-
246
- end