simple_slug 0.3.3 → 0.4.2
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.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.travis.yml +1 -1
- data/Gemfile +2 -0
- data/README.md +8 -1
- data/db/migrate/20140113000001_create_simple_slug_history_slug.rb +6 -5
- data/lib/simple_slug.rb +13 -11
- data/lib/simple_slug/adapter.rb +123 -0
- data/lib/simple_slug/history_slug.rb +1 -0
- data/lib/simple_slug/model_addition.rb +24 -110
- data/lib/simple_slug/railtie.rb +0 -2
- data/lib/simple_slug/version.rb +1 -1
- data/simple_slug.gemspec +4 -4
- data/spec/simple_slug/base_spec.rb +5 -9
- data/spec/simple_slug/history_spec.rb +59 -34
- data/spec/simple_slug/model_addition_spec.rb +124 -82
- data/spec/spec_helper.rb +33 -36
- metadata +28 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 1a485f4e0407ecb15b0b0a93a58f1cb61a49e7d41e595f4491b26dcc50f12dbd
|
4
|
+
data.tar.gz: f35ff289be593ab1d830d2f0e3d507a616d1d559786698260030cdda4e0c5f36
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 628e2c7fa28d567ed80e809013546c567924125b5c2e8e5e01bd80fabd2d5c27c90076b4673faafb029055d93a76b02e743d9ae650f51920b3b73b85f5caaef2
|
7
|
+
data.tar.gz: 63554fd5ca7d1fdb18054c775b5ee15379c258d1435c5cfeac07bb184995b5c313188d654ba4f4f0e72ecfc0cdc6ba4cc4c0eea832317eafcc989b6e9ab86664
|
data/.gitignore
CHANGED
data/.travis.yml
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# SimpleSlug
|
2
2
|
|
3
3
|
[](https://travis-ci.org/leschenko/simple_slug)
|
4
|
-
[](https://gemnasium.com/leschenko/simple_slug)
|
5
4
|
|
6
5
|
Simple friendly url generator for ActiveRecord models with history.
|
7
6
|
|
@@ -37,6 +36,14 @@ class User < ActiveRecord::Base
|
|
37
36
|
end
|
38
37
|
```
|
39
38
|
|
39
|
+
Add localization with `slug_YOUR_LOCALE` like columns:
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
class User < ActiveRecord::Base
|
43
|
+
simple_slug :full_name, locales: [nil, :it]
|
44
|
+
end
|
45
|
+
```
|
46
|
+
|
40
47
|
If you want to control when slug is generated, define `should_generate_new_slug?` method:
|
41
48
|
|
42
49
|
```ruby
|
@@ -1,13 +1,14 @@
|
|
1
1
|
class CreateSimpleSlugHistorySlug < ActiveRecord::Migration
|
2
2
|
def change
|
3
|
-
create_table :
|
4
|
-
t.string :slug, null: false
|
3
|
+
create_table :simple_slug_history_slugs do |t|
|
4
|
+
t.string :slug, null: false, limit: 191
|
5
|
+
t.string :locale, limit: 10
|
5
6
|
t.integer :sluggable_id, null: false
|
6
7
|
t.string :sluggable_type, limit: 50, null: false
|
7
|
-
t.
|
8
|
+
t.timestamps
|
8
9
|
end
|
9
10
|
|
10
|
-
add_index :
|
11
|
-
add_index :
|
11
|
+
add_index :simple_slug_history_slugs, :slug
|
12
|
+
add_index :simple_slug_history_slugs, [:sluggable_type, :sluggable_id], name: 'simple_slug_history_slugs_on_sluggable_type_and_sluggable_id'
|
12
13
|
end
|
13
14
|
end
|
data/lib/simple_slug.rb
CHANGED
@@ -4,34 +4,36 @@ require 'simple_slug/model_addition'
|
|
4
4
|
require 'simple_slug/railtie' if Object.const_defined?(:Rails)
|
5
5
|
|
6
6
|
module SimpleSlug
|
7
|
+
autoload :Adapter, 'simple_slug/adapter'
|
8
|
+
autoload :ModelAddition, 'simple_slug/model_addition'
|
7
9
|
autoload :HistorySlug, 'simple_slug/history_slug'
|
8
10
|
|
9
11
|
mattr_accessor :excludes
|
10
|
-
@@excludes = %w(new edit show index session login logout sign_in sign_out users admin stylesheets
|
12
|
+
@@excludes = %w(new edit show index session login logout sign_in sign_out users admin stylesheets javascripts images fonts assets)
|
11
13
|
|
12
|
-
mattr_accessor :
|
13
|
-
@@
|
14
|
+
mattr_accessor :slug_regexp
|
15
|
+
@@slug_regexp = /\A(?:\w+[\w\d\-_]*|--\d+)\z/
|
14
16
|
|
15
17
|
mattr_accessor :slug_column
|
16
18
|
@@slug_column = 'slug'
|
17
19
|
|
20
|
+
mattr_accessor :min_length
|
21
|
+
@@min_length = 3
|
22
|
+
|
18
23
|
mattr_accessor :max_length
|
19
|
-
@@max_length =
|
24
|
+
@@max_length = 191
|
20
25
|
|
21
26
|
mattr_accessor :callback_type
|
22
27
|
@@callback_type = :before_validation
|
23
28
|
|
24
|
-
mattr_accessor :
|
25
|
-
@@
|
29
|
+
mattr_accessor :validation
|
30
|
+
@@validation = true
|
26
31
|
|
27
32
|
STARTS_WITH_NUMBER_REGEXP =/\A\d+/
|
28
|
-
|
33
|
+
NUMBER_REGEXP =/\A\d+\z/
|
34
|
+
RESOLVE_SUFFIX_REGEXP = /--\d+\z/
|
29
35
|
|
30
36
|
def self.setup
|
31
37
|
yield self
|
32
38
|
end
|
33
|
-
|
34
|
-
def self.normalize_cyrillic(base)
|
35
|
-
base.tr('АаВЕеіКкМНОоРрСсТуХх', 'AaBEeiKkMHOoPpCcTyXx')
|
36
|
-
end
|
37
39
|
end
|
@@ -0,0 +1,123 @@
|
|
1
|
+
module SimpleSlug
|
2
|
+
class Adapter
|
3
|
+
attr_reader :model, :options, :locales
|
4
|
+
attr_accessor :current_locale
|
5
|
+
|
6
|
+
def initialize(model)
|
7
|
+
@model = model
|
8
|
+
@options = model.simple_slug_options
|
9
|
+
@locales = Array(@options[:locales] || [nil])
|
10
|
+
end
|
11
|
+
|
12
|
+
def finder_method
|
13
|
+
options[:history] ? :find_by : :find_by!
|
14
|
+
end
|
15
|
+
|
16
|
+
def valid_locale?(locale)
|
17
|
+
locales.include?(locale)
|
18
|
+
end
|
19
|
+
|
20
|
+
def current_locale
|
21
|
+
valid_locale?(I18n.locale) ? I18n.locale : nil
|
22
|
+
end
|
23
|
+
|
24
|
+
def column_names
|
25
|
+
locales.map{|l| column_name(l) }
|
26
|
+
end
|
27
|
+
|
28
|
+
def column_name(locale=I18n.locale)
|
29
|
+
[options[:slug_column], (locale if valid_locale?(locale))].compact.join('_')
|
30
|
+
end
|
31
|
+
|
32
|
+
def get(record)
|
33
|
+
record.send(column_name)
|
34
|
+
end
|
35
|
+
|
36
|
+
def get_prev(record)
|
37
|
+
record.send("#{column_name}_was")
|
38
|
+
end
|
39
|
+
|
40
|
+
def set(record, value)
|
41
|
+
record.send("#{column_name}=", value)
|
42
|
+
end
|
43
|
+
|
44
|
+
def each_locale
|
45
|
+
locales.each do |l|
|
46
|
+
with_locale(l || I18n.default_locale) { yield }
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def reset(record)
|
51
|
+
each_locale{ set record, get_prev(record) }
|
52
|
+
end
|
53
|
+
|
54
|
+
def save_history(record)
|
55
|
+
each_locale do
|
56
|
+
slug_was = record.saved_change_to_attribute(column_name).try!(:first)
|
57
|
+
next if slug_was.blank?
|
58
|
+
::SimpleSlug::HistorySlug.where(sluggable_type: record.class.name, slug: slug_was, locale: current_locale).first_or_initialize.update(sluggable_id: record.id)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
def generate(record, force: false)
|
63
|
+
each_locale do
|
64
|
+
next unless force || record.should_generate_new_slug?
|
65
|
+
simple_slug = normalize(slug_base(record))
|
66
|
+
simple_slug = "__#{record.id || rand(9999)}" if simple_slug.blank? && options[:fallback_on_blank]
|
67
|
+
return if simple_slug == get(record).to_s.sub(SimpleSlug::RESOLVE_SUFFIX_REGEXP, '')
|
68
|
+
set(record, resolve(record, simple_slug))
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
def normalize(base)
|
73
|
+
parameterize_args = ActiveSupport::VERSION::MAJOR > 4 ? {separator: '-'} : '-'
|
74
|
+
normalized = I18n.transliterate(base).parameterize(**parameterize_args).downcase
|
75
|
+
normalized = "_#{normalized}" if normalized =~ SimpleSlug::STARTS_WITH_NUMBER_REGEXP
|
76
|
+
normalized = normalized[0..options[:max_length].pred] if options[:max_length]
|
77
|
+
normalized
|
78
|
+
end
|
79
|
+
|
80
|
+
def add_suffix(slug_value)
|
81
|
+
"#{slug_value}--#{rand(99999)}"
|
82
|
+
end
|
83
|
+
|
84
|
+
def slug_base(record)
|
85
|
+
options[:slug_method].map{|m| record.send(m).to_s }.reject(&:blank?).join(' ')
|
86
|
+
end
|
87
|
+
|
88
|
+
def resolve(record, slug_value)
|
89
|
+
return slug_value unless slug_exists?(record, slug_value)
|
90
|
+
loop do
|
91
|
+
slug_with_suffix = add_suffix(slug_value)
|
92
|
+
break slug_with_suffix unless slug_exists?(record, slug_with_suffix)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def slug_exists?(record, slug_value)
|
97
|
+
model_slug_exists?(record, slug_value) || history_slug_exists?(record, slug_value)
|
98
|
+
end
|
99
|
+
|
100
|
+
def model_slug_exists?(record, slug_value)
|
101
|
+
base_scope = record.class.unscoped.where(column_name => slug_value)
|
102
|
+
base_scope = base_scope.where('id != ?', record.id) if record.persisted?
|
103
|
+
base_scope.exists?
|
104
|
+
end
|
105
|
+
|
106
|
+
def history_slug_exists?(record, slug_value)
|
107
|
+
return false unless options[:history]
|
108
|
+
base_scope = SimpleSlug::HistorySlug.where(sluggable_type: record.class.name, slug: slug_value)
|
109
|
+
base_scope = base_scope.where('sluggable_id != ?', record.id) if record.persisted?
|
110
|
+
base_scope.exists?
|
111
|
+
end
|
112
|
+
|
113
|
+
def with_locale(locale)
|
114
|
+
if defined? Globalize
|
115
|
+
Globalize.with_locale(locale) do
|
116
|
+
I18n.with_locale(locale) { yield }
|
117
|
+
end
|
118
|
+
else
|
119
|
+
I18n.with_locale(locale) { yield }
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
@@ -6,30 +6,35 @@ module SimpleSlug
|
|
6
6
|
|
7
7
|
module SingletonMethods
|
8
8
|
def simple_slug(*args)
|
9
|
-
class_attribute :simple_slug_options, instance_writer: false
|
9
|
+
class_attribute :simple_slug_options, :simple_slug_adapter, instance_writer: false
|
10
10
|
options = args.extract_options!
|
11
11
|
self.simple_slug_options = options.reverse_merge(
|
12
12
|
slug_column: SimpleSlug.slug_column,
|
13
13
|
slug_method: args,
|
14
|
+
slug_regexp: SimpleSlug.slug_regexp,
|
15
|
+
min_length: SimpleSlug.min_length,
|
14
16
|
max_length: SimpleSlug.max_length,
|
15
17
|
callback_type: SimpleSlug.callback_type,
|
16
|
-
|
18
|
+
validation: SimpleSlug.validation
|
17
19
|
)
|
20
|
+
self.simple_slug_adapter = SimpleSlug::Adapter.new(self)
|
18
21
|
|
19
22
|
include InstanceMethods
|
20
23
|
extend ClassMethods
|
21
24
|
|
22
25
|
send(simple_slug_options[:callback_type], :simple_slug_generate, if: :should_generate_new_slug?) if simple_slug_options[:callback_type]
|
23
26
|
|
24
|
-
if simple_slug_options[:
|
25
|
-
validates
|
27
|
+
if simple_slug_options[:validation]
|
28
|
+
validates *simple_slug_adapter.column_names,
|
26
29
|
presence: true,
|
30
|
+
uniqueness: {case_sensitive: true},
|
27
31
|
exclusion: {in: SimpleSlug.excludes},
|
28
|
-
format: {
|
32
|
+
format: {with: simple_slug_options[:slug_regexp]},
|
33
|
+
length: {minimum: simple_slug_options[:min_length], maximum: simple_slug_options[:max_length]}.reject{|_, v| v.blank? }
|
29
34
|
end
|
30
35
|
|
31
36
|
if simple_slug_options[:history]
|
32
|
-
after_save :
|
37
|
+
after_save :simple_slug_reset, :simple_slug_save_history
|
33
38
|
after_destroy :simple_slug_cleanup_history
|
34
39
|
include InstanceHistoryMethods
|
35
40
|
end
|
@@ -39,137 +44,46 @@ module SimpleSlug
|
|
39
44
|
module ClassMethods
|
40
45
|
def simple_slug_find(id_param)
|
41
46
|
return unless id_param
|
42
|
-
if id_param.is_a?(Integer) || id_param =~
|
47
|
+
if id_param.is_a?(Integer) || id_param =~ SimpleSlug::NUMBER_REGEXP
|
43
48
|
find(id_param)
|
44
49
|
else
|
45
|
-
finder_method
|
46
|
-
send(finder_method, simple_slug_options[:slug_column] => id_param) or find(::SimpleSlug::HistorySlug.find_by!(slug: id_param).sluggable_id)
|
50
|
+
send(simple_slug_adapter.finder_method, simple_slug_adapter.column_name => id_param) or simple_slug_history_find(id_param)
|
47
51
|
end
|
48
52
|
end
|
49
53
|
|
54
|
+
def simple_slug_history_find(slug, locale=I18n.locale)
|
55
|
+
find(SimpleSlug::HistorySlug.find_by!(locale: (locale if simple_slug_adapter.valid_locale?(locale)), slug: slug).sluggable_id)
|
56
|
+
end
|
57
|
+
|
50
58
|
alias_method :friendly_find, :simple_slug_find
|
51
59
|
end
|
52
60
|
|
53
61
|
module InstanceMethods
|
54
62
|
def to_param
|
55
|
-
|
63
|
+
simple_slug_adapter.get_prev(self).presence || super
|
56
64
|
end
|
57
65
|
|
58
66
|
def should_generate_new_slug?
|
59
|
-
|
60
|
-
return simple_slug_get.blank? unless simple_slug_options[:locales]
|
61
|
-
simple_slug_options[:locales].any? { |locale| simple_slug_get(locale).blank? }
|
67
|
+
simple_slug_adapter.column_names.any?{|cn| send(cn).blank? }
|
62
68
|
end
|
63
69
|
|
64
70
|
def simple_slug_generate(force=false)
|
65
|
-
(
|
66
|
-
simple_slug_generate_for_locale(locale, force)
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
def simple_slug_generate_for_locale(locale=nil, force=false)
|
71
|
-
simple_slug_with_locale(locale) do
|
72
|
-
simple_slug = simple_slug_normalize(simple_slug_base)
|
73
|
-
simple_slug = simple_slug.first(simple_slug_options[:max_length]) if simple_slug_options[:max_length]
|
74
|
-
return if !force && simple_slug == simple_slug_get(locale).to_s.sub(/--\d+\z/, '')
|
75
|
-
resolved_simple_slug = simple_slug_resolve(simple_slug, locale)
|
76
|
-
simple_slug_set(resolved_simple_slug, locale)
|
77
|
-
end
|
78
|
-
end
|
79
|
-
|
80
|
-
def simple_slug_with_locale(locale)
|
81
|
-
if defined? Globalize
|
82
|
-
Globalize.with_locale(locale) do
|
83
|
-
I18n.with_locale(locale) { yield }
|
84
|
-
end
|
85
|
-
else
|
86
|
-
I18n.with_locale(locale) { yield }
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
def simple_slug_generate_(force=false, locale=nil)
|
91
|
-
simple_slug = simple_slug_normalize(simple_slug_base)
|
92
|
-
simple_slug = simple_slug.first(simple_slug_options[:max_length]) if simple_slug_options[:max_length]
|
93
|
-
return true if !force && simple_slug == simple_slug_get(locale).to_s.sub(/--\d+\z/, '')
|
94
|
-
resolved_simple_slug = simple_slug_resolve(simple_slug, locale)
|
95
|
-
simple_slug_set(resolved_simple_slug, locale)
|
96
|
-
end
|
97
|
-
|
98
|
-
def simple_slug_base
|
99
|
-
simple_slug_options[:slug_method].map{|m| send(m).to_s }.reject(&:blank?).join(' ')
|
100
|
-
end
|
101
|
-
|
102
|
-
def simple_slug_normalize(base)
|
103
|
-
base = SimpleSlug.normalize_cyrillic(base) unless SimpleSlug::CYRILLIC_LOCALES.include?(I18n.locale)
|
104
|
-
parameterize_args = ActiveSupport::VERSION::MAJOR > 4 ? {separator: '-'} : '-'
|
105
|
-
normalized = I18n.transliterate(base).parameterize(parameterize_args).downcase
|
106
|
-
normalized.to_s =~ SimpleSlug::STARTS_WITH_NUMBER_REGEXP ? "_#{normalized}" : normalized
|
107
|
-
end
|
108
|
-
|
109
|
-
def simple_slug_resolve(slug_value, locale=nil)
|
110
|
-
if simple_slug_exists?(slug_value, locale)
|
111
|
-
loop do
|
112
|
-
slug_value_with_suffix = simple_slug_next(slug_value)
|
113
|
-
break slug_value_with_suffix unless simple_slug_exists?(slug_value_with_suffix, locale)
|
114
|
-
end
|
115
|
-
else
|
116
|
-
slug_value
|
117
|
-
end
|
118
|
-
end
|
119
|
-
|
120
|
-
def simple_slug_next(slug_value)
|
121
|
-
"#{slug_value}--#{rand(99999)}"
|
122
|
-
end
|
123
|
-
|
124
|
-
def simple_slug_exists?(slug_value, locale=nil)
|
125
|
-
simple_slug_base_exists?(slug_value, locale) || simple_slug_history_exists?(slug_value)
|
126
|
-
end
|
127
|
-
|
128
|
-
def simple_slug_base_exists?(slug_value, locale=nil)
|
129
|
-
base_scope = self.class.unscoped.where(simple_slug_column(locale) => slug_value)
|
130
|
-
base_scope = base_scope.where('id != ?', id) if persisted?
|
131
|
-
base_scope.exists?
|
132
|
-
end
|
133
|
-
|
134
|
-
def simple_slug_history_exists?(slug_value)
|
135
|
-
return false unless simple_slug_options[:history]
|
136
|
-
base_scope = ::SimpleSlug::HistorySlug.where(sluggable_type: self.class.name, slug: slug_value)
|
137
|
-
base_scope = base_scope.where('sluggable_id != ?', id) if persisted?
|
138
|
-
base_scope.exists?
|
139
|
-
end
|
140
|
-
|
141
|
-
def simple_slug_set(value, locale=nil)
|
142
|
-
send "#{simple_slug_column(locale)}=", value
|
143
|
-
end
|
144
|
-
|
145
|
-
def simple_slug_get(locale=nil)
|
146
|
-
send simple_slug_column(locale)
|
147
|
-
end
|
148
|
-
|
149
|
-
def simple_slug_stored_slug(locale=nil)
|
150
|
-
send("#{simple_slug_column(locale)}_was")
|
151
|
-
end
|
152
|
-
|
153
|
-
def simple_slug_column(locale=nil)
|
154
|
-
[simple_slug_options[:slug_column], locale].compact.join('_')
|
71
|
+
simple_slug_adapter.generate(self, force: force)
|
155
72
|
end
|
156
73
|
end
|
157
74
|
|
158
75
|
module InstanceHistoryMethods
|
159
|
-
def
|
160
|
-
|
161
|
-
simple_slug_set simple_slug_stored_slug
|
76
|
+
def simple_slug_reset
|
77
|
+
errors.blank? || simple_slug_adapter.reset(self)
|
162
78
|
end
|
163
79
|
|
164
80
|
def simple_slug_cleanup_history
|
165
81
|
::SimpleSlug::HistorySlug.where(sluggable_type: self.class.name, sluggable_id: id).delete_all
|
166
82
|
end
|
167
83
|
|
168
|
-
def
|
169
|
-
|
170
|
-
::SimpleSlug::HistorySlug.where(sluggable_type: self.class.name, sluggable_id: id, slug: simple_slug_get).first_or_create
|
84
|
+
def simple_slug_save_history
|
85
|
+
simple_slug_adapter.save_history(self)
|
171
86
|
end
|
172
87
|
end
|
173
|
-
|
174
88
|
end
|
175
89
|
end
|
data/lib/simple_slug/railtie.rb
CHANGED
data/lib/simple_slug/version.rb
CHANGED
data/simple_slug.gemspec
CHANGED
@@ -1,4 +1,3 @@
|
|
1
|
-
# coding: utf-8
|
2
1
|
lib = File.expand_path('../lib', __FILE__)
|
3
2
|
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
3
|
require 'simple_slug/version'
|
@@ -9,7 +8,7 @@ Gem::Specification.new do |spec|
|
|
9
8
|
spec.authors = ['Alex Leschenko']
|
10
9
|
spec.email = ['leschenko.al@gmail.com']
|
11
10
|
spec.summary = %q{Friendly url generator with history.}
|
12
|
-
spec.description = %q{Simple friendly url generator for ActiveRecord with history.
|
11
|
+
spec.description = %q{Simple friendly url generator for ActiveRecord with history.}
|
13
12
|
spec.homepage = 'https://github.com/leschenko/simple_slug'
|
14
13
|
spec.license = 'MIT'
|
15
14
|
|
@@ -18,10 +17,11 @@ Gem::Specification.new do |spec|
|
|
18
17
|
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
18
|
spec.require_paths = ['lib']
|
20
19
|
|
21
|
-
spec.add_dependency 'activerecord', '>= 4.0.0', '<
|
20
|
+
spec.add_dependency 'activerecord', '>= 4.0.0', '< 6.2'
|
22
21
|
spec.add_dependency 'i18n', '~> 0.7'
|
23
22
|
|
24
|
-
spec.add_development_dependency 'bundler'
|
23
|
+
spec.add_development_dependency 'bundler'
|
25
24
|
spec.add_development_dependency 'rake'
|
26
25
|
spec.add_development_dependency 'rspec'
|
26
|
+
spec.add_development_dependency 'sqlite3'
|
27
27
|
end
|
@@ -1,21 +1,17 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
describe SimpleSlug do
|
4
|
-
|
5
|
-
it '
|
4
|
+
describe 'config' do
|
5
|
+
it 'has column name' do
|
6
6
|
expect(SimpleSlug.slug_column).to eq 'slug'
|
7
7
|
end
|
8
8
|
|
9
|
-
it 'excludes' do
|
9
|
+
it 'has excludes' do
|
10
10
|
expect(SimpleSlug.excludes).to include('new', 'edit')
|
11
11
|
end
|
12
12
|
|
13
|
-
it '
|
14
|
-
expect( SimpleSlug.
|
15
|
-
end
|
16
|
-
|
17
|
-
it 'max length' do
|
18
|
-
expect( SimpleSlug.max_length).to eq 240
|
13
|
+
it 'has max length' do
|
14
|
+
expect( SimpleSlug.max_length).to eq 191
|
19
15
|
end
|
20
16
|
end
|
21
17
|
end
|
@@ -1,54 +1,79 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class SlugHistoryRspecModel <
|
3
|
+
class SlugHistoryRspecModel < RspecActiveRecordBase
|
4
4
|
simple_slug :name, history: true
|
5
|
+
|
6
|
+
def should_generate_new_slug?
|
7
|
+
true
|
8
|
+
end
|
5
9
|
end
|
6
10
|
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
+
class SlugLocalizedHistoryRspecModel < RspecActiveRecordBase
|
12
|
+
simple_slug :name_for_slug, history: true, locales: [nil, :en]
|
13
|
+
|
14
|
+
def name_for_slug
|
15
|
+
[name, (I18n.locale unless I18n.locale == I18n.default_locale)].compact.join(' ')
|
16
|
+
end
|
17
|
+
|
18
|
+
def should_generate_new_slug?
|
19
|
+
true
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe 'history' do
|
24
|
+
before :each do
|
25
|
+
RspecActiveRecordBase.delete_all
|
26
|
+
SimpleSlug::HistorySlug.delete_all
|
27
|
+
end
|
28
|
+
|
29
|
+
describe 'persistence' do
|
30
|
+
it 'save previous on change' do
|
31
|
+
sluggable = SlugHistoryRspecModel.create(id: 1, name: 'Hello')
|
32
|
+
expect(SimpleSlug::HistorySlug.where(sluggable_type: 'SlugHistoryRspecModel', sluggable_id: 1).exists?).to be_falsey
|
33
|
+
sluggable.update(name: 'Bye')
|
34
|
+
hs = SimpleSlug::HistorySlug.where(sluggable_type: 'SlugHistoryRspecModel', sluggable_id: 1).to_a
|
35
|
+
expect(hs.size).to eq 1
|
36
|
+
expect(hs.first.locale).to be_falsey
|
37
|
+
expect(hs.first.slug).to eq 'hello'
|
11
38
|
end
|
12
39
|
|
13
|
-
it '
|
14
|
-
|
15
|
-
|
16
|
-
expect
|
17
|
-
SlugHistoryRspecModel.create(id: 1, name: 'Hello')
|
40
|
+
it 'remove on destroy' do
|
41
|
+
sluggable = SlugHistoryRspecModel.create(id: 1, name: 'Hello')
|
42
|
+
sluggable.update(name: 'Bye')
|
43
|
+
expect{ sluggable.destroy }.to change{ SimpleSlug::HistorySlug.where(sluggable_type: 'SlugHistoryRspecModel', sluggable_id: 1).count }.from(1).to(0)
|
18
44
|
end
|
19
45
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
46
|
+
context 'localized' do
|
47
|
+
it 'save previous on change' do
|
48
|
+
SlugLocalizedHistoryRspecModel.create(id: 1, name: 'Hello').update(name: 'Bye')
|
49
|
+
hs = SimpleSlug::HistorySlug.where(sluggable_type: 'SlugLocalizedHistoryRspecModel', sluggable_id: 1).to_a
|
50
|
+
expect(hs.map(&:locale)).to match_array [nil, 'en']
|
51
|
+
expect(hs.map(&:slug)).to match_array %w(hello hello-en)
|
52
|
+
end
|
26
53
|
end
|
27
54
|
end
|
28
55
|
|
29
56
|
describe 'conflicts' do
|
30
|
-
it '
|
31
|
-
|
32
|
-
|
33
|
-
expect(record).to
|
34
|
-
expect(record).to receive(:simple_slug_history_exists?).once.ordered.and_return(false)
|
35
|
-
record.save
|
36
|
-
expect(record.slug).to start_with('hi--')
|
57
|
+
it 'resolve with suffix' do
|
58
|
+
SlugHistoryRspecModel.create(name: 'Hello').update(name: 'Bye')
|
59
|
+
record = SlugHistoryRspecModel.create(name: 'Hello')
|
60
|
+
expect(record.slug).to start_with('hello--')
|
37
61
|
end
|
38
|
-
end
|
39
62
|
|
40
|
-
|
41
|
-
|
42
|
-
|
63
|
+
context 'localized' do
|
64
|
+
it 'resolve with suffix' do
|
65
|
+
SlugLocalizedHistoryRspecModel.create(name: 'Hello').update(name: 'Bye')
|
66
|
+
record = SlugLocalizedHistoryRspecModel.create(name: 'Hello')
|
67
|
+
expect(record.slug).to start_with('hello--')
|
68
|
+
expect(record.slug_en).to start_with('hello-en--')
|
69
|
+
end
|
43
70
|
end
|
71
|
+
end
|
44
72
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
expect(
|
49
|
-
expect(SlugHistoryRspecModel).to receive(:find).with(1).and_return(record)
|
50
|
-
SlugHistoryRspecModel.friendly_find('title')
|
73
|
+
describe 'find' do
|
74
|
+
it 'use history' do
|
75
|
+
SlugLocalizedHistoryRspecModel.create(id: 1, name: 'Hello').update(name: 'Bye')
|
76
|
+
expect(SlugLocalizedHistoryRspecModel.friendly_find('hello')).to be_truthy
|
51
77
|
end
|
52
78
|
end
|
53
|
-
|
54
79
|
end
|
@@ -1,151 +1,193 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
class
|
3
|
+
class SlugRspecModel < RspecActiveRecordBase
|
4
4
|
simple_slug :name
|
5
5
|
end
|
6
6
|
|
7
|
-
class
|
8
|
-
simple_slug :name,
|
7
|
+
class SlugWithFallbackOnBlankRspecModel < RspecActiveRecordBase
|
8
|
+
simple_slug :name, fallback_on_blank: true
|
9
9
|
end
|
10
10
|
|
11
|
-
class
|
12
|
-
simple_slug :name,
|
11
|
+
class SlugWithoutMaxLengthRspecModel < RspecActiveRecordBase
|
12
|
+
simple_slug :name, max_length: nil
|
13
13
|
end
|
14
14
|
|
15
|
-
class SlugGenerationRspecModelLocalized < RspecActiveModelBase
|
16
|
-
attr_accessor :slug_en, :name_en
|
17
|
-
alias_method :slug_en_was, :slug_en
|
18
15
|
|
19
|
-
|
16
|
+
class SlugWithoutValidationRspecModel < RspecActiveRecordBase
|
17
|
+
simple_slug :name, validation: false
|
18
|
+
end
|
20
19
|
|
21
|
-
|
22
|
-
|
20
|
+
class SlugWithoutCallbackRspecModel < RspecActiveRecordBase
|
21
|
+
simple_slug :name, callback_type: nil
|
22
|
+
end
|
23
|
+
|
24
|
+
class SlugLocalizedRspecModel < RspecActiveRecordBase
|
25
|
+
simple_slug :name_for_slug, history: true, locales: [nil, :en]
|
26
|
+
|
27
|
+
def name_for_slug
|
28
|
+
[name, (I18n.locale unless I18n.locale == I18n.default_locale)].compact.join(' ')
|
23
29
|
end
|
24
30
|
end
|
25
31
|
|
26
32
|
describe SimpleSlug::ModelAddition do
|
27
|
-
|
28
|
-
|
29
|
-
|
33
|
+
before :each do
|
34
|
+
RspecActiveRecordBase.delete_all
|
35
|
+
SimpleSlug::HistorySlug.delete_all
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'slug' do
|
39
|
+
it 'generate on save' do
|
40
|
+
expect(SlugRspecModel.create(name: 'Hello').slug).to eq 'hello'
|
30
41
|
end
|
31
42
|
|
32
|
-
it '
|
33
|
-
expect(
|
43
|
+
it 'add prefix for numbers' do
|
44
|
+
expect(SlugRspecModel.create(name: '123').slug).to eq '_123'
|
34
45
|
end
|
35
46
|
|
36
|
-
it '
|
37
|
-
expect(
|
47
|
+
it 'reject excludes' do
|
48
|
+
expect(SlugRspecModel.new(name: 'new')).not_to be_valid
|
38
49
|
end
|
39
50
|
|
40
|
-
it '
|
41
|
-
expect(
|
51
|
+
it 'reject spaces' do
|
52
|
+
expect(SlugRspecModel.new(slug: 'test test')).not_to be_valid
|
42
53
|
end
|
43
54
|
|
44
|
-
it '
|
45
|
-
|
46
|
-
expect(SlugGenerationRspecModel.create(name: 'Hello').slug).to be_blank
|
55
|
+
it 'reject punctuation' do
|
56
|
+
expect(SlugRspecModel.new(slug: 'test.test')).not_to be_valid
|
47
57
|
end
|
48
|
-
end
|
49
58
|
|
50
|
-
|
51
|
-
|
52
|
-
record = SlugGenerationRspecModel.new(name: 'Hi')
|
53
|
-
expect(record).to receive(:simple_slug_exists?).once.ordered.with('hi', nil).and_return(true)
|
54
|
-
expect(record).to receive(:simple_slug_exists?).once.ordered.with(/hi--\d+/, nil).and_return(false)
|
55
|
-
record.save
|
56
|
-
expect(record.slug).to start_with('hi--')
|
59
|
+
it 'fallback to prefixed id on blank slug source' do
|
60
|
+
expect(SlugWithFallbackOnBlankRspecModel.create({}).slug).to start_with '__'
|
57
61
|
end
|
58
62
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
63
|
+
describe '#should_generate_new_slug?' do
|
64
|
+
it 'can omit generation' do
|
65
|
+
allow_any_instance_of(SlugRspecModel).to receive(:should_generate_new_slug?).and_return(false)
|
66
|
+
expect(SlugRspecModel.create(name: 'Hello').slug).to be_blank
|
67
|
+
end
|
64
68
|
end
|
65
69
|
end
|
66
70
|
|
67
|
-
describe '
|
68
|
-
|
69
|
-
|
71
|
+
describe 'conflicts' do
|
72
|
+
it 'resolve with suffix' do
|
73
|
+
SlugRspecModel.create(name: 'Hello')
|
74
|
+
record = SlugHistoryRspecModel.create(name: 'Hello')
|
75
|
+
expect(record.slug).to start_with('hello--')
|
70
76
|
end
|
71
77
|
|
72
|
-
|
73
|
-
|
78
|
+
context 'localized' do
|
79
|
+
it 'resolve with suffix' do
|
80
|
+
SlugLocalizedRspecModel.create(name: 'Hello')
|
81
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
82
|
+
expect(record.slug).to start_with('hello--')
|
83
|
+
expect(record.slug_en).to start_with('hello-en--')
|
84
|
+
end
|
74
85
|
end
|
86
|
+
end
|
75
87
|
|
76
|
-
|
77
|
-
|
88
|
+
describe '#to_param' do
|
89
|
+
before do
|
90
|
+
allow_any_instance_of(SlugRspecModel).to receive(:simple_slug_exists?).and_return(false)
|
78
91
|
end
|
79
|
-
end
|
80
92
|
|
81
|
-
|
82
|
-
|
83
|
-
expect(SlugGenerationRspecModel).to receive(:find).with(1)
|
84
|
-
SlugGenerationRspecModel.friendly_find(1)
|
93
|
+
it 'use slug if present' do
|
94
|
+
expect(SlugRspecModel.create(name: 'Hello').to_param).to eq 'hello'
|
85
95
|
end
|
86
96
|
|
87
|
-
it '
|
88
|
-
expect(
|
89
|
-
SlugGenerationRspecModel.friendly_find('1')
|
97
|
+
it 'do not use unsaved slug' do
|
98
|
+
expect(SlugRspecModel.new(name: 'Hello').to_param).to be_falsey
|
90
99
|
end
|
91
100
|
|
92
|
-
it '
|
93
|
-
expect(
|
94
|
-
SlugGenerationRspecModel.friendly_find('title')
|
101
|
+
it 'use id if slug blank' do
|
102
|
+
expect(SlugRspecModel.create(id: 1).to_param).to eq '1'
|
95
103
|
end
|
96
104
|
end
|
97
105
|
|
98
|
-
describe '
|
99
|
-
|
100
|
-
|
106
|
+
describe 'find' do
|
107
|
+
it 'by id on integer like param' do
|
108
|
+
expect(SlugRspecModel).to receive(:find).with('1')
|
109
|
+
SlugRspecModel.friendly_find('1')
|
101
110
|
end
|
102
111
|
|
103
|
-
|
104
|
-
|
112
|
+
it 'by slug' do
|
113
|
+
expect(SlugRspecModel).to receive(:find_by!).with('slug' => 'title').and_return(double)
|
114
|
+
SlugRspecModel.friendly_find('title')
|
105
115
|
end
|
116
|
+
end
|
106
117
|
|
118
|
+
describe 'max length' do
|
107
119
|
it 'cuts slug to max length' do
|
108
|
-
record =
|
109
|
-
record.simple_slug_generate
|
110
|
-
expect(record.slug.length).to eq 240
|
111
|
-
end
|
112
|
-
|
113
|
-
it 'use max length from per model options' do
|
114
|
-
SlugGenerationRspecModel.simple_slug_options[:max_length] = 100
|
115
|
-
record = SlugGenerationRspecModel.new(name: 'Hello' * 100)
|
120
|
+
record = SlugRspecModel.new(name: 'Hello' * 100)
|
116
121
|
record.simple_slug_generate
|
117
|
-
expect(record.slug.length).to eq
|
122
|
+
expect(record.slug.length).to eq 191
|
118
123
|
end
|
119
124
|
|
120
|
-
it '
|
121
|
-
|
122
|
-
record = SlugGenerationRspecModel.new(name: 'Hello' * 100)
|
125
|
+
it 'return full slug without max_length option' do
|
126
|
+
record = SlugWithoutMaxLengthRspecModel.new(name: 'Hello' * 100)
|
123
127
|
record.simple_slug_generate
|
124
128
|
expect(record.slug.length).to eq 500
|
125
129
|
end
|
126
130
|
end
|
127
131
|
|
128
|
-
describe '
|
129
|
-
it 'skip
|
130
|
-
expect(
|
132
|
+
describe 'validation' do
|
133
|
+
it 'optionally skip validations' do
|
134
|
+
expect(SlugWithoutValidationRspecModel.validators_on(:slug)).to be_blank
|
131
135
|
end
|
132
136
|
end
|
133
137
|
|
134
|
-
describe '
|
135
|
-
it 'skip callback' do
|
136
|
-
expect(
|
138
|
+
describe 'callbacks' do
|
139
|
+
it 'optionally skip callback' do
|
140
|
+
expect(SlugWithoutCallbackRspecModel.new).not_to receive(:should_generate_new_slug?)
|
137
141
|
end
|
138
142
|
end
|
139
143
|
|
140
144
|
describe 'localized' do
|
141
|
-
before do
|
142
|
-
allow_any_instance_of(SlugGenerationRspecModelLocalized).to receive(:simple_slug_exists?).and_return(false)
|
143
|
-
end
|
144
|
-
|
145
145
|
it 'generate slug for locales' do
|
146
|
-
record =
|
146
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
147
147
|
expect(record.slug).to eq 'hello'
|
148
148
|
expect(record.slug_en).to eq 'hello-en'
|
149
149
|
end
|
150
|
+
|
151
|
+
describe '#should_generate_new_slug?' do
|
152
|
+
it 'keep slug when present' do
|
153
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
154
|
+
expect{ record.update(name: 'Bye') }.not_to change{ record.slug }
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'generate slug when blank' do
|
158
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
159
|
+
record.name = 'bye'
|
160
|
+
record.slug_en = nil
|
161
|
+
expect{ record.save }.to change{ record.slug_en }.to('bye-en')
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#to_param' do
|
166
|
+
it 'use unlocalized column for default locale' do
|
167
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
168
|
+
expect(record.to_param).to eq 'hello'
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'use localized column for non-default locales' do
|
172
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
173
|
+
I18n.with_locale(:en) do
|
174
|
+
expect(record.to_param).to eq 'hello-en'
|
175
|
+
end
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
describe 'find' do
|
180
|
+
it 'use default slug column for default locale' do
|
181
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
182
|
+
expect(SlugLocalizedRspecModel.simple_slug_find('hello')).to eq record
|
183
|
+
end
|
184
|
+
|
185
|
+
it 'use localized slug column for non-default locale' do
|
186
|
+
record = SlugLocalizedRspecModel.create(name: 'Hello')
|
187
|
+
I18n.with_locale(:en) do
|
188
|
+
expect(SlugLocalizedRspecModel.simple_slug_find('hello-en')).to eq record
|
189
|
+
end
|
190
|
+
end
|
191
|
+
end
|
150
192
|
end
|
151
193
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,47 +1,44 @@
|
|
1
|
+
require 'sqlite3'
|
1
2
|
require 'active_record'
|
2
3
|
require 'i18n'
|
3
4
|
require 'active_support/core_ext'
|
5
|
+
require 'byebug'
|
4
6
|
require 'simple_slug'
|
5
7
|
|
6
|
-
# just silence warning
|
7
8
|
I18n.enforce_available_locales = false
|
8
9
|
I18n.default_locale = :uk
|
9
10
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
true
|
11
|
+
ActiveRecord::Base.establish_connection(
|
12
|
+
adapter: 'sqlite3',
|
13
|
+
database: ':memory:'
|
14
|
+
)
|
15
|
+
|
16
|
+
# ActiveRecord::Base.logger = Logger.new(STDOUT)
|
17
|
+
|
18
|
+
RSpec.configure do |config|
|
19
|
+
config.before(:suite) do
|
20
|
+
ActiveRecord::Migration.verbose = false
|
21
|
+
|
22
|
+
ActiveRecord::Schema.define do
|
23
|
+
create_table :rspec_active_record_bases, force: true do |t|
|
24
|
+
t.string :name
|
25
|
+
t.string :slug, limit: 191
|
26
|
+
t.string :slug_en, limit: 191
|
27
|
+
t.timestamps
|
28
|
+
end
|
29
|
+
|
30
|
+
create_table :simple_slug_history_slugs, force: true do |t|
|
31
|
+
t.string :slug, null: false, limit: 191
|
32
|
+
t.string :locale, limit: 10
|
33
|
+
t.integer :sluggable_id, null: false
|
34
|
+
t.string :sluggable_type, limit: 50, null: false
|
35
|
+
t.timestamps
|
36
|
+
end
|
37
|
+
end
|
38
38
|
end
|
39
|
+
end
|
39
40
|
|
40
|
-
def slug_changed?
|
41
|
-
slug.present?
|
42
|
-
end
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
end
|
42
|
+
class RspecActiveRecordBase < ActiveRecord::Base
|
43
|
+
include SimpleSlug::ModelAddition
|
44
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: simple_slug
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Alex Leschenko
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-01-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -19,7 +19,7 @@ dependencies:
|
|
19
19
|
version: 4.0.0
|
20
20
|
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '6.2'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -29,7 +29,7 @@ dependencies:
|
|
29
29
|
version: 4.0.0
|
30
30
|
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '6.2'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: i18n
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -48,16 +48,16 @@ dependencies:
|
|
48
48
|
name: bundler
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- - "
|
51
|
+
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
|
-
version: '
|
53
|
+
version: '0'
|
54
54
|
type: :development
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- - "
|
58
|
+
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
|
-
version: '
|
60
|
+
version: '0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: rake
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
@@ -86,7 +86,21 @@ dependencies:
|
|
86
86
|
- - ">="
|
87
87
|
- !ruby/object:Gem::Version
|
88
88
|
version: '0'
|
89
|
-
|
89
|
+
- !ruby/object:Gem::Dependency
|
90
|
+
name: sqlite3
|
91
|
+
requirement: !ruby/object:Gem::Requirement
|
92
|
+
requirements:
|
93
|
+
- - ">="
|
94
|
+
- !ruby/object:Gem::Version
|
95
|
+
version: '0'
|
96
|
+
type: :development
|
97
|
+
prerelease: false
|
98
|
+
version_requirements: !ruby/object:Gem::Requirement
|
99
|
+
requirements:
|
100
|
+
- - ">="
|
101
|
+
- !ruby/object:Gem::Version
|
102
|
+
version: '0'
|
103
|
+
description: Simple friendly url generator for ActiveRecord with history.
|
90
104
|
email:
|
91
105
|
- leschenko.al@gmail.com
|
92
106
|
executables: []
|
@@ -101,6 +115,7 @@ files:
|
|
101
115
|
- Rakefile
|
102
116
|
- db/migrate/20140113000001_create_simple_slug_history_slug.rb
|
103
117
|
- lib/simple_slug.rb
|
118
|
+
- lib/simple_slug/adapter.rb
|
104
119
|
- lib/simple_slug/history_slug.rb
|
105
120
|
- lib/simple_slug/model_addition.rb
|
106
121
|
- lib/simple_slug/railtie.rb
|
@@ -114,7 +129,7 @@ homepage: https://github.com/leschenko/simple_slug
|
|
114
129
|
licenses:
|
115
130
|
- MIT
|
116
131
|
metadata: {}
|
117
|
-
post_install_message:
|
132
|
+
post_install_message:
|
118
133
|
rdoc_options: []
|
119
134
|
require_paths:
|
120
135
|
- lib
|
@@ -129,9 +144,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
129
144
|
- !ruby/object:Gem::Version
|
130
145
|
version: '0'
|
131
146
|
requirements: []
|
132
|
-
|
133
|
-
|
134
|
-
signing_key:
|
147
|
+
rubygems_version: 3.0.6
|
148
|
+
signing_key:
|
135
149
|
specification_version: 4
|
136
150
|
summary: Friendly url generator with history.
|
137
151
|
test_files:
|