simple_slug 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 4e372bf7c9afde482560d5e69ed52ce343e0c08e
4
- data.tar.gz: 3f51178cc10919580d3e167839c93d1ceaa5fedd
2
+ SHA256:
3
+ metadata.gz: ac49bba6dff11ad2a2bce99cef0ff717ca35a626fb22c23ef708369b596c57fe
4
+ data.tar.gz: eb3955cec13641066e6d15aef572b78491fc8b6c59500658edbd72e05126083d
5
5
  SHA512:
6
- metadata.gz: e6b3a471ce38ccb23d33ca1be285012b7980d1d5c15f6a982b869c8d348ee879d405728c1fe0eeea80e112b4471a2765e6ceec7b38da3b01c1ea7e1dcd64be6f
7
- data.tar.gz: 5872ee8fe9b193d425ec3090c403a19fe7fec864f1fdf94f0a6039a65782248bef837600d49ba3b2679299ba6008353ea83bd8d6d749678f2b867d0bde8431ec
6
+ metadata.gz: 961d7deede6a55925d4020f2b09f3e40b86012d3574f5745318a69ea34b952cef7f00b251562832ec053fcc61db52b268f647092f57e934e7278f58a34c8b789
7
+ data.tar.gz: dbc20244f3751330ac668edf4a92b381c9c1b2480a924be0b90cf0d37a194703cd6c9833e6cc1d852f8b912b08c815a93c916666660460b780a7cce02ed1341b
@@ -1,4 +1,4 @@
1
1
  language: ruby
2
2
 
3
3
  rvm:
4
- - 2.3.0
4
+ - 2.6.3
data/README.md CHANGED
@@ -1,7 +1,6 @@
1
1
  # SimpleSlug
2
2
 
3
3
  [![Build Status](https://travis-ci.org/leschenko/simple_slug.png?branch=master)](https://travis-ci.org/leschenko/simple_slug)
4
- [![Dependency Status](https://gemnasium.com/leschenko/simple_slug.png)](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 :simple_slug_history_slug do |t|
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.datetime :created_at
8
+ t.timestamps
8
9
  end
9
10
 
10
- add_index :simple_slug_history_slug, [:slug, :sluggable_type], unique: true
11
- add_index :simple_slug_history_slug, [:sluggable_type, :sluggable_id]
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
@@ -4,10 +4,12 @@ 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 assets javascripts images)
12
+ @@excludes = %w(new edit show index session login logout sign_in sign_out users admin stylesheets javascripts images fonts assets)
11
13
 
12
14
  mattr_accessor :slug_regexp
13
15
  @@slug_regexp = /\A(?:\w+[\w\d\-_]*|--\d+)\z/
@@ -15,48 +17,23 @@ module SimpleSlug
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 = 240
24
+ @@max_length = 191
20
25
 
21
26
  mattr_accessor :callback_type
22
27
  @@callback_type = :before_validation
23
28
 
24
- mattr_accessor :add_validation
25
- @@add_validation = true
29
+ mattr_accessor :validation
30
+ @@validation = true
26
31
 
27
32
  STARTS_WITH_NUMBER_REGEXP =/\A\d+/
28
- CYRILLIC_LOCALES = [:uk, :ru, :be].freeze
29
- ES_LOCALES = [:es].freeze
30
-
31
- ES_NORMALIZE_SINGLE = [
32
- 'ÀÁÂÃÄÅÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖØÙÚÛÜÝßàáâãäåçèéêëìíîïñòóôõöøùúûüýÿĀāĂ㥹ĆćĈĉĊċČčĎďĐđĒēĔĕĖėĘęĚěĜĝĞğĠġĢģĤĥĦħĨĩĪīĬĭĮįİıĴĵĶķĹĺĻļĽľĿŀŁłŃńŅņŇňʼnŌōŎŏŐőŔŕŖŗŘřŚśŜŝŞşŠšŢţŤťŦŧŨũŪūŬŭŮůŰűŲųŴŵŶŷŸŹźŻżŽžſƒƠơƯưǍǎǏǐǑǒǓǔǕǖǗǘǙǚǛǜǺǻǾǿ',
33
- 'AAAAAACEEEEIIIIDNOOOOOOUUUUYsaaaaaaceeeeiiiinoooooouuuuyyAaAaAaCcCcCcCcDdDdEeEeEeEeEeGgGgGgGgHhHhIiIiIiIiIiJjKkLlLlLlLlllNnNnNnnOoOoOoRrRrRrSsSsSsSsTtTtTtUuUuUuUuUuUuWwYyYZzZzZzsfOoUuAaIiOoUuUuUuUuUuAaOo'
34
- ].freeze
35
-
36
- ES_NORMALIZE_MULTI = [['Æ', 'AE'], ['æ', 'ae'], ['IJ', 'IJ'], ['ij', 'ij'], ['Œ', 'OE'], ['œ', 'oe'], ['Ǽ', 'AE'], ['ǽ', 'ae']].freeze
33
+ NUMBER_REGEXP =/\A\d+\z/
34
+ RESOLVE_SUFFIX_REGEXP = /--\d+\z/
37
35
 
38
36
  def self.setup
39
37
  yield self
40
38
  end
41
-
42
- def self.normalize_i18n_fix(base, locale=I18n.locale)
43
- locale_sym = locale.to_sym
44
- if CYRILLIC_LOCALES.include?(locale_sym)
45
- normalize_cyrillic(base)
46
- elsif ES_LOCALES.include?(locale_sym)
47
- normalize_es(base)
48
- else
49
- base
50
- end
51
- end
52
-
53
- def self.normalize_cyrillic(base)
54
- base.tr('АаВЕеіКкМНОоРрСсТуХх', 'AaBEeiKkMHOoPpCcTyXx')
55
- end
56
-
57
- def self.normalize_es(base)
58
- base = base.tr(*ES_NORMALIZE_SINGLE)
59
- ES_NORMALIZE_MULTI.each{|d| base.gsub!(*d) }
60
- base
61
- end
62
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.first(options[:max_length]) 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
@@ -1,5 +1,6 @@
1
1
  module SimpleSlug
2
2
  class HistorySlug < ActiveRecord::Base
3
+ self.table_name = 'simple_slug_history_slugs'
3
4
  belongs_to :sluggable, polymorphic: true
4
5
  end
5
6
  end
@@ -6,33 +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
14
  slug_regexp: SimpleSlug.slug_regexp,
15
+ min_length: SimpleSlug.min_length,
15
16
  max_length: SimpleSlug.max_length,
16
17
  callback_type: SimpleSlug.callback_type,
17
- add_validation: SimpleSlug.add_validation
18
+ validation: SimpleSlug.validation
18
19
  )
20
+ self.simple_slug_adapter = SimpleSlug::Adapter.new(self)
19
21
 
20
22
  include InstanceMethods
21
23
  extend ClassMethods
22
24
 
23
25
  send(simple_slug_options[:callback_type], :simple_slug_generate, if: :should_generate_new_slug?) if simple_slug_options[:callback_type]
24
26
 
25
- if simple_slug_options[:add_validation]
26
- simple_slug_locales.each do |locale|
27
- validates simple_slug_column(locale),
28
- presence: true,
29
- exclusion: {in: SimpleSlug.excludes},
30
- format: {with: simple_slug_options[:slug_regexp]}
31
- end
27
+ if simple_slug_options[:validation]
28
+ validates *simple_slug_adapter.column_names,
29
+ presence: true,
30
+ uniqueness: {case_sensitive: true},
31
+ exclusion: {in: SimpleSlug.excludes},
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? }
32
34
  end
33
35
 
34
36
  if simple_slug_options[:history]
35
- after_save :simple_slug_reset_unsaved_slug, :simple_slug_create_history_slug
37
+ after_save :simple_slug_reset, :simple_slug_save_history
36
38
  after_destroy :simple_slug_cleanup_history
37
39
  include InstanceHistoryMethods
38
40
  end
@@ -42,157 +44,45 @@ module SimpleSlug
42
44
  module ClassMethods
43
45
  def simple_slug_find(id_param)
44
46
  return unless id_param
45
- if id_param.is_a?(Integer) || id_param =~ /\A\d+\z/
47
+ if id_param.is_a?(Integer) || id_param =~ SimpleSlug::NUMBER_REGEXP
46
48
  find(id_param)
47
49
  else
48
- finder_method = simple_slug_options[:history] ? :find_by : :find_by!
49
- send(finder_method, simple_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)
50
51
  end
51
52
  end
52
53
 
53
- alias_method :friendly_find, :simple_slug_find
54
-
55
- def simple_slug_column(locale=I18n.locale)
56
- if simple_slug_localized?(locale)
57
- [simple_slug_options[:slug_column], locale].compact.join('_')
58
- else
59
- simple_slug_options[:slug_column]
60
- end
61
- end
62
-
63
- def simple_slug_columns
64
- simple_slug_locales.map{|locale| simple_slug_column(locale) }
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)
65
56
  end
66
57
 
67
- def simple_slug_locales
68
- Array(simple_slug_options[:locales] || [nil])
69
- end
70
-
71
- def simple_slug_localized?(locale=I18n.locale)
72
- return unless locale
73
- simple_slug_locales.include?(locale.to_sym)
74
- end
58
+ alias_method :friendly_find, :simple_slug_find
75
59
  end
76
60
 
77
61
  module InstanceMethods
78
62
  def to_param
79
- simple_slug_stored_slug.presence || super
63
+ simple_slug_adapter.get_prev(self).presence || super
80
64
  end
81
65
 
82
66
  def should_generate_new_slug?
83
- return true if simple_slug_options[:history]
84
- if simple_slug_options[:locales]
85
- should_generate_new_slug_for_locales.present?
86
- else
87
- simple_slug_get.blank?
88
- end
89
- end
90
-
91
- def should_generate_new_slug_for_locales
92
- return unless simple_slug_options[:locales]
93
- simple_slug_options[:locales].find_all {|locale| simple_slug_get(locale).blank?}
67
+ simple_slug_adapter.column_names.any?{|cn| send(cn).blank? }
94
68
  end
95
69
 
96
70
  def simple_slug_generate(force=false)
97
- locales = if simple_slug_options[:locales]
98
- ((!force && should_generate_new_slug_for_locales) || simple_slug_options[:locales])
99
- else
100
- [nil]
101
- end
102
- locales.each do |locale|
103
- simple_slug_generate_for_locale(locale, force)
104
- end
105
- end
106
-
107
- def simple_slug_generate_for_locale(locale=I18n.locale, force=false)
108
- simple_slug_with_locale(locale) do
109
- simple_slug = simple_slug_normalize(simple_slug_base)
110
- simple_slug = simple_slug.first(simple_slug_options[:max_length]) if simple_slug_options[:max_length]
111
- simple_slug = "__#{id || rand(9999)}" if simple_slug.blank? && simple_slug_options[:fallback_on_blank]
112
- return if !force && simple_slug == simple_slug_get(locale).to_s.sub(/--\d+\z/, '')
113
- resolved_simple_slug = simple_slug_resolve(simple_slug, locale)
114
- simple_slug_set(resolved_simple_slug, locale)
115
- end
116
- end
117
-
118
- def simple_slug_with_locale(locale)
119
- if defined? Globalize
120
- Globalize.with_locale(locale) do
121
- I18n.with_locale(locale) { yield }
122
- end
123
- else
124
- I18n.with_locale(locale) { yield }
125
- end
126
- end
127
-
128
- def simple_slug_base
129
- simple_slug_options[:slug_method].map{|m| send(m).to_s }.reject(&:blank?).join(' ')
130
- end
131
-
132
- def simple_slug_normalize(base)
133
- parameterize_args = ActiveSupport::VERSION::MAJOR > 4 ? {separator: '-'} : '-'
134
- normalized = I18n.transliterate(SimpleSlug.normalize_i18n_fix(base)).parameterize(parameterize_args).downcase
135
- normalized.to_s =~ SimpleSlug::STARTS_WITH_NUMBER_REGEXP ? "_#{normalized}" : normalized
136
- end
137
-
138
- def simple_slug_resolve(slug_value, locale=I18n.locale)
139
- if simple_slug_exists?(slug_value, locale)
140
- loop do
141
- slug_value_with_suffix = simple_slug_next(slug_value)
142
- break slug_value_with_suffix unless simple_slug_exists?(slug_value_with_suffix, locale)
143
- end
144
- else
145
- slug_value
146
- end
147
- end
148
-
149
- def simple_slug_next(slug_value)
150
- "#{slug_value}--#{rand(99999)}"
151
- end
152
-
153
- def simple_slug_exists?(slug_value, locale=I18n.locale)
154
- simple_slug_base_exists?(slug_value, locale) || simple_slug_history_exists?(slug_value)
155
- end
156
-
157
- def simple_slug_base_exists?(slug_value, locale=I18n.locale)
158
- base_scope = self.class.unscoped.where(self.class.simple_slug_column(locale) => slug_value)
159
- base_scope = base_scope.where('id != ?', id) if persisted?
160
- base_scope.exists?
161
- end
162
-
163
- def simple_slug_history_exists?(slug_value)
164
- return false unless simple_slug_options[:history]
165
- base_scope = ::SimpleSlug::HistorySlug.where(sluggable_type: self.class.name, slug: slug_value)
166
- base_scope = base_scope.where('sluggable_id != ?', id) if persisted?
167
- base_scope.exists?
168
- end
169
-
170
- def simple_slug_set(value, locale=I18n.locale)
171
- send "#{self.class.simple_slug_column(locale)}=", value
172
- end
173
-
174
- def simple_slug_get(locale=I18n.locale)
175
- send self.class.simple_slug_column(locale)
176
- end
177
-
178
- def simple_slug_stored_slug(locale=I18n.locale)
179
- send("#{self.class.simple_slug_column(locale)}_was")
71
+ simple_slug_adapter.generate(self, force: force)
180
72
  end
181
73
  end
182
74
 
183
75
  module InstanceHistoryMethods
184
- def simple_slug_reset_unsaved_slug
185
- return true if errors.blank?
186
- simple_slug_set simple_slug_stored_slug
76
+ def simple_slug_reset
77
+ errors.blank? || simple_slug_adapter.reset(self)
187
78
  end
188
79
 
189
80
  def simple_slug_cleanup_history
190
81
  ::SimpleSlug::HistorySlug.where(sluggable_type: self.class.name, sluggable_id: id).delete_all
191
82
  end
192
83
 
193
- def simple_slug_create_history_slug
194
- return true unless slug_changed?
195
- ::SimpleSlug::HistorySlug.where(sluggable_type: self.class.name, slug: simple_slug_get).first_or_create{|hs| hs.sluggable_id = id }
84
+ def simple_slug_save_history
85
+ simple_slug_adapter.save_history(self)
196
86
  end
197
87
  end
198
88
  end
@@ -1,11 +1,9 @@
1
1
  module SimpleSlug
2
2
  class Railtie < Rails::Railtie
3
3
  initializer 'simple_slug.model_additions' do
4
-
5
4
  ActiveSupport.on_load :active_record do
6
5
  include SimpleSlug::ModelAddition
7
6
  end
8
-
9
7
  end
10
8
  end
11
9
  end
@@ -1,3 +1,3 @@
1
1
  module SimpleSlug
2
- VERSION = '0.3.5'
2
+ VERSION = '0.4.0'
3
3
  end
@@ -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'
@@ -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', '< 5.3'
20
+ spec.add_dependency 'activerecord', '>= 4.0.0', '< 6.1'
22
21
  spec.add_dependency 'i18n', '~> 0.7'
23
22
 
24
23
  spec.add_development_dependency 'bundler', '~> 1.5'
25
24
  spec.add_development_dependency 'rake'
26
25
  spec.add_development_dependency 'rspec'
26
+ spec.add_development_dependency 'sqlite3'
27
27
  end
@@ -1,17 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe SimpleSlug do
4
- context 'defaults' do
5
- it 'slug column' do
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 'max length' do
14
- expect( SimpleSlug.max_length).to eq 240
13
+ it 'has max length' do
14
+ expect( SimpleSlug.max_length).to eq 191
15
15
  end
16
16
  end
17
17
  end
@@ -1,54 +1,79 @@
1
1
  require 'spec_helper'
2
2
 
3
- class SlugHistoryRspecModel < RspecActiveModelBase
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
- describe 'slug history' do
8
- describe 'history records handling' do
9
- before do
10
- expect_any_instance_of(SlugHistoryRspecModel).to receive(:simple_slug_exists?).and_return(false)
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 'create' do
14
- relation = double
15
- expect(::SimpleSlug::HistorySlug).to receive(:where).once.ordered.with(sluggable_type: 'SlugHistoryRspecModel', slug: 'hello').and_return(relation)
16
- expect(relation).to receive(:first_or_create)
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
- it 'cleanup' do
21
- relation = double
22
- expect(relation).to receive(:first_or_create)
23
- allow(::SimpleSlug::HistorySlug).to receive(:where).and_return(relation)
24
- expect(relation).to receive(:delete_all)
25
- SlugHistoryRspecModel.create(name: 'Hello', id: 1).destroy
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 'history slug exists' do
31
- record = SlugGenerationRspecModel.new(name: 'Hi')
32
- allow(record).to receive(:simple_slug_base_exists?).and_return(false)
33
- expect(record).to receive(:simple_slug_history_exists?).once.ordered.and_return(true)
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
- describe '#friendly_find' do
41
- before do
42
- allow(SlugHistoryRspecModel).to receive(:find_by)
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
- it 'find from history' do
46
- record = double('history')
47
- allow(record).to receive(:sluggable_id).and_return(1)
48
- expect(::SimpleSlug::HistorySlug).to receive(:find_by!).with(slug: 'title').and_return(record)
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,220 +1,192 @@
1
1
  require 'spec_helper'
2
2
 
3
- class SlugGenerationRspecModel < RspecActiveModelBase
3
+ class SlugRspecModel < RspecActiveRecordBase
4
4
  simple_slug :name
5
5
  end
6
6
 
7
- class SlugGenerationRspecModelWithoutValidation < RspecActiveModelBase
8
- simple_slug :name, add_validation: false
7
+ class SlugWithFallbackOnBlankRspecModel < RspecActiveRecordBase
8
+ simple_slug :name, fallback_on_blank: true
9
9
  end
10
10
 
11
- class SlugGenerationRspecModelWithoutCallback < RspecActiveModelBase
12
- simple_slug :name, callback_type: nil
11
+ class SlugWithoutMaxLengthRspecModel < RspecActiveRecordBase
12
+ simple_slug :name, max_length: nil
13
13
  end
14
14
 
15
- class SlugGenerationRspecModelWithFallbackOnBlank < RspecActiveModelBase
16
- simple_slug :name, fallback_on_blank: true
15
+
16
+ class SlugWithoutValidationRspecModel < RspecActiveRecordBase
17
+ simple_slug :name, validation: false
17
18
  end
18
19
 
19
- class SlugGenerationRspecModelLocalized < RspecActiveModelBase
20
- attr_accessor :slug_en, :name_en
21
- alias_method :slug_en_was, :slug_en
20
+ class SlugWithoutCallbackRspecModel < RspecActiveRecordBase
21
+ simple_slug :name, callback_type: nil
22
+ end
22
23
 
23
- simple_slug :name, locales: [nil, :en]
24
+ class SlugLocalizedRspecModel < RspecActiveRecordBase
25
+ simple_slug :name_for_slug, history: true, locales: [nil, :en]
24
26
 
25
- def name
26
- I18n.locale == :en ? name_en : @name
27
+ def name_for_slug
28
+ [name, (I18n.locale unless I18n.locale == I18n.default_locale)].compact.join(' ')
27
29
  end
28
30
  end
29
31
 
30
32
  describe SimpleSlug::ModelAddition do
31
- describe 'slug generation' do
32
- before do
33
- allow_any_instance_of(SlugGenerationRspecModel). to receive(:simple_slug_exists?).and_return(false)
34
- allow_any_instance_of(SlugGenerationRspecModelWithFallbackOnBlank). to receive(:simple_slug_exists?).and_return(false)
35
- end
36
-
37
- it 'after save' do
38
- expect(SlugGenerationRspecModel.create(name: 'Hello').slug).to eq 'hello'
39
- end
33
+ before :each do
34
+ RspecActiveRecordBase.delete_all
35
+ SimpleSlug::HistorySlug.delete_all
36
+ end
40
37
 
41
- it 'skip excludes' do
42
- expect(SlugGenerationRspecModel.new(name: 'new')).not_to be_valid
38
+ describe 'slug' do
39
+ it 'generate on save' do
40
+ expect(SlugRspecModel.create(name: 'Hello').slug).to eq 'hello'
43
41
  end
44
42
 
45
- it 'skip integers' do
46
- expect(SlugGenerationRspecModel.new(name: '123')).not_to be_valid
43
+ it 'add prefix for numbers' do
44
+ expect(SlugRspecModel.create(name: '123').slug).to eq '_123'
47
45
  end
48
46
 
49
- it 'skip spaces' do
50
- expect(SlugGenerationRspecModel.new(slug: 'test test')).not_to be_valid
47
+ it 'reject excludes' do
48
+ expect(SlugRspecModel.new(name: 'new')).not_to be_valid
51
49
  end
52
50
 
53
- it 'skip punctuation' do
54
- expect(SlugGenerationRspecModel.new(slug: 'test.test')).not_to be_valid
51
+ it 'reject spaces' do
52
+ expect(SlugRspecModel.new(slug: 'test test')).not_to be_valid
55
53
  end
56
54
 
57
- it 'es chars' do
58
- I18n.with_locale(:es) do
59
- expect(SlugGenerationRspecModel.create(name: 'áǼßHello').slug).to eq 'aaeshello'
60
- end
55
+ it 'reject punctuation' do
56
+ expect(SlugRspecModel.new(slug: 'test.test')).not_to be_valid
61
57
  end
62
58
 
63
- it 'fallback on blank' do
64
- SlugGenerationRspecModelWithFallbackOnBlank.create({})
65
- expect(SlugGenerationRspecModelWithFallbackOnBlank.create({}).slug).to start_with '__'
59
+ it 'fallback to prefixed id on blank slug source' do
60
+ expect(SlugWithFallbackOnBlankRspecModel.create({}).slug).to start_with '__'
66
61
  end
67
62
 
68
- it 'skip slug generation' do
69
- allow_any_instance_of(SlugGenerationRspecModel).to receive(:should_generate_new_slug?).and_return(false)
70
- expect(SlugGenerationRspecModel.create(name: 'Hello').slug).to be_blank
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
71
68
  end
72
69
  end
73
70
 
74
- describe 'resolve conflicts' do
75
- it 'duplicate slug' do
76
- record = SlugGenerationRspecModel.new(name: 'Hi')
77
- expect(record).to receive(:simple_slug_exists?).once.ordered.with('hi', nil).and_return(true)
78
- expect(record).to receive(:simple_slug_exists?).once.ordered.with(/hi--\d+/, nil).and_return(false)
79
- record.save
80
- expect(record.slug).to start_with('hi--')
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--')
81
76
  end
82
77
 
83
- it 'numeric slug' do
84
- record = SlugGenerationRspecModel.new(name: '123')
85
- expect(record).to receive(:simple_slug_exists?).with('_123', nil).and_return(false)
86
- record.save
87
- expect(record.slug).to eq '_123'
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
88
85
  end
89
86
  end
90
87
 
91
88
  describe '#to_param' do
92
89
  before do
93
- allow_any_instance_of(SlugGenerationRspecModel).to receive(:simple_slug_exists?).and_return(false)
90
+ allow_any_instance_of(SlugRspecModel).to receive(:simple_slug_exists?).and_return(false)
94
91
  end
95
92
 
96
- it 'slug if exists' do
97
- expect(SlugGenerationRspecModel.create(name: 'Hello').to_param).to eq 'hello'
93
+ it 'use slug if present' do
94
+ expect(SlugRspecModel.create(name: 'Hello').to_param).to eq 'hello'
98
95
  end
99
96
 
100
- it 'id without slug' do
101
- expect(SlugGenerationRspecModel.create(id: 1).to_param).to eq '1'
97
+ it 'do not use unsaved slug' do
98
+ expect(SlugRspecModel.new(name: 'Hello').to_param).to be_falsey
102
99
  end
103
- end
104
100
 
105
- describe '#friendly_find' do
106
- it '#find if integer like' do
107
- expect(SlugGenerationRspecModel).to receive(:find).with(1)
108
- SlugGenerationRspecModel.friendly_find(1)
101
+ it 'use id if slug blank' do
102
+ expect(SlugRspecModel.create(id: 1).to_param).to eq '1'
109
103
  end
104
+ end
110
105
 
111
- it '#find if numeric string' do
112
- expect(SlugGenerationRspecModel).to receive(:find).with('1')
113
- SlugGenerationRspecModel.friendly_find('1')
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')
114
110
  end
115
111
 
116
- it 'find by slug' do
117
- expect(SlugGenerationRspecModel).to receive(:find_by!).with('slug' => 'title').and_return(double)
118
- SlugGenerationRspecModel.friendly_find('title')
112
+ it 'by slug' do
113
+ expect(SlugRspecModel).to receive(:find_by!).with('slug' => 'title').and_return(double)
114
+ SlugRspecModel.friendly_find('title')
119
115
  end
120
116
  end
121
117
 
122
118
  describe 'max length' do
123
- before do
124
- allow_any_instance_of(SlugGenerationRspecModel).to receive(:simple_slug_exists?).and_return(false)
125
- end
126
-
127
- after do
128
- SlugGenerationRspecModel.simple_slug_options.delete(:max_length)
129
- end
130
-
131
119
  it 'cuts slug to max length' do
132
- record = SlugGenerationRspecModel.new(name: 'Hello' * 100)
133
- record.simple_slug_generate
134
- expect(record.slug.length).to eq 240
135
- end
136
-
137
- it 'use max length from per model options' do
138
- SlugGenerationRspecModel.simple_slug_options[:max_length] = 100
139
- record = SlugGenerationRspecModel.new(name: 'Hello' * 100)
120
+ record = SlugRspecModel.new(name: 'Hello' * 100)
140
121
  record.simple_slug_generate
141
- expect(record.slug.length).to eq 100
122
+ expect(record.slug.length).to eq 191
142
123
  end
143
124
 
144
- it 'omit max length' do
145
- SimpleSlug.max_length = nil
146
- record = SlugGenerationRspecModel.new(name: 'Hello' * 100)
125
+ it 'return full slug without max_length option' do
126
+ record = SlugWithoutMaxLengthRspecModel.new(name: 'Hello' * 100)
147
127
  record.simple_slug_generate
148
128
  expect(record.slug.length).to eq 500
149
129
  end
150
130
  end
151
131
 
152
- describe 'add_validation' do
153
- it 'skip validation' do
154
- expect(SlugGenerationRspecModelWithoutValidation.validators_on(:slug)).to be_blank
132
+ describe 'validation' do
133
+ it 'optionally skip validations' do
134
+ expect(SlugWithoutValidationRspecModel.validators_on(:slug)).to be_blank
155
135
  end
156
136
  end
157
137
 
158
- describe 'callback_type' do
159
- it 'skip callback' do
160
- expect(SlugGenerationRspecModelWithoutCallback.new).not_to receive(:should_generate_new_slug?)
138
+ describe 'callbacks' do
139
+ it 'optionally skip callback' do
140
+ expect(SlugWithoutCallbackRspecModel.new).not_to receive(:should_generate_new_slug?)
161
141
  end
162
142
  end
163
143
 
164
144
  describe 'localized' do
165
- before do
166
- allow_any_instance_of(SlugGenerationRspecModelLocalized).to receive(:simple_slug_exists?).and_return(false)
167
- end
168
-
169
145
  it 'generate slug for locales' do
170
- record = SlugGenerationRspecModelLocalized.create(name: 'Hello', name_en: 'Hello en')
146
+ record = SlugLocalizedRspecModel.create(name: 'Hello')
171
147
  expect(record.slug).to eq 'hello'
172
148
  expect(record.slug_en).to eq 'hello-en'
173
149
  end
174
150
 
175
151
  describe '#should_generate_new_slug?' do
176
- it 'keep generated slugs' do
177
- record = SlugGenerationRspecModelLocalized.create(name: 'Hello', name_en: 'Hello en')
178
- record.name = 'bye'
179
- record.slug_en = nil
180
- record.name_en = 'Bye en'
181
- expect{ record.save }.not_to change{ record.slug }
152
+ it 'keep slug when present' do
153
+ record = SlugLocalizedRspecModel.create(name: 'Hello')
154
+ expect{ record.update(name: 'Bye') }.not_to change{ record.slug }
182
155
  end
183
156
 
184
- it 'generate slug for locales with blank slug' do
185
- record = SlugGenerationRspecModelLocalized.create(name: 'Hello', name_en: 'Hello en')
157
+ it 'generate slug when blank' do
158
+ record = SlugLocalizedRspecModel.create(name: 'Hello')
186
159
  record.name = 'bye'
187
160
  record.slug_en = nil
188
- record.name_en = 'Bye en'
189
161
  expect{ record.save }.to change{ record.slug_en }.to('bye-en')
190
162
  end
191
163
  end
192
164
 
193
165
  describe '#to_param' do
194
- it 'generate not localized for default locale' do
195
- record = SlugGenerationRspecModelLocalized.create(name: 'Hello', name_en: 'Hello en')
166
+ it 'use unlocalized column for default locale' do
167
+ record = SlugLocalizedRspecModel.create(name: 'Hello')
196
168
  expect(record.to_param).to eq 'hello'
197
169
  end
198
170
 
199
- it 'generate localized' do
200
- record = SlugGenerationRspecModelLocalized.create(name: 'Hello', name_en: 'Hello en')
171
+ it 'use localized column for non-default locales' do
172
+ record = SlugLocalizedRspecModel.create(name: 'Hello')
201
173
  I18n.with_locale(:en) do
202
174
  expect(record.to_param).to eq 'hello-en'
203
175
  end
204
176
  end
205
177
  end
206
178
 
207
- describe '#simple_slug_find' do
208
- it 'use default slug column with default locale' do
209
- record = SlugGenerationRspecModelLocalized.create(name: 'Hello', name_en: 'Hello en')
210
- expect(SlugGenerationRspecModelLocalized).to receive(:find_by!).with('slug' => 'hello').and_return(record)
211
- SlugGenerationRspecModelLocalized.simple_slug_find('hello')
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
212
183
  end
213
184
 
214
- it 'use localized slug column' do
215
- record = SlugGenerationRspecModelLocalized.create(name: 'Hello', name_en: 'Hello en')
216
- expect(SlugGenerationRspecModelLocalized).to receive(:find_by!).with('slug_en' => 'hello-en').and_return(record)
217
- I18n.with_locale(:en) { SlugGenerationRspecModelLocalized.simple_slug_find('hello-en') }
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
218
190
  end
219
191
  end
220
192
  end
@@ -1,48 +1,44 @@
1
+ require 'sqlite3'
1
2
  require 'active_record'
2
3
  require 'i18n'
3
4
  require 'active_support/core_ext'
4
5
  require 'byebug'
5
6
  require 'simple_slug'
6
7
 
7
- # just silence warning
8
8
  I18n.enforce_available_locales = false
9
9
  I18n.default_locale = :uk
10
10
 
11
- class RspecActiveModelBase
12
- include ActiveModel::Model
13
- include ActiveModel::AttributeMethods
14
- extend ActiveModel::Callbacks
15
-
16
- include SimpleSlug::ModelAddition
17
-
18
- define_model_callbacks :validation, :save, :destroy
19
-
20
- attr_accessor :id, :slug, :name, :created_at
21
- alias_method :slug_was, :slug
22
-
23
- def self.create(attributes, *)
24
- record = new(attributes)
25
- record.save
26
- record
27
- end
28
-
29
- def save
30
- run_callbacks(:validation) { run_callbacks(:save) { } }
31
- end
32
-
33
- def destroy
34
- run_callbacks(:destroy) { @destroyed = true }
35
- end
36
-
37
- def persisted?
38
- 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
39
38
  end
39
+ end
40
40
 
41
- def slug_changed?
42
- slug.present?
43
- end
44
41
 
45
- def destroyed?
46
- !!@destroyed
47
- end
48
- 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.3.5
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Alex Leschenko
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-04 00:00:00.000000000 Z
11
+ date: 2020-01-03 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: '5.3'
22
+ version: '6.1'
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: '5.3'
32
+ version: '6.1'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: i18n
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -86,6 +86,20 @@ dependencies:
86
86
  - - ">="
87
87
  - !ruby/object:Gem::Version
88
88
  version: '0'
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'
89
103
  description: Simple friendly url generator for ActiveRecord with history."
90
104
  email:
91
105
  - leschenko.al@gmail.com
@@ -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
@@ -129,8 +144,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
129
144
  - !ruby/object:Gem::Version
130
145
  version: '0'
131
146
  requirements: []
132
- rubyforge_project:
133
- rubygems_version: 2.6.14
147
+ rubygems_version: 3.0.6
134
148
  signing_key:
135
149
  specification_version: 4
136
150
  summary: Friendly url generator with history.