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