friendly_id4 4.0.0.beta1 → 4.0.0.beta3
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/.gemtest +0 -0
- data/Gemfile +4 -3
- data/Guide.md +31 -36
- data/README.md +8 -7
- data/Rakefile +12 -5
- data/bench.rb +20 -28
- data/lib/friendly_id/base.rb +11 -16
- data/lib/friendly_id/configuration.rb +78 -13
- data/lib/friendly_id/finder_methods.rb +1 -3
- data/lib/friendly_id/history.rb +7 -5
- data/lib/friendly_id/object_utils.rb +5 -2
- data/lib/friendly_id/scoped.rb +25 -30
- data/lib/friendly_id/slug_sequencer.rb +1 -2
- data/lib/friendly_id/slugged.rb +20 -22
- data/lib/friendly_id/version.rb +1 -1
- data/lib/friendly_id.rb +25 -0
- data/test/base_test.rb +31 -0
- data/test/configuration_test.rb +27 -0
- data/test/core_test.rb +4 -9
- data/test/helper.rb +6 -2
- data/test/history_test.rb +11 -2
- data/test/scoped_test.rb +13 -5
- data/test/slugged_test.rb +6 -6
- metadata +79 -80
data/.gemtest
ADDED
File without changes
|
data/Gemfile
CHANGED
@@ -7,12 +7,13 @@ platform :jruby do
|
|
7
7
|
end
|
8
8
|
|
9
9
|
platform :ruby do
|
10
|
-
gem "mysql"
|
11
|
-
gem "pg"
|
10
|
+
# gem "mysql"
|
11
|
+
# gem "pg"
|
12
12
|
gem "sqlite3"
|
13
13
|
end
|
14
14
|
|
15
|
-
gem "activerecord", ENV["AR"] || "3.0.9"
|
15
|
+
#gem "activerecord", ENV["AR"] || "3.0.9"
|
16
|
+
gem "rails", :path => "../rails"
|
16
17
|
|
17
18
|
gem "ffaker"
|
18
19
|
gem "minitest"
|
data/Guide.md
CHANGED
@@ -25,8 +25,9 @@ column with no spaces or special characters, and that is seldom or never
|
|
25
25
|
updated. The most common example of this is a user name or login column:
|
26
26
|
|
27
27
|
class User < ActiveRecord::Base
|
28
|
+
extend FriendlyId
|
28
29
|
validates_format_of :login, :with => /\A[a-z0-9]+\z/i
|
29
|
-
|
30
|
+
friendly_id :login
|
30
31
|
end
|
31
32
|
|
32
33
|
@user = User.find "joe" # the old User.find(1) still works, too
|
@@ -38,7 +39,8 @@ modify the value of the column, and your application should ensure that the valu
|
|
38
39
|
is admissible in a URL:
|
39
40
|
|
40
41
|
class City < ActiveRecord::Base
|
41
|
-
|
42
|
+
extend FriendlyId
|
43
|
+
friendly_id :name
|
42
44
|
end
|
43
45
|
|
44
46
|
@city.find "Viña del Mar"
|
@@ -55,8 +57,8 @@ title, which may have spaces, uppercase characters, or other attributes you
|
|
55
57
|
wish to modify to make them more suitable for use in URL's.
|
56
58
|
|
57
59
|
class Post < ActiveRecord::Base
|
58
|
-
|
59
|
-
|
60
|
+
extend FriendlyId
|
61
|
+
friendly_id :title, :use => :slugged
|
60
62
|
end
|
61
63
|
|
62
64
|
@post = Post.create(:title => "This is the first post!")
|
@@ -83,16 +85,13 @@ dropped until a stable release of 3.2 is out, or possibly longer.
|
|
83
85
|
|
84
86
|
## Configuration
|
85
87
|
|
86
|
-
FriendlyId is configured in your model using the `
|
87
|
-
features can be
|
88
|
+
FriendlyId is configured in your model using the `friendly_id` method. Additional
|
89
|
+
features can be passing the names of modules into the `:use` option:
|
88
90
|
|
89
91
|
class Post < ActiveRecord::Base
|
90
|
-
|
91
|
-
include FriendlyId::Slugged
|
92
|
-
# record slug history
|
93
|
-
include FriendlyId::History
|
92
|
+
extend FriendlyId
|
94
93
|
# use the "title" accessor as the basis of the friendly_id
|
95
|
-
|
94
|
+
friendly_id :title, :use => [:slugged, :history]
|
96
95
|
end
|
97
96
|
|
98
97
|
Read on to learn about the various features that can be configured. For the
|
@@ -121,10 +120,9 @@ FriendlyId can use either a column or a method to generate the slug text for
|
|
121
120
|
your model:
|
122
121
|
|
123
122
|
class City < ActiveRecord::Base
|
124
|
-
|
123
|
+
extend FriendlyId
|
125
124
|
belongs_to :country
|
126
|
-
|
127
|
-
has_friendly_id :name_and_country
|
125
|
+
friendly_id :name_and_country, :use => :slugged
|
128
126
|
|
129
127
|
def name_and_country
|
130
128
|
#{name} #{country.name}
|
@@ -148,9 +146,8 @@ you can override the `normalize_friendly_id` method in your model class in
|
|
148
146
|
order to fine-tune the output:
|
149
147
|
|
150
148
|
class City < ActiveRecord::Base
|
151
|
-
|
152
|
-
|
153
|
-
has_friendly_id :whatever
|
149
|
+
extend FriendlyId
|
150
|
+
friendly_id :whatever, :use => :slugged
|
154
151
|
|
155
152
|
def normalize_friendly_id(text)
|
156
153
|
my_text_modifier_method(text)
|
@@ -186,9 +183,8 @@ FriendlyId can maintain a history of your record's older slugs, so if your
|
|
186
183
|
record's friendly_id changes, your URL's won't break.
|
187
184
|
|
188
185
|
class Post < ActiveRecord::Base
|
189
|
-
|
190
|
-
|
191
|
-
has_friendly_id :title
|
186
|
+
extend FriendlyId
|
187
|
+
friendly_id :title, :use => :history
|
192
188
|
end
|
193
189
|
|
194
190
|
class PostsController < ApplicationController
|
@@ -230,10 +226,9 @@ the rest of the slug. This is important to enable having slugs like:
|
|
230
226
|
/cars/peugeot-206--2
|
231
227
|
|
232
228
|
You can configure the separator string used by your model by setting the
|
233
|
-
`:sequence_separator` option in `
|
229
|
+
`:sequence_separator` option in `friendly_id`:
|
234
230
|
|
235
|
-
|
236
|
-
has_friendly_id :title, :sequence_separator => ":"
|
231
|
+
friendly_id :title, :use => :slugged, :sequence_separator => ":"
|
237
232
|
|
238
233
|
You can also override the default used in
|
239
234
|
{FriendlyId::Configuration::DEFAULTS} to set the value for any model using
|
@@ -259,16 +254,15 @@ names unique for each city, so that the second "Joe's Diner" can also have the
|
|
259
254
|
slug "joes-diner", as long as it's located in a different city:
|
260
255
|
|
261
256
|
class Restaurant < ActiveRecord::Base
|
257
|
+
extend FriendlyId
|
262
258
|
belongs_to :city
|
263
|
-
|
264
|
-
include FriendlyId::Scoped
|
265
|
-
has_friendly_id :name, :scope => :city
|
259
|
+
friendly_id :name, :use => :scoped, :scope => :city
|
266
260
|
end
|
267
261
|
|
268
262
|
class City < ActiveRecord::Base
|
263
|
+
extend FriendlyId
|
269
264
|
has_many :restaurants
|
270
|
-
|
271
|
-
has_friendly_id :name
|
265
|
+
friendly_id :name, :use => :slugged
|
272
266
|
end
|
273
267
|
|
274
268
|
City.find("seattle").restaurants.find("joes-diner")
|
@@ -355,14 +349,15 @@ performance of your application. Of course your results may vary.
|
|
355
349
|
|
356
350
|
activerecord (3.0.9)
|
357
351
|
ruby 1.9.2p180 (2011-02-18 revision 30909) [x86_64-darwin10.6.0]
|
358
|
-
friendly_id (4.0.0.
|
352
|
+
friendly_id (4.0.0.beta1)
|
359
353
|
sqlite3 (1.3.3) gem
|
360
354
|
sqlite3 3.6.12 in-memory database
|
361
355
|
|
362
|
-
|
363
|
-
|
364
|
-
find (
|
365
|
-
find (
|
366
|
-
|
367
|
-
insert (
|
368
|
-
insert (
|
356
|
+
|
357
|
+
user system total real
|
358
|
+
find (without FriendlyId) 0.300000 0.000000 0.300000 ( 0.306729)
|
359
|
+
find (in-table slug) 0.350000 0.000000 0.350000 ( 0.351760)
|
360
|
+
find (external slug) 3.320000 0.000000 3.320000 ( 3.326749)
|
361
|
+
insert (without FriendlyId) 0.810000 0.010000 0.820000 ( 0.810513)
|
362
|
+
insert (in-table-slug) 1.740000 0.000000 1.740000 ( 1.743511)
|
363
|
+
insert (external slug) 3.540000 0.010000 3.550000 ( 3.544898)
|
data/README.md
CHANGED
@@ -58,8 +58,8 @@ FriendlyId is compatible with Active Record **3.0** and **3.1**.
|
|
58
58
|
|
59
59
|
# edit app/models/user.rb
|
60
60
|
class User < ActiveRecord::Base
|
61
|
-
|
62
|
-
|
61
|
+
extend FriendlyId
|
62
|
+
friendly_id :name, :use => :slugged
|
63
63
|
end
|
64
64
|
|
65
65
|
User.create! :name => "Joe Schmoe"
|
@@ -70,14 +70,14 @@ FriendlyId is compatible with Active Record **3.0** and **3.1**.
|
|
70
70
|
|
71
71
|
## Bugs
|
72
72
|
|
73
|
-
Please report them on the [Github issue
|
74
|
-
for this project.
|
73
|
+
Please report them on the [Github issue
|
74
|
+
tracker](http://github.com/norman/friendly_id/issues) for this project.
|
75
75
|
|
76
76
|
If you have a bug to report, please include the following information:
|
77
77
|
|
78
78
|
* **Version information for FriendlyId, Rails and Ruby.**
|
79
79
|
* Stack trace and error message.
|
80
|
-
* Any snippets of relevant model, view or controller code that shows how
|
80
|
+
* Any snippets of relevant model, view or controller code that shows how you
|
81
81
|
are using FriendlyId.
|
82
82
|
|
83
83
|
If you are able to, it helps even more if you can fork FriendlyId on Github,
|
@@ -85,8 +85,9 @@ and add a test that reproduces the error you are experiencing.
|
|
85
85
|
|
86
86
|
## Credits
|
87
87
|
|
88
|
-
FriendlyId was created by Norman Clarke
|
89
|
-
|
88
|
+
FriendlyId was originally created by Norman Clarke and Adrian Mugnolo, with
|
89
|
+
significant help early in its life by Emilio Tagua. I'm deeply gratful for the
|
90
|
+
generous contributions over the years from [many
|
90
91
|
volunteers](https://github.com/norman/friendly_id/contributors).
|
91
92
|
|
92
93
|
Copyright (c) 2008-2011 Norman Clarke, released under the MIT license.
|
data/Rakefile
CHANGED
@@ -3,25 +3,28 @@ require "rake/testtask"
|
|
3
3
|
|
4
4
|
def rubies(&block)
|
5
5
|
["ruby-1.9.2-p180", "ree-1.8.7-2011.03", "jruby-1.6.2", "rbx-2.0.0pre"].each do |ruby|
|
6
|
+
old = ENV["RB"]
|
6
7
|
ENV["RB"] = ruby
|
7
8
|
yield
|
8
|
-
ENV["RB"] =
|
9
|
+
ENV["RB"] = old
|
9
10
|
end
|
10
11
|
end
|
11
12
|
|
12
13
|
def versions(&block)
|
13
14
|
["3.1.0.rc4", "3.0.9"].each do |version|
|
15
|
+
old = ENV["AR"]
|
14
16
|
ENV["AR"] = version
|
15
17
|
yield
|
16
|
-
ENV["AR"] =
|
18
|
+
ENV["AR"] = old
|
17
19
|
end
|
18
20
|
end
|
19
21
|
|
20
22
|
def adapters(&block)
|
21
23
|
["mysql", "postgres", "sqlite3"].each do |adapter|
|
24
|
+
old = ENV["DB"]
|
22
25
|
ENV["DB"] = adapter
|
23
26
|
yield
|
24
|
-
ENV["DB"] =
|
27
|
+
ENV["DB"] = old
|
25
28
|
end
|
26
29
|
end
|
27
30
|
|
@@ -33,7 +36,7 @@ Rake::TestTask.new do |t|
|
|
33
36
|
end
|
34
37
|
|
35
38
|
task :clean do
|
36
|
-
%x{rm -rf *.gem doc pkg}
|
39
|
+
%x{rm -rf *.gem doc pkg coverage}
|
37
40
|
%x{rm -f `find . -name '*.rbc'`}
|
38
41
|
end
|
39
42
|
|
@@ -42,7 +45,11 @@ task :gem do
|
|
42
45
|
end
|
43
46
|
|
44
47
|
task :yard do
|
45
|
-
%x{bundle exec yard doc --files=*.md}
|
48
|
+
puts %x{bundle exec yard doc --files=*.md}
|
49
|
+
end
|
50
|
+
|
51
|
+
task :bench do
|
52
|
+
require File.expand_path("../bench", __FILE__)
|
46
53
|
end
|
47
54
|
|
48
55
|
desc "Bundle for all supported Ruby/AR versions"
|
data/bench.rb
CHANGED
@@ -1,49 +1,41 @@
|
|
1
1
|
require File.expand_path("../test/helper", __FILE__)
|
2
2
|
require "ffaker"
|
3
|
-
require "friendly_id/migration"
|
4
3
|
|
5
4
|
N = 1000
|
6
5
|
|
7
|
-
|
8
|
-
|
9
|
-
m.add_index :users, :slug, :unique => true
|
6
|
+
def transaction
|
7
|
+
ActiveRecord::Base.transaction { yield ; raise ActiveRecord::Rollback }
|
10
8
|
end
|
11
9
|
|
12
|
-
migration do |m|
|
13
|
-
m.create_table :posts do |t|
|
14
|
-
t.string :name
|
15
|
-
t.string :slug
|
16
|
-
end
|
17
|
-
m.add_index :posts, :slug, :unique => true
|
18
|
-
end
|
19
|
-
CreateFriendlyIdSlugs.up
|
20
|
-
|
21
|
-
|
22
10
|
class Array
|
23
11
|
def rand
|
24
12
|
self[Kernel.rand(length)]
|
25
13
|
end
|
26
14
|
end
|
27
15
|
|
28
|
-
|
16
|
+
Book = Class.new ActiveRecord::Base
|
17
|
+
|
18
|
+
class Journalist < ActiveRecord::Base
|
19
|
+
extend FriendlyId
|
29
20
|
include FriendlyId::Slugged
|
30
|
-
|
21
|
+
friendly_id :name
|
31
22
|
end
|
32
23
|
|
33
|
-
class
|
24
|
+
class Manual < ActiveRecord::Base
|
25
|
+
extend FriendlyId
|
34
26
|
include FriendlyId::History
|
35
|
-
|
27
|
+
friendly_id :name
|
36
28
|
end
|
37
29
|
|
38
|
-
|
39
|
-
|
40
|
-
|
30
|
+
BOOKS = []
|
31
|
+
JOURNALISTS = []
|
32
|
+
MANUALS = []
|
41
33
|
|
42
34
|
100.times do
|
43
35
|
name = Faker::Name.name
|
44
|
-
|
45
|
-
|
46
|
-
|
36
|
+
BOOKS << (Book.create! :name => name).id
|
37
|
+
JOURNALISTS << (Journalist.create! :name => name).friendly_id
|
38
|
+
MANUALS << (Manual.create! :name => name).friendly_id
|
47
39
|
end
|
48
40
|
|
49
41
|
Benchmark.bmbm do |x|
|
@@ -51,10 +43,10 @@ Benchmark.bmbm do |x|
|
|
51
43
|
N.times {Book.find BOOKS.rand}
|
52
44
|
end
|
53
45
|
x.report 'find (in-table slug)' do
|
54
|
-
N.times {
|
46
|
+
N.times {Journalist.find JOURNALISTS.rand}
|
55
47
|
end
|
56
48
|
x.report 'find (external slug)' do
|
57
|
-
N.times {
|
49
|
+
N.times {Manual.find_by_friendly_id MANUALS.rand}
|
58
50
|
end
|
59
51
|
|
60
52
|
x.report 'insert (without FriendlyId)' do
|
@@ -62,10 +54,10 @@ Benchmark.bmbm do |x|
|
|
62
54
|
end
|
63
55
|
|
64
56
|
x.report 'insert (in-table-slug)' do
|
65
|
-
N.times {transaction {
|
57
|
+
N.times {transaction {Journalist.create :name => Faker::Name.name}}
|
66
58
|
end
|
67
59
|
|
68
60
|
x.report 'insert (external slug)' do
|
69
|
-
N.times {transaction {
|
61
|
+
N.times {transaction {Manual.create :name => Faker::Name.name}}
|
70
62
|
end
|
71
63
|
end
|
data/lib/friendly_id/base.rb
CHANGED
@@ -1,29 +1,24 @@
|
|
1
1
|
module FriendlyId
|
2
2
|
# Class methods that will be added to ActiveRecord::Base.
|
3
3
|
module Base
|
4
|
-
extend self
|
5
4
|
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
5
|
+
def friendly_id(*args, &block)
|
6
|
+
if block_given?
|
7
|
+
yield(friendly_id_config)
|
8
|
+
else
|
9
|
+
base = args.shift
|
10
|
+
options = args.extract_options!
|
11
|
+
@friendly_id_config.use options.delete :use
|
12
|
+
@friendly_id_config.send :set, options.merge(:base => base)
|
13
|
+
end
|
13
14
|
before_save do |record|
|
14
15
|
record.instance_eval {@current_friendly_id = friendly_id}
|
15
16
|
end
|
16
|
-
|
17
|
+
include Model
|
17
18
|
end
|
18
19
|
|
19
20
|
def friendly_id_config
|
20
|
-
@friendly_id_config
|
21
|
-
end
|
22
|
-
|
23
|
-
def uses_friendly_id?
|
24
|
-
defined? @friendly_id_config
|
21
|
+
@friendly_id_config
|
25
22
|
end
|
26
23
|
end
|
27
24
|
end
|
28
|
-
|
29
|
-
ActiveRecord::Base.extend FriendlyId::Base
|
@@ -1,31 +1,96 @@
|
|
1
1
|
module FriendlyId
|
2
|
-
# The configuration paramters passed to +
|
3
|
-
#
|
2
|
+
# The configuration paramters passed to +friendly_id+ will be stored in
|
3
|
+
# this object.
|
4
4
|
class Configuration
|
5
|
-
attr_accessor :base
|
6
|
-
attr_reader :klass
|
7
5
|
|
8
|
-
|
9
|
-
|
10
|
-
|
6
|
+
# The base column or method used by FriendlyId as the basis of a friendly id
|
7
|
+
# or slug.
|
8
|
+
#
|
9
|
+
# For models that don't use FriendlyId::Slugged, the base is the column that
|
10
|
+
# is used as the FriendlyId directly. For models using FriendlyId::Slugged,
|
11
|
+
# the base is a column or method whose value is used as the basis of the
|
12
|
+
# slug.
|
13
|
+
#
|
14
|
+
# For example, if you have a model representing blog posts and that uses
|
15
|
+
# slugs, you likely will want to use the "title" attribute as the base, and
|
16
|
+
# FriendlyId will take care of transforming the human-readable title into
|
17
|
+
# something suitable for use in a URL.
|
18
|
+
#
|
19
|
+
# @param [Symbol] A symbol referencing a column or method in the model. This
|
20
|
+
# value is usually set by passing it as the first argument to
|
21
|
+
# {FriendlyId::Base#friendly_id friendly_id}:
|
22
|
+
#
|
23
|
+
# @example
|
24
|
+
# class Book < ActiveRecord::Base
|
25
|
+
# extend FriendlyId
|
26
|
+
# friendly_id :name
|
27
|
+
# end
|
28
|
+
attr_reader :base
|
29
|
+
|
30
|
+
# The model class that this configuration belongs to.
|
31
|
+
# @return ActiveRecord::Base
|
32
|
+
attr_reader :klass
|
33
|
+
|
34
|
+
# The configuration parameters for the {#klass model class} using FriendlyId.
|
35
|
+
# @return Hash
|
36
|
+
attr_reader :defaults
|
37
|
+
|
38
|
+
@@defaults = {
|
39
|
+
:reserved_words => ["new", "edit"]
|
11
40
|
}
|
12
41
|
|
42
|
+
# The default configuration parameters for models using FriendlyId.
|
43
|
+
# @return Hash
|
44
|
+
def self.defaults
|
45
|
+
@@defaults
|
46
|
+
end
|
47
|
+
|
13
48
|
def initialize(klass, values = nil)
|
14
49
|
@klass = klass
|
50
|
+
@defaults = self.class.defaults.dup
|
15
51
|
set values
|
16
52
|
end
|
17
53
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
54
|
+
def base=(base)
|
55
|
+
@base = base
|
56
|
+
if @base.respond_to?(:to_s)
|
57
|
+
@klass.validates_exclusion_of @base, :in => defaults[:reserved_words]
|
58
|
+
end
|
21
59
|
end
|
22
60
|
|
23
|
-
|
24
|
-
|
61
|
+
# Lets you specify the modules to use with FriendlyId.
|
62
|
+
#
|
63
|
+
# This method is invoked by {FriendlyId::Base#friendly_id friendly_id} when
|
64
|
+
# passing the +:use+ option, or when using {FriendlyId::Base#friendly_id
|
65
|
+
# friendly_id} with a block.
|
66
|
+
#
|
67
|
+
# @example
|
68
|
+
# class Book < ActiveRecord::Base
|
69
|
+
# extend FriendlyId
|
70
|
+
# friendly_id :name, :use => :slugged
|
71
|
+
# end
|
72
|
+
# @param [#to_s] *modules Arguments should be a symbols or strings that
|
73
|
+
# correspond with the name of a module inside the FriendlyId namespace. By
|
74
|
+
# default FriendlyId provides +:slugged+, +:history+ and +:scoped+.
|
75
|
+
def use(*modules)
|
76
|
+
modules.to_a.flatten.compact.map do |name|
|
77
|
+
klass.send :include, FriendlyId.const_get(name.to_s.classify)
|
78
|
+
end
|
25
79
|
end
|
26
80
|
|
81
|
+
# The column that FriendlyId will use to find the record when querying by
|
82
|
+
# friendly id.
|
83
|
+
#
|
84
|
+
# This method is generally only used internally by FriendlyId.
|
85
|
+
# @return String
|
27
86
|
def query_field
|
28
|
-
base
|
87
|
+
base.to_s
|
88
|
+
end
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def set(values)
|
93
|
+
values and values.each {|name, value| self.send "#{name}=", value}
|
29
94
|
end
|
30
95
|
end
|
31
96
|
end
|
@@ -5,10 +5,8 @@ module FriendlyId
|
|
5
5
|
protected
|
6
6
|
|
7
7
|
def find_one(id)
|
8
|
-
return super if !@klass.
|
8
|
+
return super if !@klass.respond_to?(:friendly_id) || id.unfriendly_id?
|
9
9
|
where(@klass.friendly_id_config.query_field => id).first or super
|
10
10
|
end
|
11
11
|
end
|
12
12
|
end
|
13
|
-
|
14
|
-
ActiveRecord::Relation.send :include, FriendlyId::FinderMethods
|
data/lib/friendly_id/history.rb
CHANGED
@@ -3,12 +3,14 @@ require "friendly_id/slug"
|
|
3
3
|
module FriendlyId
|
4
4
|
module History
|
5
5
|
|
6
|
-
def self.included(
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
def self.included(klass)
|
7
|
+
klass.instance_eval do
|
8
|
+
raise "FriendlyId::History is incompatibe with FriendlyId::Scoped" if self < Scoped
|
9
|
+
include Slugged unless self < Slugged
|
10
10
|
has_many :friendly_id_slugs, :as => :sluggable, :dependent => :destroy
|
11
11
|
before_save :build_friendly_id_slug, :if => lambda {|r| r.slug_sequencer.slug_changed?}
|
12
|
+
scope :with_friendly_id, lambda {|id| includes(:friendly_id_slugs).where("friendly_id_slugs.slug = ?", id)}
|
13
|
+
extend Finder
|
12
14
|
end
|
13
15
|
end
|
14
16
|
|
@@ -21,7 +23,7 @@ module FriendlyId
|
|
21
23
|
|
22
24
|
module Finder
|
23
25
|
def find_by_friendly_id(*args)
|
24
|
-
|
26
|
+
with_friendly_id(args.shift).first(*args)
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -6,10 +6,13 @@ module FriendlyId
|
|
6
6
|
|
7
7
|
# True is the id is definitely friendly, false if definitely unfriendly,
|
8
8
|
# else nil.
|
9
|
+
#
|
10
|
+
# An object is considired "definitely unfriendly" if its class is or
|
11
|
+
# inherits from Numeric, Symbol or ActiveRecord::Base.
|
9
12
|
def friendly_id?
|
10
|
-
if
|
13
|
+
if [Numeric, Symbol, ActiveRecord::Base].detect {|klass| self.class < klass}
|
11
14
|
false
|
12
|
-
elsif to_i.to_s != to_s
|
15
|
+
elsif respond_to?(:to_i) && to_i.to_s != to_s
|
13
16
|
true
|
14
17
|
end
|
15
18
|
end
|
data/lib/friendly_id/scoped.rb
CHANGED
@@ -12,43 +12,38 @@ module FriendlyId
|
|
12
12
|
# class Restaurant < ActiveRecord::Base
|
13
13
|
# belongs_to :city
|
14
14
|
# include FriendlyId::Scoped
|
15
|
-
#
|
15
|
+
# friendly_id :name, :scope => :city
|
16
16
|
# end
|
17
17
|
module Scoped
|
18
18
|
def self.included(klass)
|
19
|
-
klass.
|
19
|
+
klass.instance_eval do
|
20
|
+
raise "FriendlyId::Scoped is incompatibe with FriendlyId::History" if self < History
|
21
|
+
include Slugged unless self < Slugged
|
22
|
+
friendly_id_config.class.send :include, Configuration
|
23
|
+
friendly_id_config.slug_sequencer_class.send :include, SlugSequencer
|
24
|
+
end
|
20
25
|
end
|
21
|
-
end
|
22
|
-
|
23
|
-
class SlugSequencer
|
24
|
-
private
|
25
26
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
27
|
+
module Configuration
|
28
|
+
attr_accessor :scope
|
29
|
+
|
30
|
+
# Gets the scope column.
|
31
|
+
#
|
32
|
+
# Checks to see if the +:scope+ option passed to {#friendly_id}
|
33
|
+
# refers to a relation, and if so, returns the realtion's foreign key.
|
34
|
+
# Otherwise it assumes the option value was the name of column and returns
|
35
|
+
# it cast to a String.
|
36
|
+
# @return String The scope column
|
37
|
+
def scope_column
|
38
|
+
(klass.reflections[@scope].try(:association_foreign_key) || @scope).to_s
|
39
|
+
end
|
33
40
|
end
|
34
41
|
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
class Configuration
|
41
|
-
attr_accessor :scope
|
42
|
-
|
43
|
-
# Gets the scope column.
|
44
|
-
#
|
45
|
-
# Checks to see if the +:scope+ option passed to {#has_friendly_id}
|
46
|
-
# refers to a relation, and if so, returns the realtion's foreign key.
|
47
|
-
# Otherwise it assumes the option value was the name of column and returns
|
48
|
-
# it cast to a String.
|
49
|
-
# @return String The scope column
|
50
|
-
def scope_column
|
51
|
-
(klass.reflections[@scope].try(:association_foreign_key) || @scope).to_s
|
42
|
+
module SlugSequencer
|
43
|
+
def conflict
|
44
|
+
column = friendly_id_config.scope_column
|
45
|
+
conflicts.where("#{column} = ?", sluggable.send(column)).first
|
46
|
+
end
|
52
47
|
end
|
53
48
|
end
|
54
49
|
end
|
@@ -15,7 +15,7 @@ module FriendlyId
|
|
15
15
|
end
|
16
16
|
|
17
17
|
def generate
|
18
|
-
if
|
18
|
+
if new_record? or slug_changed?
|
19
19
|
conflict? ? self.next : normalized
|
20
20
|
else
|
21
21
|
sluggable.friendly_id
|
@@ -48,7 +48,6 @@ module FriendlyId
|
|
48
48
|
@conflict
|
49
49
|
end
|
50
50
|
|
51
|
-
# @NOTE AR-specific code here
|
52
51
|
def conflicts
|
53
52
|
pkey = sluggable.class.primary_key
|
54
53
|
value = sluggable.send pkey
|
data/lib/friendly_id/slugged.rb
CHANGED
@@ -5,19 +5,22 @@ module FriendlyId
|
|
5
5
|
# This module adds in-table slugs to an ActiveRecord model.
|
6
6
|
module Slugged
|
7
7
|
|
8
|
-
# @NOTE AR-specific code here
|
9
8
|
def self.included(klass)
|
10
|
-
klass.
|
11
|
-
|
9
|
+
klass.instance_eval do
|
10
|
+
friendly_id_config.class.send :include, Configuration
|
11
|
+
friendly_id_config.defaults[:slug_column] = 'slug'
|
12
|
+
friendly_id_config.defaults[:sequence_separator] = '--'
|
13
|
+
friendly_id_config.slug_sequencer_class = Class.new(SlugSequencer)
|
14
|
+
before_validation :set_slug
|
15
|
+
end
|
12
16
|
end
|
13
17
|
|
14
|
-
# @NOTE AS-specific code here
|
15
18
|
def normalize_friendly_id(value)
|
16
19
|
value.to_s.parameterize
|
17
20
|
end
|
18
21
|
|
19
22
|
def slug_sequencer
|
20
|
-
|
23
|
+
friendly_id_config.slug_sequencer_class.new(self)
|
21
24
|
end
|
22
25
|
|
23
26
|
private
|
@@ -25,27 +28,22 @@ module FriendlyId
|
|
25
28
|
def set_slug
|
26
29
|
send "#{friendly_id_config.slug_column}=", slug_sequencer.generate
|
27
30
|
end
|
28
|
-
end
|
29
|
-
|
30
|
-
class Configuration
|
31
|
-
attr :use_slugs
|
32
|
-
attr_writer :slug_column, :sequence_separator, :use_slugs
|
33
31
|
|
34
|
-
|
35
|
-
|
32
|
+
module Configuration
|
33
|
+
attr_writer :slug_column, :sequence_separator
|
34
|
+
attr_accessor :slug_sequencer_class
|
36
35
|
|
37
|
-
|
36
|
+
def query_field
|
37
|
+
slug_column
|
38
|
+
end
|
38
39
|
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def sequence_separator
|
44
|
-
@sequence_separator ||= DEFAULTS[:sequence_separator]
|
45
|
-
end
|
40
|
+
def sequence_separator
|
41
|
+
@sequence_separator or defaults[:sequence_separator]
|
42
|
+
end
|
46
43
|
|
47
|
-
|
48
|
-
|
44
|
+
def slug_column
|
45
|
+
@slug_column or defaults[:slug_column]
|
46
|
+
end
|
49
47
|
end
|
50
48
|
end
|
51
49
|
end
|
data/lib/friendly_id/version.rb
CHANGED
data/lib/friendly_id.rb
CHANGED
@@ -6,9 +6,34 @@ require "friendly_id/finder_methods"
|
|
6
6
|
|
7
7
|
# FriendlyId is a comprehensive Ruby library for ActiveRecord permalinks and
|
8
8
|
# slugs.
|
9
|
+
#
|
9
10
|
# @author Norman Clarke
|
10
11
|
module FriendlyId
|
11
12
|
autoload :Slugged, "friendly_id/slugged"
|
12
13
|
autoload :Scoped, "friendly_id/scoped"
|
13
14
|
autoload :History, "friendly_id/history"
|
15
|
+
|
16
|
+
# FriendlyId takes advantage of `extended` to do basic model setup, primarily
|
17
|
+
# extending FriendlyId::Base to add #friendly_id as a class method for
|
18
|
+
# configuring how a model is going to use FriendlyId. In previous versions of
|
19
|
+
# this library, ActiveRecord::Base was patched by default to include methods
|
20
|
+
# needed to configure friendly_id, but this version tries to be a little less
|
21
|
+
# invasive.
|
22
|
+
#
|
23
|
+
# In addition to adding the #friendly_id method, the class instance variable
|
24
|
+
# +@friendly_id_config+ is added. This variable is an instance of an anonymous
|
25
|
+
# subclass of FriendlyId::Configuration. This is done to allow for
|
26
|
+
# subsequently loaded modules like FriendlyId::Slugged to add functionality to
|
27
|
+
# the configuration only for the current class, and thereby isolating other
|
28
|
+
# classes from large feature changes a module could potentially introduce. The
|
29
|
+
# upshot of this is, you can have two Active Record models that both have a
|
30
|
+
# @friendly_id_config, but each config object can have different methods and
|
31
|
+
# behaviors depending on what modules have been loaded, without conflicts.
|
32
|
+
def self.extended(base)
|
33
|
+
base.instance_eval do
|
34
|
+
extend FriendlyId::Base
|
35
|
+
@friendly_id_config = Class.new(FriendlyId::Configuration).new(base)
|
36
|
+
end
|
37
|
+
ActiveRecord::Relation.send :include, FriendlyId::FinderMethods
|
38
|
+
end
|
14
39
|
end
|
data/test/base_test.rb
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
require File.expand_path("../helper.rb", __FILE__)
|
2
|
+
|
3
|
+
class CoreTest < MiniTest::Unit::TestCase
|
4
|
+
include FriendlyId::Test
|
5
|
+
|
6
|
+
test "friendly_id should accept a base and a hash" do
|
7
|
+
klass = Class.new(ActiveRecord::Base) do
|
8
|
+
extend FriendlyId
|
9
|
+
friendly_id :foo, :use => :slugged, :slug_column => :bar
|
10
|
+
end
|
11
|
+
assert klass < FriendlyId::Slugged
|
12
|
+
assert_equal :foo, klass.friendly_id_config.base
|
13
|
+
assert_equal :bar, klass.friendly_id_config.slug_column
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
test "friendly_id should accept a block" do
|
18
|
+
klass = Class.new(ActiveRecord::Base) do
|
19
|
+
extend FriendlyId
|
20
|
+
friendly_id do |config|
|
21
|
+
config.use :slugged
|
22
|
+
config.base = :foo
|
23
|
+
config.slug_column = :bar
|
24
|
+
end
|
25
|
+
end
|
26
|
+
assert klass < FriendlyId::Slugged
|
27
|
+
assert_equal :foo, klass.friendly_id_config.base
|
28
|
+
assert_equal :bar, klass.friendly_id_config.slug_column
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require File.expand_path("../helper", __FILE__)
|
2
|
+
|
3
|
+
class ConfigurationTest < MiniTest::Unit::TestCase
|
4
|
+
|
5
|
+
include FriendlyId::Test
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@klass = Class.new(ActiveRecord::Base)
|
9
|
+
end
|
10
|
+
|
11
|
+
test "should set klass on initialization" do
|
12
|
+
config = FriendlyId::Configuration.new @klass
|
13
|
+
assert_equal @klass, config.klass
|
14
|
+
end
|
15
|
+
|
16
|
+
test "should set options on initialization if present" do
|
17
|
+
config = FriendlyId::Configuration.new @klass, :base => "hello"
|
18
|
+
assert_equal "hello", config.base
|
19
|
+
end
|
20
|
+
|
21
|
+
test "should raise error if passed unrecognized option" do
|
22
|
+
assert_raises NoMethodError do
|
23
|
+
FriendlyId::Configuration.new @klass, :foo => "bar"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
end
|
data/test/core_test.rb
CHANGED
@@ -2,7 +2,8 @@ require File.expand_path("../helper.rb", __FILE__)
|
|
2
2
|
|
3
3
|
Author, Book = 2.times.map do
|
4
4
|
Class.new(ActiveRecord::Base) do
|
5
|
-
|
5
|
+
extend FriendlyId
|
6
|
+
friendly_id :name
|
6
7
|
end
|
7
8
|
end
|
8
9
|
|
@@ -16,17 +17,11 @@ class CoreTest < MiniTest::Unit::TestCase
|
|
16
17
|
end
|
17
18
|
|
18
19
|
test "models don't use friendly_id by default" do
|
19
|
-
assert !Class.new(ActiveRecord::Base).
|
20
|
+
assert !Class.new(ActiveRecord::Base).respond_to?(:friendly_id)
|
20
21
|
end
|
21
22
|
|
22
23
|
test "model classes should have a friendly id config" do
|
23
|
-
assert klass.
|
24
|
-
end
|
25
|
-
|
26
|
-
test "should raise error when bad config options are set" do
|
27
|
-
assert_raises ArgumentError do
|
28
|
-
klass.has_friendly_id :name, :garbage => :in
|
29
|
-
end
|
24
|
+
assert klass.friendly_id(:name).friendly_id_config
|
30
25
|
end
|
31
26
|
|
32
27
|
test "should reserve 'new' and 'edit' by default" do
|
data/test/helper.rb
CHANGED
@@ -7,10 +7,14 @@ require "bundler/setup"
|
|
7
7
|
require "mocha"
|
8
8
|
require "minitest/unit"
|
9
9
|
require "active_record"
|
10
|
+
# require "active_support/core_ext/class"
|
10
11
|
|
11
12
|
if ENV["COVERAGE"]
|
12
13
|
require 'simplecov'
|
13
|
-
SimpleCov.start
|
14
|
+
SimpleCov.start do
|
15
|
+
add_filter "test/"
|
16
|
+
add_filter "friendly_id/migration"
|
17
|
+
end
|
14
18
|
end
|
15
19
|
|
16
20
|
require "friendly_id"
|
@@ -77,7 +81,7 @@ end
|
|
77
81
|
|
78
82
|
class Module
|
79
83
|
def test(name, &block)
|
80
|
-
define_method("test_#{name.gsub(/[^a-z0-9]/i, "_")}".to_sym, &block)
|
84
|
+
define_method("test_#{name.gsub(/[^a-z0-9']/i, "_")}".to_sym, &block)
|
81
85
|
end
|
82
86
|
end
|
83
87
|
|
data/test/history_test.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
require File.expand_path("../helper.rb", __FILE__)
|
2
2
|
|
3
3
|
class Manual < ActiveRecord::Base
|
4
|
-
|
5
|
-
|
4
|
+
extend FriendlyId
|
5
|
+
friendly_id :name, :use => :history
|
6
6
|
end
|
7
7
|
|
8
8
|
class HistoryTest < MiniTest::Unit::TestCase
|
@@ -43,4 +43,13 @@ class HistoryTest < MiniTest::Unit::TestCase
|
|
43
43
|
assert !found.readonly?
|
44
44
|
end
|
45
45
|
end
|
46
|
+
|
47
|
+
test "should raise error if used with scoped" do
|
48
|
+
klass = Class.new(ActiveRecord::Base)
|
49
|
+
klass.extend FriendlyId
|
50
|
+
assert_raises RuntimeError do
|
51
|
+
klass.friendly_id :name, :use => [:history, :scoped]
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
46
55
|
end
|
data/test/scoped_test.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
require File.expand_path("../helper", __FILE__)
|
2
2
|
|
3
3
|
class Novelist < ActiveRecord::Base
|
4
|
-
|
5
|
-
|
4
|
+
extend FriendlyId
|
5
|
+
friendly_id :name, :use => :slugged
|
6
6
|
end
|
7
7
|
|
8
8
|
class Novel < ActiveRecord::Base
|
9
|
-
|
9
|
+
extend FriendlyId
|
10
10
|
belongs_to :novelist
|
11
|
-
|
11
|
+
friendly_id :name, :use => :scoped, :scope => :novelist
|
12
12
|
end
|
13
13
|
|
14
14
|
class ScopedTest < MiniTest::Unit::TestCase
|
@@ -26,7 +26,8 @@ class ScopedTest < MiniTest::Unit::TestCase
|
|
26
26
|
|
27
27
|
test "should detect scope column from explicit column name" do
|
28
28
|
klass = Class.new(ActiveRecord::Base)
|
29
|
-
klass.
|
29
|
+
klass.extend FriendlyId
|
30
|
+
klass.friendly_id :empty, :use => :scoped, :scope => :dummy
|
30
31
|
assert_equal "dummy", klass.friendly_id_config.scope_column
|
31
32
|
end
|
32
33
|
|
@@ -46,4 +47,11 @@ class ScopedTest < MiniTest::Unit::TestCase
|
|
46
47
|
end
|
47
48
|
end
|
48
49
|
|
50
|
+
test "should raise error if used with history" do
|
51
|
+
klass = Class.new(ActiveRecord::Base)
|
52
|
+
klass.extend FriendlyId
|
53
|
+
assert_raises RuntimeError do
|
54
|
+
klass.friendly_id :name, :use => [:scoped, :history]
|
55
|
+
end
|
56
|
+
end
|
49
57
|
end
|
data/test/slugged_test.rb
CHANGED
@@ -2,8 +2,8 @@ require File.expand_path("../helper.rb", __FILE__)
|
|
2
2
|
|
3
3
|
Journalist, Article = 2.times.map do
|
4
4
|
Class.new(ActiveRecord::Base) do
|
5
|
-
|
6
|
-
|
5
|
+
extend FriendlyId
|
6
|
+
friendly_id :name, :use => :slugged
|
7
7
|
end
|
8
8
|
end
|
9
9
|
|
@@ -53,8 +53,8 @@ class SlugSequencerTest < MiniTest::Unit::TestCase
|
|
53
53
|
test "should quote column names" do
|
54
54
|
klass = Class.new(ActiveRecord::Base)
|
55
55
|
klass.table_name = "journalists"
|
56
|
-
klass.
|
57
|
-
klass.
|
56
|
+
klass.extend FriendlyId
|
57
|
+
klass.friendly_id :name, :use => :slugged, :slug_column => "strange name"
|
58
58
|
begin
|
59
59
|
with_instance_of(klass) {|record| assert klass.find(record.friendly_id)}
|
60
60
|
rescue ActiveRecord::StatementInvalid
|
@@ -68,8 +68,8 @@ class SlugSeparatorTest < MiniTest::Unit::TestCase
|
|
68
68
|
include FriendlyId::Test
|
69
69
|
|
70
70
|
class Journalist < ActiveRecord::Base
|
71
|
-
|
72
|
-
|
71
|
+
extend FriendlyId
|
72
|
+
friendly_id :name, :use => :slugged, :sequence_separator => ":"
|
73
73
|
end
|
74
74
|
|
75
75
|
def klass
|
metadata
CHANGED
@@ -1,104 +1,104 @@
|
|
1
|
-
--- !ruby/object:Gem::Specification
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
2
|
name: friendly_id4
|
3
|
-
version: !ruby/object:Gem::Version
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 4.0.0.beta3
|
4
5
|
prerelease: 6
|
5
|
-
version: 4.0.0.beta1
|
6
6
|
platform: ruby
|
7
|
-
authors:
|
7
|
+
authors:
|
8
8
|
- Norman Clarke
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
|
13
|
-
|
14
|
-
dependencies:
|
15
|
-
- !ruby/object:Gem::Dependency
|
12
|
+
date: 2011-07-26 00:00:00.000000000 -03:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
17
|
-
|
18
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
17
|
+
requirement: &70311865559640 !ruby/object:Gem::Requirement
|
19
18
|
none: false
|
20
|
-
requirements:
|
19
|
+
requirements:
|
21
20
|
- - ~>
|
22
|
-
- !ruby/object:Gem::Version
|
23
|
-
version:
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '3.0'
|
24
23
|
type: :development
|
25
|
-
version_requirements: *id001
|
26
|
-
- !ruby/object:Gem::Dependency
|
27
|
-
name: sqlite3
|
28
24
|
prerelease: false
|
29
|
-
|
25
|
+
version_requirements: *70311865559640
|
26
|
+
- !ruby/object:Gem::Dependency
|
27
|
+
name: sqlite3
|
28
|
+
requirement: &70311865558600 !ruby/object:Gem::Requirement
|
30
29
|
none: false
|
31
|
-
requirements:
|
30
|
+
requirements:
|
32
31
|
- - ~>
|
33
|
-
- !ruby/object:Gem::Version
|
34
|
-
version:
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.3'
|
35
34
|
type: :development
|
36
|
-
version_requirements: *id002
|
37
|
-
- !ruby/object:Gem::Dependency
|
38
|
-
name: cutest
|
39
35
|
prerelease: false
|
40
|
-
|
36
|
+
version_requirements: *70311865558600
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: cutest
|
39
|
+
requirement: &70311865558040 !ruby/object:Gem::Requirement
|
41
40
|
none: false
|
42
|
-
requirements:
|
41
|
+
requirements:
|
43
42
|
- - ~>
|
44
|
-
- !ruby/object:Gem::Version
|
43
|
+
- !ruby/object:Gem::Version
|
45
44
|
version: 1.1.2
|
46
45
|
type: :development
|
47
|
-
version_requirements: *id003
|
48
|
-
- !ruby/object:Gem::Dependency
|
49
|
-
name: ffaker
|
50
46
|
prerelease: false
|
51
|
-
|
47
|
+
version_requirements: *70311865558040
|
48
|
+
- !ruby/object:Gem::Dependency
|
49
|
+
name: ffaker
|
50
|
+
requirement: &70311865557340 !ruby/object:Gem::Requirement
|
52
51
|
none: false
|
53
|
-
requirements:
|
54
|
-
- -
|
55
|
-
- !ruby/object:Gem::Version
|
56
|
-
version:
|
52
|
+
requirements:
|
53
|
+
- - ! '>='
|
54
|
+
- !ruby/object:Gem::Version
|
55
|
+
version: '0'
|
57
56
|
type: :development
|
58
|
-
version_requirements: *id004
|
59
|
-
- !ruby/object:Gem::Dependency
|
60
|
-
name: maruku
|
61
57
|
prerelease: false
|
62
|
-
|
58
|
+
version_requirements: *70311865557340
|
59
|
+
- !ruby/object:Gem::Dependency
|
60
|
+
name: maruku
|
61
|
+
requirement: &70311865556780 !ruby/object:Gem::Requirement
|
63
62
|
none: false
|
64
|
-
requirements:
|
65
|
-
- -
|
66
|
-
- !ruby/object:Gem::Version
|
67
|
-
version:
|
63
|
+
requirements:
|
64
|
+
- - ! '>='
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: '0'
|
68
67
|
type: :development
|
69
|
-
version_requirements: *id005
|
70
|
-
- !ruby/object:Gem::Dependency
|
71
|
-
name: yard
|
72
68
|
prerelease: false
|
73
|
-
|
69
|
+
version_requirements: *70311865556780
|
70
|
+
- !ruby/object:Gem::Dependency
|
71
|
+
name: yard
|
72
|
+
requirement: &70311865556100 !ruby/object:Gem::Requirement
|
74
73
|
none: false
|
75
|
-
requirements:
|
76
|
-
- -
|
77
|
-
- !ruby/object:Gem::Version
|
78
|
-
version:
|
74
|
+
requirements:
|
75
|
+
- - ! '>='
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: '0'
|
79
78
|
type: :development
|
80
|
-
version_requirements: *id006
|
81
|
-
- !ruby/object:Gem::Dependency
|
82
|
-
name: mocha
|
83
79
|
prerelease: false
|
84
|
-
|
80
|
+
version_requirements: *70311865556100
|
81
|
+
- !ruby/object:Gem::Dependency
|
82
|
+
name: mocha
|
83
|
+
requirement: &70311865555640 !ruby/object:Gem::Requirement
|
85
84
|
none: false
|
86
|
-
requirements:
|
87
|
-
- -
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version:
|
85
|
+
requirements:
|
86
|
+
- - ! '>='
|
87
|
+
- !ruby/object:Gem::Version
|
88
|
+
version: '0'
|
90
89
|
type: :development
|
91
|
-
|
92
|
-
|
93
|
-
|
90
|
+
prerelease: false
|
91
|
+
version_requirements: *70311865555640
|
92
|
+
description: ! " FriendlyId is the \"Swiss Army bulldozer\" of slugging and permalink
|
93
|
+
plugins\n for Ruby on Rails. It allows you to create pretty URL's and work with\n
|
94
|
+
\ human-friendly strings as if they were numeric ids for ActiveRecord models.\n"
|
95
|
+
email:
|
94
96
|
- norman@njclarke.com
|
95
97
|
executables: []
|
96
|
-
|
97
98
|
extensions: []
|
98
|
-
|
99
99
|
extra_rdoc_files: []
|
100
|
-
|
101
|
-
|
100
|
+
files:
|
101
|
+
- .gemtest
|
102
102
|
- .gitignore
|
103
103
|
- Gemfile
|
104
104
|
- Guide.md
|
@@ -121,9 +121,11 @@ files:
|
|
121
121
|
- lib/friendly_id/slugged.rb
|
122
122
|
- lib/friendly_id/version.rb
|
123
123
|
- lib/generators/friendly_id_generator.rb
|
124
|
+
- test/base_test.rb
|
124
125
|
- test/config/mysql.yml
|
125
126
|
- test/config/postgres.yml
|
126
127
|
- test/config/sqlite3.yml
|
128
|
+
- test/configuration_test.rb
|
127
129
|
- test/core_test.rb
|
128
130
|
- test/helper.rb
|
129
131
|
- test/history_test.rb
|
@@ -132,32 +134,29 @@ files:
|
|
132
134
|
- test/scoped_test.rb
|
133
135
|
- test/shared.rb
|
134
136
|
- test/slugged_test.rb
|
137
|
+
has_rdoc: true
|
135
138
|
homepage: http://norman.github.com/friendly_id
|
136
139
|
licenses: []
|
137
|
-
|
138
140
|
post_install_message:
|
139
141
|
rdoc_options: []
|
140
|
-
|
141
|
-
require_paths:
|
142
|
+
require_paths:
|
142
143
|
- lib
|
143
|
-
required_ruby_version: !ruby/object:Gem::Requirement
|
144
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
144
145
|
none: false
|
145
|
-
requirements:
|
146
|
-
- -
|
147
|
-
- !ruby/object:Gem::Version
|
148
|
-
version:
|
149
|
-
required_rubygems_version: !ruby/object:Gem::Requirement
|
146
|
+
requirements:
|
147
|
+
- - ! '>='
|
148
|
+
- !ruby/object:Gem::Version
|
149
|
+
version: '0'
|
150
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
150
151
|
none: false
|
151
|
-
requirements:
|
152
|
-
- -
|
153
|
-
- !ruby/object:Gem::Version
|
152
|
+
requirements:
|
153
|
+
- - ! '>'
|
154
|
+
- !ruby/object:Gem::Version
|
154
155
|
version: 1.3.1
|
155
156
|
requirements: []
|
156
|
-
|
157
157
|
rubyforge_project: friendly_id
|
158
|
-
rubygems_version: 1.
|
158
|
+
rubygems_version: 1.6.2
|
159
159
|
signing_key:
|
160
160
|
specification_version: 3
|
161
161
|
summary: A comprehensive slugging and pretty-URL plugin.
|
162
162
|
test_files: []
|
163
|
-
|