slugable 0.0.4 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,3 +1,3 @@
1
1
  module Slugable
2
- VERSION = "0.0.4"
2
+ VERSION = '1.0.0'
3
3
  end
@@ -4,25 +4,27 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'slugable/version'
5
5
 
6
6
  Gem::Specification.new do |gem|
7
- gem.name = "slugable"
7
+ gem.name = 'slugable'
8
8
  gem.version = Slugable::VERSION
9
- gem.authors = ["Miroslav Hettes"]
10
- gem.email = ["hettes@webynamieru.sk"]
9
+ gem.authors = ['Miroslav Hettes']
10
+ gem.email = ['hettes@webynamieru.sk']
11
11
  gem.description = %q{Add dsl method for automatic storing seo friendly url in database column}
12
12
  gem.summary = %q{Storing seo friendly url in column}
13
- gem.homepage = "https://github.com/mirrec/slugable"
13
+ gem.homepage = 'https://github.com/mirrec/slugable'
14
14
 
15
15
  gem.files = `git ls-files`.split($/)
16
16
  gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
17
  gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
- gem.require_paths = ["lib"]
18
+ gem.require_paths = ['lib']
19
19
 
20
- gem.add_runtime_dependency "activerecord", ">= 3.0"
21
- gem.add_runtime_dependency "activesupport", ">= 3.0"
22
- gem.add_runtime_dependency "wnm_support", "~> 0.0.4"
20
+ gem.add_runtime_dependency 'activerecord', '>= 3.0', '< 5.0'
23
21
 
24
- gem.add_development_dependency "rspec", "~> 2.11.0"
25
- gem.add_development_dependency "rake", "~> 0.9.2.2"
26
- gem.add_development_dependency "sqlite3", "~> 1.3.6"
27
- gem.add_development_dependency "ancestry", "~> 1.3.0"
22
+ gem.add_development_dependency 'appraisal', '~> 2.1.0'
23
+ gem.add_development_dependency 'rspec', '~> 3.4.0'
24
+ gem.add_development_dependency 'rake', '~> 0.9.2.2'
25
+ gem.add_development_dependency 'sqlite3', '~> 1.3.11'
26
+ gem.add_development_dependency 'ancestry', '>= 1.3.0', '< 3.0'
27
+ gem.add_development_dependency 'pry'
28
+ gem.add_development_dependency 'simplecov'
29
+ gem.add_development_dependency 'codeclimate-test-reporter'
28
30
  end
@@ -0,0 +1,35 @@
1
+ require 'slugable/cache_layer'
2
+ require 'active_support/core_ext/string/inflections'
3
+
4
+ describe Slugable::CacheLayer do
5
+ MyModel = Class.new
6
+
7
+ let(:model) { MyModel }
8
+ let(:cache_storage) { double(:cache_storage) }
9
+
10
+ subject { Slugable::CacheLayer.new(cache_storage, model) }
11
+
12
+ describe '#read_slug' do
13
+ it 'use fetch for reading value for slug from cache storage' do
14
+ allow(cache_storage).to receive(:fetch).with('my_model/slug_column/1').and_return('hello')
15
+
16
+ expect(subject.read_slug(:slug_column, 1)).to eq 'hello'
17
+ end
18
+
19
+ it 'passes block that will be executed if cache storage does not have given value yet' do
20
+ allow(model).to receive(:find).with(1).and_return(double(:record, slug_column: 'hello'))
21
+
22
+ allow(cache_storage).to receive(:fetch).with('my_model/slug_column/1').and_yield
23
+
24
+ expect(subject.read_slug(:slug_column, 1)).to eq 'hello'
25
+ end
26
+ end
27
+
28
+ describe '#update' do
29
+ it 'writes new value to cache storage' do
30
+ expect(cache_storage).to receive(:write).with('my_model/slug_column/1', 'hello')
31
+
32
+ subject.update(:slug_column, 1, 'hello')
33
+ end
34
+ end
35
+ end
@@ -1,280 +1,217 @@
1
- require "spec_helper"
1
+ require 'spec_helper'
2
+ require 'support/hash_cache_storage'
2
3
 
3
- ActiveRecord::Base.send :extend, Slugable::HasSlug
4
+ hash_cache_storage = HashCacheStorage.new
4
5
 
5
- class Item < ActiveRecord::Base
6
- attr_accessible :name, :slug
7
-
8
- has_slug
9
- end
10
-
11
- class Page < ActiveRecord::Base
12
- attr_accessible :title, :seo_url
13
-
14
- has_slug :from => :title, :to => :seo_url
15
- end
16
-
17
- class Category < ActiveRecord::Base
18
- attr_accessible :name, :slug
19
-
20
- has_ancestry
21
- has_slug
22
- end
23
-
24
- class TreeItem < ActiveRecord::Base
25
- attr_accessible :name, :slug
26
-
27
- has_ancestry
28
- has_slug :cache_tree => false
29
- end
30
-
31
- class Product < ActiveRecord::Base
32
- attr_accessible :name, :slug
33
-
34
- has_slug :formatter => :my_formatter
6
+ Slugable.configure do |config|
7
+ config.tree_cache_storage = hash_cache_storage
35
8
  end
36
9
 
10
+ require 'support/set_up_models'
37
11
 
38
12
  describe Slugable::HasSlug do
39
13
  before(:each) do
40
- Category.clear_cached_slugs
14
+ hash_cache_storage.clear
41
15
  end
42
16
 
43
- context "default options" do
44
- it "should create fill_slug_from_name_to_slug" do
45
- Item.new.should respond_to :fill_slug_from_name_to_slug
46
- end
47
-
48
- it "should create format_slug_from_name_to_slug" do
49
- Item.new.should respond_to :format_slug_from_name_to_slug
50
- end
51
-
52
- it "should fill in slug parameter from attribute name and parametrize it" do
53
- name = "my name is"
54
- name.should_receive(:parameterize).and_return("my-name-is")
55
-
56
- item = Item.create!(:name => name)
57
- item.slug.should eq "my-name-is"
58
- end
59
-
60
- it "should fill in slug from attribute name if parameterize version of slug is blank" do
61
- item = Item.create!(:name => "my name is", :slug => "/")
62
- item.slug.should eq "my-name-is"
17
+ context 'method definitions' do
18
+ context 'default options' do
19
+ it 'creates all needed methods for slug' do
20
+ record = FlatItem.new
21
+ expect(record).to respond_to :slug_builder_for_slug
22
+ expect(record).to respond_to :prepare_slug_in_slug
23
+ expect(record).to respond_to :to_slug
24
+ expect(record).to respond_to :to_slug_was
25
+ expect(record).to respond_to :to_slug_will
26
+ end
63
27
  end
64
28
 
65
- it "should only parametrize slug attribute if slug is present" do
66
- item = Item.create!(:name => "my name is", :slug => "my url")
67
- item.slug.should eq "my-url"
29
+ context 'option with cache' do
30
+ it 'creates method that updates cache' do
31
+ record = TreeItem.new
32
+ expect(record).to respond_to :update_my_slug_cache
33
+ end
68
34
  end
69
35
  end
70
36
 
71
- context "given options" do
72
- it "should create fill_slug_from_title_to_seo_url" do
73
- Page.new.should respond_to :fill_slug_from_title_to_seo_url
74
- end
37
+ context 'callbacks' do
38
+ context 'default options' do
39
+ it 'fills in slug parameter from attribute apply a parameterize format to it' do
40
+ name = 'my name is'
75
41
 
76
- it "should create format_slug_from_title_to_seo_url" do
77
- Page.new.should respond_to :format_slug_from_title_to_seo_url
78
- end
79
-
80
- it "should fill in slug parameter from attribute title and parametrize it" do
81
- page = Page.create!(:title => "my name is")
82
- page.seo_url.should eq "my-name-is"
83
- end
42
+ item = FlatItem.create!(name: name)
43
+ expect(item.slug).to eq 'my-name-is'
44
+ end
84
45
 
85
- it "should fill in slug parameter from attribute title if parameterize version of slug is blank" do
86
- page = Page.create!(:title => "my name is", :seo_url => "/")
87
- page.seo_url.should eq "my-name-is"
88
- end
46
+ it 'fills in slug from attribute name if parameterize version of slug is blank' do
47
+ item = FlatItem.create!(name: 'my name is', slug: '')
48
+ expect(item.slug).to eq 'my-name-is'
49
+ end
89
50
 
90
- it "should only parametrize slug attribute if slug is present" do
91
- page = Page.create!(:title => "my name is", :seo_url => "my url")
92
- page.seo_url.should eq "my-url"
51
+ it 'does not change slug attribute if slug is present' do
52
+ item = FlatItem.create!(name: 'my name is', slug: 'my url')
53
+ expect(item.slug).to eq 'my-url'
54
+ end
93
55
  end
94
56
 
95
- it "should be able to change parameterize method" do
96
- name = "product"
97
- name.should_receive(:my_formatter).and_return("hello")
98
- product = Product.create!(:name => "my name is", :slug => name)
99
- product.slug.should eq "hello"
100
- end
57
+ context 'given options' do
58
+ it 'creates fill_slug_from_title_to_seo_url' do
59
+ expect(FlatPage.new).to respond_to :prepare_slug_in_seo_url
60
+ end
101
61
 
102
- it "should be able to disable tree caching" do
103
- tree_item = TreeItem.create!(:name => "my name is", :parent => TreeItem.create!(:name => "root"))
104
- tree_item.should_receive(:path).and_return([])
105
- tree_item.to_slug
106
- tree_item.should_receive(:path).and_return([])
107
- tree_item.to_slug
62
+ it 'fills in slug parameter from attribute title and parametrize it' do
63
+ page = FlatPage.create!(title: 'my name is')
64
+ expect(page.seo_url).to eq 'my-name-is'
65
+ end
108
66
 
109
- tree_item = Category.create!(:name => "my name is", :parent => Category.create!(:name => "root"))
110
- tree_item.should_not_receive(:path)
111
- tree_item.to_slug
67
+ it 'fills in slug parameter and use custom formatter' do
68
+ product = FlatProduct.create!(name: 'my name is', slug: 'product')
69
+ expect(product.slug).to eq 'hello-all-the-time'
70
+ end
112
71
  end
113
72
  end
114
73
 
115
- describe "to_slug" do
116
- context "default options" do
117
- it "should define method to_seo_url" do
118
- Item.new.should respond_to :to_slug
74
+ describe '#to_slug' do
75
+ context 'default options' do
76
+ it 'defines to_slug method' do
77
+ expect(FlatItem.new).to respond_to :to_slug
119
78
  end
120
79
 
121
- it "should return slug in string" do
122
- item = Item.create!(:name => "my name is", :slug => "my-url")
123
- item.to_slug.should eq "my-url"
80
+ it 'returns slug in string' do
81
+ item = FlatItem.create!(name: 'my name is', slug: 'my-url')
82
+ expect(item.to_slug).to eq 'my-url'
124
83
  end
125
84
  end
126
85
 
127
- context "given options" do
128
- it "should define method to_seo_url" do
129
- Page.new.should respond_to :to_seo_url
86
+ context 'given options' do
87
+ it 'defines method to_seo_url' do
88
+ expect(FlatPage.new).to respond_to :to_seo_url
130
89
  end
131
90
 
132
- it "should return slug in string" do
133
- page = Page.create!(:title => "my name is", :seo_url => "my-url")
134
- page.to_seo_url.should eq "my-url"
91
+ it 'returns slug in string' do
92
+ page = FlatPage.create!(title: 'my name is', seo_url: 'my-url')
93
+ expect(page.to_seo_url).to eq 'my-url'
94
+ end
95
+
96
+ it 'returns result from custom to_slug_builder' do
97
+ news = FlatNews.create!(name: 'news')
98
+ expect(news.to_slug).to eq "to_slug_#{news.id}"
135
99
  end
136
100
  end
137
101
 
138
- context "ancestry model" do
139
- it "should return array of slugs" do
140
- root = Category.create!(:name => "root", :slug => "root")
141
- child = Category.new(:name => "child", :slug => "child")
102
+ context 'tree models' do
103
+ it 'returns array of slugs' do
104
+ root = TreeCategory.create!(name: 'root', slug: 'root')
105
+ child = TreeCategory.new(name: 'child', slug: 'child')
142
106
  child.parent = root
143
107
  child.save!
144
108
 
145
- child.to_slug.should eq ["root", "child"]
109
+ expect(child.to_slug).to eq ['root', 'child']
146
110
  end
147
111
 
148
- it "should skip nil values from slug path" do
149
- root = Category.create!(:name => "root", :slug => "root")
150
- child = Category.new(:name => "child", :slug => "child")
112
+ it 'skips nil values from slug path' do
113
+ root = TreeCategory.create!(name: 'root', slug: 'root')
114
+ child = TreeCategory.new(name: 'child', slug: 'child')
151
115
  child.parent = root
152
116
  child.save!
153
117
 
154
- Category.update_all({:slug => nil}, {:id => root.id})
155
- Category.clear_cached_slugs
118
+ TreeCategory.where(id: root.id).update_all(slug: nil)
119
+ hash_cache_storage.clear
120
+
121
+ expect(child.to_slug).to eq ['child']
122
+ end
156
123
 
157
- child.to_slug.should eq ["child"]
124
+ it 'returns correct results also with caching support' do
125
+ child = TreeItem.create!(slug: 'child', parent: TreeItem.create!(slug: 'root'))
126
+ expect(child.to_slug).to eq ['root', 'child']
127
+ expect(child.to_slug).to eq ['root', 'child']
158
128
  end
159
129
  end
160
130
  end
161
131
 
162
- describe "to_slug_was" do
163
- context "default options" do
164
- it "should define method to_slug_was" do
165
- Item.new.should respond_to :to_slug_was
132
+ describe '#to_slug_was' do
133
+ context 'default options' do
134
+ it 'defines method to_slug_was' do
135
+ expect(FlatItem.new).to respond_to :to_slug_was
166
136
  end
167
137
 
168
- it "should return old slug in string" do
169
- item = Item.create!(:name => "my name is", :slug => "my-url")
170
- item.slug = "new-slug"
171
- item.to_slug_was.should eq "my-url"
138
+ it 'returns old slug in string' do
139
+ item = FlatItem.create!(name: 'my name is', slug: 'my-url')
140
+ item.slug = 'new-slug'
141
+ expect(item.to_slug_was).to eq 'my-url'
172
142
  end
173
143
  end
174
144
 
175
- context "given options" do
176
- it "should define method to_seo_url_was" do
177
- Page.new.should respond_to :to_seo_url_was
145
+ context 'given options' do
146
+ it 'defines method to_seo_url_was' do
147
+ expect(FlatPage.new).to respond_to :to_seo_url_was
178
148
  end
179
149
 
180
- it "should return future slug in string" do
181
- page = Page.create!(:title => "my name is", :seo_url => "my-url")
182
- page.seo_url = "hello-world"
183
- page.to_seo_url_was.should eq "my-url"
150
+ it 'returns future slug in string' do
151
+ page = FlatPage.create!(title: 'my name is', seo_url: 'my-url')
152
+ page.seo_url = 'hello-world'
153
+ expect(page.to_seo_url_was).to eq 'my-url'
154
+ end
155
+
156
+ it 'returns result from custom to_slug_builder' do
157
+ news = FlatNews.create!(name: 'news')
158
+ expect(news.to_slug_was).to eq "to_slug_was_#{news.id}"
184
159
  end
185
160
  end
186
161
 
187
- context "ancestry model" do
188
- it "should return array of old slugs" do
189
- root = Category.create!(:name => "root", :slug => "root")
190
- child = Category.new(:name => "child", :slug => "child")
162
+ context 'tree models' do
163
+ it 'returns array of old slugs' do
164
+ root = TreeCategory.create!(name: 'root', slug: 'root')
165
+ child = TreeCategory.new(name: 'child', slug: 'child')
191
166
  child.save!
192
167
 
193
168
  child.parent = root
194
- child.slug = "moved"
195
- child.to_slug_was.should eq ["child"]
169
+ child.slug = 'moved'
170
+ expect(child.to_slug_was).to eq ['child']
196
171
  end
197
172
  end
198
173
  end
199
174
 
200
- describe "to_slug_will" do
201
- context "default options" do
202
- it "should define method to_slug_will" do
203
- Item.new.should respond_to :to_slug_will
175
+ describe '#to_slug_will' do
176
+ context 'default options' do
177
+ it 'defines method to_slug_will' do
178
+ expect(FlatItem.new).to respond_to :to_slug_will
204
179
  end
205
180
 
206
- it "should return future slug in string" do
207
- item = Item.create!(:name => "my name is", :slug => "my-url")
208
- item.slug = "new slug"
209
- item.to_slug_will.should eq "new-slug"
181
+ it 'returns future slug in string' do
182
+ item = FlatItem.create!(name: 'my name is', slug: 'my-url')
183
+ item.slug = 'new slug'
184
+ expect(item.to_slug_will).to eq 'new-slug'
210
185
  end
211
186
  end
212
187
 
213
- context "given options" do
214
- it "should define method to_seo_url_will" do
215
- Page.new.should respond_to :to_seo_url_will
188
+ context 'given options' do
189
+ it 'defines method to_seo_url_will' do
190
+ expect(FlatPage.new).to respond_to :to_seo_url_will
216
191
  end
217
192
 
218
- it "should return slug in string" do
219
- page = Page.create!(:title => "my name is", :seo_url => "my-url")
220
- page.seo_url = "hello world"
221
- page.to_seo_url_will.should eq "hello-world"
193
+ it 'returns slug in string' do
194
+ page = FlatPage.create!(title: 'my name is', seo_url: 'my-url')
195
+ page.seo_url = 'hello world'
196
+ expect(page.to_seo_url_will).to eq 'hello-world'
222
197
  end
223
- end
224
198
 
225
- context "ancestry model" do
226
- it "should return array of slugs" do
227
- root = Category.create!(:name => "root", :slug => "root")
228
- child = Category.new(:name => "child", :slug => "child")
229
- child.save!
230
-
231
- child.parent = root
232
- child.slug = "move d"
233
- child.to_slug_will.should eq ["root", "move-d"]
199
+ it 'returns result from custom to_slug_builder' do
200
+ news = FlatNews.create!(name: 'news')
201
+ expect(news.to_slug_will).to eq "to_slug_will_#{news.id}"
234
202
  end
235
203
  end
236
- end
237
204
 
238
- describe "ancestry methods" do
239
- describe "all_slugs" do
240
- it "ancestry model class should respond to all_slugs" do
241
- Category.should respond_to :all_slugs
242
- end
243
-
244
- it "should return all slugs in hash where key is id and value is slug by itself" do
245
- root = Category.create!(:name => "root", :slug => "root")
246
- child = Category.new(:name => "child", :slug => "child")
247
- child.parent = root
205
+ context 'tree models' do
206
+ it 'returns array of slugs' do
207
+ root = TreeCategory.create!(name: 'root', slug: 'root')
208
+ child = TreeCategory.new(name: 'child', slug: 'child')
248
209
  child.save!
249
210
 
250
- Category.all_slugs.should eq({root.id => "root", child.id => "child"})
251
- end
252
-
253
- it "should update slug cache after save" do
254
- root = Category.create!(:name => "root", :slug => "root")
255
- Category.all_slugs.should eq({root.id => "root"})
256
-
257
- child = Category.new(:name => "child", :slug => "child")
258
- child.save! # force save
259
- Category.all_slugs.should eq({root.id => "root", child.id => "child"})
260
-
261
- child.slug = "updated-child"
262
- child.save # standard save
263
- Category.all_slugs.should eq({root.id => "root", child.id => "updated-child"})
264
- end
265
- end
266
-
267
- describe "clear_cached_slugs" do
268
- it "should clear cache for slug" do
269
- root = Category.create!(:name => "root", :slug => "root")
270
- Category.all_slugs.should eq({root.id => "root"})
271
-
272
- root.destroy
273
- Category.all_slugs.should eq({root.id => "root"})
274
-
275
- Category.clear_cached_slugs
276
- Category.all_slugs.should eq({})
211
+ child.parent = root
212
+ child.slug = 'move d'
213
+ expect(child.to_slug_will).to eq ['root', 'move-d']
277
214
  end
278
215
  end
279
216
  end
280
- end
217
+ end