slug 0.5.0 → 0.5.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +3 -0
- data/LICENSE +20 -0
- data/README.rdoc +74 -0
- data/Rakefile +47 -0
- data/VERSION.yml +1 -1
- data/lib/slug.rb +1 -1
- data/lib/slug/slug.rb +73 -66
- data/slug.gemspec +62 -0
- data/test/models.rb +23 -0
- data/test/schema.rb +12 -0
- data/test/test_helper.rb +1 -7
- data/test/test_slug.rb +20 -7
- metadata +18 -9
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2008 Ben Koski
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= slug
|
2
|
+
|
3
|
+
Slug provides simple, straightforward slugging for your ActiveRecord models.
|
4
|
+
|
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
|
+
|
7
|
+
Here's what's different:
|
8
|
+
|
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
|
+
* 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)
|
12
|
+
|
13
|
+
== INSTALLATION
|
14
|
+
|
15
|
+
sudo gem install slug --source http://gemcutter.org
|
16
|
+
|
17
|
+
then add
|
18
|
+
|
19
|
+
config.gem 'slug', :source => 'http://gemcutter.org'
|
20
|
+
|
21
|
+
to your rails project.
|
22
|
+
|
23
|
+
== USAGE
|
24
|
+
|
25
|
+
It's up to you to set up the appropriate column in your model. By default, Slug saves the slug to a column called 'slug', so in most cases you'll just want to add
|
26
|
+
|
27
|
+
t.string :slug
|
28
|
+
|
29
|
+
to your create migration.
|
30
|
+
|
31
|
+
I'd also suggest adding a unique index on the slug field in your migration
|
32
|
+
|
33
|
+
add_index :model_name, :slug, :unique => true
|
34
|
+
|
35
|
+
Though Slug uses validates_uniqueness_of to ensue the uniqueness of your slug, two concurrent INSERTs could conceivably try to set the same slug. Unlikely, but it's worth adding a unique index as a backstop.
|
36
|
+
|
37
|
+
Once your table is migrated, just add
|
38
|
+
|
39
|
+
slug :source_field
|
40
|
+
|
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
|
+
|
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>.
|
48
|
+
|
49
|
+
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
|
+
|
51
|
+
For example:
|
52
|
+
|
53
|
+
class Article < ActiveRecord::Base
|
54
|
+
slug :title_for_slug
|
55
|
+
|
56
|
+
def title_for_slug
|
57
|
+
"#{headline}-#{publication_date.year}-#{publication_date.month}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
would use headline-pub year-pub month as the slug source.
|
63
|
+
|
64
|
+
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
|
+
|
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.
|
68
|
+
* 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
|
+
* 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
|
+
* 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
|
+
|
72
|
+
== AUTHOR
|
73
|
+
|
74
|
+
Ben Koski, ben.koski@gmail.com
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rake'
|
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'
|
21
|
+
Rake::RDocTask.new do |rdoc|
|
22
|
+
rdoc.rdoc_dir = 'rdoc'
|
23
|
+
rdoc.title = 'slug'
|
24
|
+
rdoc.options << '--line-numbers' << '--inline-source' << '--all'
|
25
|
+
rdoc.rdoc_files.include('README*')
|
26
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
27
|
+
end
|
28
|
+
|
29
|
+
require 'rake/testtask'
|
30
|
+
Rake::TestTask.new(:test) do |t|
|
31
|
+
t.libs << 'lib' << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
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
|
+
task :default => :test
|
data/VERSION.yml
CHANGED
data/lib/slug.rb
CHANGED
@@ -2,5 +2,5 @@ require File.join(File.dirname(__FILE__), 'slug', 'slug')
|
|
2
2
|
require File.join(File.dirname(__FILE__), 'slug', 'ascii_approximations')
|
3
3
|
|
4
4
|
if defined?(ActiveRecord)
|
5
|
-
ActiveRecord::Base.
|
5
|
+
ActiveRecord::Base.instance_eval { extend Slug::ClassMethods }
|
6
6
|
end
|
data/lib/slug/slug.rb
CHANGED
@@ -14,91 +14,98 @@ module Slug
|
|
14
14
|
# later on, call <tt>@model.set_slug</tt>
|
15
15
|
def slug source, opts={}
|
16
16
|
class_inheritable_accessor :slug_source, :slug_column
|
17
|
+
include InstanceMethods
|
17
18
|
|
18
19
|
self.slug_source = source
|
19
|
-
raise ArgumentError, "Source column '#{self.slug_source}' does not exist!" if !self.column_names.include?(self.slug_source.to_s)
|
20
20
|
|
21
21
|
self.slug_column = opts.has_key?(:column) ? opts[:column] : :slug
|
22
|
-
raise ArgumentError, "Slug column '#{self.slug_column}' does not exist! #{self.column_names.join(',')}" if !self.column_names.include?(self.slug_column.to_s)
|
23
22
|
|
24
|
-
validates_presence_of self.slug_column
|
23
|
+
validates_presence_of self.slug_column, :message => "#{self.slug_column} cannot be blank. Is #{self.slug_source} sluggable?"
|
25
24
|
validates_uniqueness_of self.slug_column
|
26
25
|
before_validation_on_create :set_slug
|
27
26
|
end
|
28
27
|
end
|
29
28
|
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
module InstanceMethods
|
30
|
+
|
31
|
+
# Sets the slug. Called before create.
|
32
|
+
def set_slug
|
33
|
+
validate_slug_columns
|
34
|
+
self[self.slug_column] = self.send(self.slug_source)
|
33
35
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
self.errors.add(self.slug_column, "#{self.slug_column} cannot be blank. Is #{self.slug_source} sluggable?") if self[self.slug_column].blank?
|
39
|
-
end
|
36
|
+
strip_diacritics_from_slug
|
37
|
+
normalize_slug
|
38
|
+
assign_slug_sequence
|
39
|
+
end
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
# Overrides to_param to return the model's slug.
|
42
|
+
def to_param
|
43
|
+
self[self.slug_column]
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
|
48
|
-
|
46
|
+
def self.included(klass)
|
47
|
+
klass.extend(ClassMethods)
|
48
|
+
end
|
49
49
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
50
|
+
private
|
51
|
+
# Validates that source and destination methods exist. Invoked at runtime to allow definition
|
52
|
+
# of source/slug methods after <tt>slug</tt> setup in class.
|
53
|
+
def validate_slug_columns
|
54
|
+
raise ArgumentError, "Source column '#{self.slug_source}' does not exist!" if !self.respond_to?(self.slug_source)
|
55
|
+
raise ArgumentError, "Slug column '#{self.slug_column}' does not exist!" if !self.respond_to?("#{self.slug_column}=")
|
56
|
+
end
|
57
|
+
|
58
|
+
# Takes the slug, downcases it and replaces non-word characters with a -.
|
59
|
+
# Feel free to override this method if you'd like different slug formatting.
|
60
|
+
def normalize_slug
|
61
|
+
return if self[self.slug_column].blank?
|
62
|
+
s = ActiveSupport::Multibyte.proxy_class.new(self[self.slug_column]).normalize(:kc)
|
63
|
+
s.downcase!
|
64
|
+
s.strip!
|
65
|
+
s.gsub!(/[\W]/u, ' ') # Remove non-word characters
|
66
|
+
s.gsub!(/\s+/u, '-') # Convert whitespaces to dashes
|
67
|
+
s.gsub!(/-\z/u, '') # Remove trailing dashes
|
68
|
+
self[self.slug_column] = s.to_s
|
69
|
+
end
|
63
70
|
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
71
|
+
# Converts accented characters to their ASCII equivalents and removes them if they have no equivalent.
|
72
|
+
# Override this with a void function if you don't want accented characters to be stripped.
|
73
|
+
def strip_diacritics_from_slug
|
74
|
+
return if self[self.slug_column].blank?
|
75
|
+
s = ActiveSupport::Multibyte.proxy_class.new(self[self.slug_column])
|
76
|
+
s = s.normalize(:kd).unpack('U*')
|
77
|
+
s = s.inject([]) do |a,u|
|
78
|
+
if Slug::ASCII_APPROXIMATIONS[u]
|
79
|
+
a += Slug::ASCII_APPROXIMATIONS[u].unpack('U*')
|
80
|
+
elsif (u < 0x300 || u > 0x036F)
|
81
|
+
a << u
|
82
|
+
end
|
83
|
+
a
|
75
84
|
end
|
76
|
-
|
85
|
+
s = s.pack('U*')
|
86
|
+
s.gsub!(/[^a-z0-9]+/i, ' ')
|
87
|
+
self[self.slug_column] = s.to_s
|
77
88
|
end
|
78
|
-
s = s.pack('U*')
|
79
|
-
s.gsub!(/[^a-z0-9]+/i, ' ')
|
80
|
-
self[self.slug_column] = s.to_s
|
81
|
-
end
|
82
89
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
+
# If a slug of the same name already exists, this will append '-n' to the end of the slug to
|
91
|
+
# make it unique. The second instance gets a '-1' suffix.
|
92
|
+
def assign_slug_sequence
|
93
|
+
return if self[self.slug_column].blank?
|
94
|
+
idx = next_slug_sequence
|
95
|
+
self[self.slug_column] = "#{self[self.slug_column]}-#{idx}" if idx > 0
|
96
|
+
end
|
90
97
|
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
98
|
+
# Returns the next unique index for a slug.
|
99
|
+
def next_slug_sequence
|
100
|
+
last_in_sequence = self.class.find(:first, :conditions => ["#{self.slug_column} LIKE ?", self[self.slug_column] + '%'],
|
101
|
+
:order => "CAST(REPLACE(#{self.slug_column},'#{self[self.slug_column]}','') AS UNSIGNED)")
|
102
|
+
if last_in_sequence.nil?
|
103
|
+
return 0
|
104
|
+
else
|
105
|
+
sequence_match = last_in_sequence[self.slug_column].match(/^#{self[self.slug_column]}(-(\d+))?/)
|
106
|
+
current = sequence_match.nil? ? 0 : sequence_match[2].to_i
|
107
|
+
return current + 1
|
108
|
+
end
|
101
109
|
end
|
102
110
|
end
|
103
|
-
|
104
111
|
end
|
data/slug.gemspec
ADDED
@@ -0,0 +1,62 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{slug}
|
8
|
+
s.version = "0.5.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Ben Koski"]
|
12
|
+
s.date = %q{2009-12-07}
|
13
|
+
s.description = %q{Simple, straightforward slugs for your ActiveRecord models.}
|
14
|
+
s.email = %q{ben.koski@gmail.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
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 = [
|
40
|
+
"test/models.rb",
|
41
|
+
"test/schema.rb",
|
42
|
+
"test/test_helper.rb",
|
43
|
+
"test/test_slug.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
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"])
|
53
|
+
else
|
54
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
55
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
56
|
+
end
|
57
|
+
else
|
58
|
+
s.add_dependency(%q<activerecord>, [">= 0"])
|
59
|
+
s.add_dependency(%q<activesupport>, [">= 0"])
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
data/test/models.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
# Used to test slug behavior in general
|
2
|
+
class Article < ActiveRecord::Base
|
3
|
+
slug :headline
|
4
|
+
end
|
5
|
+
|
6
|
+
# Used to test alternate slug column
|
7
|
+
class Person < ActiveRecord::Base
|
8
|
+
slug :name, :column => :web_slug
|
9
|
+
end
|
10
|
+
|
11
|
+
# Used to test invalid method names
|
12
|
+
class Company < ActiveRecord::Base
|
13
|
+
slug :name
|
14
|
+
end
|
15
|
+
|
16
|
+
# Used to test slugs based on methods rather than database attributes
|
17
|
+
class Event < ActiveRecord::Base
|
18
|
+
slug :title_for_slug
|
19
|
+
|
20
|
+
def title_for_slug
|
21
|
+
"#{title}-#{location}"
|
22
|
+
end
|
23
|
+
end
|
data/test/schema.rb
CHANGED
@@ -2,6 +2,7 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
2
2
|
|
3
3
|
create_table "articles", :force => true do |t|
|
4
4
|
t.column "headline", "string"
|
5
|
+
t.column "section", "string"
|
5
6
|
t.column "slug", "string"
|
6
7
|
end
|
7
8
|
|
@@ -10,4 +11,15 @@ ActiveRecord::Schema.define(:version => 1) do
|
|
10
11
|
t.column "web_slug", "string"
|
11
12
|
end
|
12
13
|
|
14
|
+
create_table "companies", :force => true do |t|
|
15
|
+
t.column "name", "string"
|
16
|
+
t.column "slug", "string"
|
17
|
+
end
|
18
|
+
|
19
|
+
create_table "events", :force => true do |t|
|
20
|
+
t.column "title", "string"
|
21
|
+
t.column "location", "string"
|
22
|
+
t.column "slug", "string"
|
23
|
+
end
|
24
|
+
|
13
25
|
end
|
data/test/test_helper.rb
CHANGED
data/test/test_slug.rb
CHANGED
@@ -12,6 +12,11 @@ class TestSlug < Test::Unit::TestCase
|
|
12
12
|
assert_equal 'test-headline', article.slug
|
13
13
|
end
|
14
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
|
+
|
15
20
|
context "slug column" do
|
16
21
|
should "save slug to 'slug' column by default" do
|
17
22
|
article = Article.create!(:headline => 'Test Headline')
|
@@ -24,29 +29,31 @@ class TestSlug < Test::Unit::TestCase
|
|
24
29
|
end
|
25
30
|
end
|
26
31
|
|
27
|
-
context "
|
28
|
-
teardown do
|
29
|
-
Person.slug(:name, :column => :web_slug) # Reset Person slug column to valid config.
|
30
|
-
end
|
31
|
-
|
32
|
+
context "column validations" do
|
32
33
|
should "raise ArgumentError if an invalid source column is passed" do
|
33
|
-
|
34
|
+
Company.slug(:invalid_source_column)
|
35
|
+
assert_raises(ArgumentError) { Company.create! }
|
34
36
|
end
|
35
37
|
|
36
38
|
should "raise an ArgumentError if an invalid slug column is passed" do
|
37
|
-
|
39
|
+
Company.slug(:name, :column => :bad_slug_column)
|
40
|
+
assert_raises(ArgumentError) { Company.create! }
|
38
41
|
end
|
39
42
|
end
|
40
43
|
|
41
44
|
should "set validation error if source column is empty" do
|
42
45
|
article = Article.create
|
43
46
|
assert !article.valid?
|
47
|
+
require 'ruby-debug'
|
48
|
+
debugger if article.errors.count > 1
|
49
|
+
assert_equal 1, article.errors.count
|
44
50
|
assert article.errors.on(:slug)
|
45
51
|
end
|
46
52
|
|
47
53
|
should "set validation error if normalization makes source value empty" do
|
48
54
|
article = Article.create(:headline => '---')
|
49
55
|
assert !article.valid?
|
56
|
+
assert_equal 1, article.errors.count
|
50
57
|
assert article.errors.on(:slug)
|
51
58
|
end
|
52
59
|
|
@@ -109,6 +116,12 @@ class TestSlug < Test::Unit::TestCase
|
|
109
116
|
assert_match 'ab', @article.slug
|
110
117
|
end
|
111
118
|
|
119
|
+
should "remove double-dashes" do
|
120
|
+
@article.headline = 'a--b--c'
|
121
|
+
@article.save!
|
122
|
+
assert_match 'a-b-c', @article.slug
|
123
|
+
end
|
124
|
+
|
112
125
|
should "should not modify valid slug strings" do
|
113
126
|
@article.headline = 'a-b-c-d'
|
114
127
|
@article.save!
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.5.
|
4
|
+
version: 0.5.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ben Koski
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-
|
12
|
+
date: 2009-12-07 00:00:00 -05:00
|
13
13
|
default_executable:
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -38,13 +38,20 @@ executables: []
|
|
38
38
|
|
39
39
|
extensions: []
|
40
40
|
|
41
|
-
extra_rdoc_files:
|
42
|
-
|
41
|
+
extra_rdoc_files:
|
42
|
+
- LICENSE
|
43
|
+
- README.rdoc
|
43
44
|
files:
|
45
|
+
- .gitignore
|
46
|
+
- LICENSE
|
47
|
+
- README.rdoc
|
48
|
+
- Rakefile
|
44
49
|
- VERSION.yml
|
50
|
+
- lib/slug.rb
|
45
51
|
- lib/slug/ascii_approximations.rb
|
46
52
|
- lib/slug/slug.rb
|
47
|
-
-
|
53
|
+
- slug.gemspec
|
54
|
+
- test/models.rb
|
48
55
|
- test/schema.rb
|
49
56
|
- test/test_helper.rb
|
50
57
|
- test/test_slug.rb
|
@@ -54,7 +61,6 @@ licenses: []
|
|
54
61
|
|
55
62
|
post_install_message:
|
56
63
|
rdoc_options:
|
57
|
-
- --inline-source
|
58
64
|
- --charset=UTF-8
|
59
65
|
require_paths:
|
60
66
|
- lib
|
@@ -75,7 +81,10 @@ requirements: []
|
|
75
81
|
rubyforge_project:
|
76
82
|
rubygems_version: 1.3.5
|
77
83
|
signing_key:
|
78
|
-
specification_version:
|
84
|
+
specification_version: 3
|
79
85
|
summary: Simple, straightforward slugs for your ActiveRecord models.
|
80
|
-
test_files:
|
81
|
-
|
86
|
+
test_files:
|
87
|
+
- test/models.rb
|
88
|
+
- test/schema.rb
|
89
|
+
- test/test_helper.rb
|
90
|
+
- test/test_slug.rb
|