slugable 0.0.2 → 0.0.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  * adds support for seo friendly url
4
4
  * one helper method has_slug
5
5
  * support for ancestry models 'https://github.com/stefankroes/ancestry'
6
+ * be default cache ancestry models url, can be changed
6
7
 
7
8
  ## Installation
8
9
 
@@ -22,11 +23,10 @@ Or install it yourself as:
22
23
 
23
24
  in model use method has_slug
24
25
 
25
-
26
26
  class Item < ActiveRecord::Base
27
27
  attr_accessor :name, :slug
28
28
 
29
- has_slug # default :from => :name, :to => :slug
29
+ has_slug # default :from => :name, :to => :slug, :formatter => :parameterize, :cache_tree => true
30
30
  end
31
31
 
32
32
  # then in code
@@ -35,13 +35,25 @@ in model use method has_slug
35
35
 
36
36
  item.to_slug # => "my-name-is"
37
37
 
38
+ item.slug = "new-slug
39
+
40
+ item.to_slug_was # => "my-name-is"
41
+ item.to_slug_will # => "new-slug"
42
+ item.to_slug # => "new-slug"
43
+
38
44
  you can override defaults by passing hash
39
45
 
40
46
 
41
47
  class Page < ActiveRecord::Base
42
48
  attr_accessor :title, :seo_url
43
49
 
44
- has_slug :from => :title, :to => :seo_url
50
+ has_slug :from => :title, :to => :seo_url, :formatter => :my_style
51
+ end
52
+
53
+ class String
54
+ def my_style
55
+ self.parameterize
56
+ end
45
57
  end
46
58
 
47
59
  # then in code
@@ -71,6 +83,30 @@ if you have model with ancestry gem 'https://github.com/stefankroes/ancestry'
71
83
  child.slug # => "child"
72
84
  child.to_slug # => ["root", "child"]
73
85
 
86
+ branch = Category.create!(:name => "branch", :slug => "branch")
87
+ child.parent = branch
88
+ child.slug = "renamed"
89
+
90
+ child.to_slug_was # => ["root", "child"]
91
+ child.to_slug_will # => ["branch", "renamed"]
92
+
93
+ child.to_slug # => ["root", "child"]
94
+ child.save!
95
+ child.to_slug # => ["branch", "renamed"]
96
+
97
+ ## configuration
98
+
99
+ By default all ancestry structure are cached to prevent useless calls to fetch same record from database just for slug values.
100
+ You can pass :cache_tree option to disable it like this.
101
+
102
+
103
+ class Category < ActiveRecord::Base
104
+ attr_accessor :name, :slug
105
+
106
+ has_ancestry
107
+ has_slug :cache_tree => false
108
+ end
109
+
74
110
  ## Contributing
75
111
 
76
112
  1. Fork it
data/changelog.md CHANGED
@@ -1,4 +1,18 @@
1
- # 0.0.2
1
+ # 0.0.3 (March 04, 2013)
2
+ ## added
3
+ * config for allowing or disabling caching
4
+ * `to_slug_was` for getting old values of object `to_slug`
5
+ * `to_slug_will` for getting future values of object `to_slug`
6
+ * options for specifying string formatting method
7
+ * options for enabling or disabling cacing slugs for tree
8
+
9
+ # 0.0.3.beta (December 27, 2012)
10
+ ## changed
11
+ * skip cache in tree
12
+ ## fixed
13
+ * tests and schema for appropriate testing
14
+
15
+ # 0.0.2 (December 5, 2012)
2
16
  ## fixed
3
17
  * fill in slug from name parameter if slug.parameterize is blank
4
18
 
data/db/schema.rb CHANGED
@@ -10,7 +10,7 @@ ActiveRecord::Schema.define do
10
10
 
11
11
  create_table "pages", :force => true do |t|
12
12
  t.string "title"
13
- t.string "seo_path"
13
+ t.string "seo_url"
14
14
  t.datetime "created_at", :null => false
15
15
  t.datetime "updated_at", :null => false
16
16
  end
@@ -22,4 +22,19 @@ ActiveRecord::Schema.define do
22
22
  t.datetime "created_at", :null => false
23
23
  t.datetime "updated_at", :null => false
24
24
  end
25
+
26
+ create_table "products", :force => true do |t|
27
+ t.string "name"
28
+ t.string "slug"
29
+ t.datetime "created_at", :null => false
30
+ t.datetime "updated_at", :null => false
31
+ end
32
+
33
+ create_table "tree_items", :force => true do |t|
34
+ t.string "name"
35
+ t.string "ancestry"
36
+ t.string "slug"
37
+ t.datetime "created_at", :null => false
38
+ t.datetime "updated_at", :null => false
39
+ end
25
40
  end
@@ -13,10 +13,12 @@ module Slugable
13
13
  # has_slug :from => :name, :to => :slug # generate to_slug
14
14
  #
15
15
  def has_slug(options={})
16
- defaults = {:from => :name, :to => :slug}
16
+ defaults = {:from => :name, :to => :slug, :formatter => :parameterize, :cache_tree => true}
17
17
  options.reverse_merge!(defaults)
18
18
  from = options.delete(:from)
19
19
  to = options.delete(:to)
20
+ formatter = options.delete(:formatter)
21
+ cache_tree = options.delete(:cache_tree)
20
22
  before_save :"fill_slug_from_#{from}_to_#{to}", :"format_slug_from_#{from}_to_#{to}"
21
23
  after_save :"update_my_#{to}_cache"
22
24
 
@@ -39,7 +41,7 @@ module Slugable
39
41
  # end
40
42
  code =<<-method
41
43
  def format_slug_from_#{from}_to_#{to}
42
- self.#{to} = #{to}.parameterize
44
+ self.#{to} = #{to}.send(:#{formatter})
43
45
  end
44
46
  method
45
47
  class_eval(code)
@@ -98,12 +100,12 @@ module Slugable
98
100
  #
99
101
  # def to_slug
100
102
  # if respond_to?(:path_ids)
101
- # slugs = path_ids.map{|id| self.class.cached_slug(id)}.select{|i| i.size > 0 }
102
- # if slugs.empty?
103
- # ""
103
+ # slugs = if true
104
+ # path_ids.map{|id| self.class.cached_slug(id)}.select{|i| i.size > 0 }
104
105
  # else
105
- # slug
106
+ # path.map{|record| record.send(:"slug")}.select{|i| i.size > 0 }
106
107
  # end
108
+ # slugs.empty? ? "" : slugs
107
109
  # else
108
110
  # send(:slug)
109
111
  # end
@@ -111,19 +113,79 @@ module Slugable
111
113
  code =<<-method
112
114
  def to_#{to}
113
115
  if respond_to?(:path_ids)
114
- slugs = path_ids.map{|id| self.class.cached_#{to}(id)}.select{|i| i.size > 0 }
115
- if slugs.empty?
116
- ""
116
+ slugs = if #{cache_tree}
117
+ path_ids.map{|id| self.class.cached_#{to}(id)}.select{|i| i.size > 0 }
117
118
  else
118
- slugs
119
+ path.map{|record| record.send(:"#{to}")}.select{|i| i.size > 0 }
119
120
  end
121
+ slugs.empty? ? "" : slugs
120
122
  else
121
123
  send(:#{to})
122
124
  end
123
125
  end
124
126
  method
125
127
  class_eval(code)
126
- end
127
128
 
129
+
130
+ # generate this
131
+ #
132
+ # def to_slug_was
133
+ # if respond_to?(:ancestry_was)
134
+ # old_slugs = if true
135
+ # ancestry_was.to_s.split("/").map { |ancestor_id| self.class.cached_slug(ancestor_id.to_i) }
136
+ # else
137
+ # ancestry_was.to_s.split("/").map { |ancestor_id| self.class.find(ancestor_id).send(:slug) }
138
+ # end
139
+ # old_slugs << send(:slug_was)
140
+ # else
141
+ # send(:slug_was)
142
+ # end
143
+ # end
144
+ code =<<-method
145
+ def to_#{to}_was
146
+ if respond_to?(:ancestry_was)
147
+ old_slugs = if #{cache_tree}
148
+ ancestry_was.to_s.split("/").map { |ancestor_id| self.class.cached_#{to}(ancestor_id.to_i) }
149
+ else
150
+ ancestry_was.to_s.split("/").map { |ancestor_id| self.class.find(ancestor_id).send(:#{to}) }
151
+ end
152
+ old_slugs << send(:#{to}_was)
153
+ else
154
+ send(:#{to}_was)
155
+ end
156
+ end
157
+ method
158
+ class_eval(code)
159
+
160
+ # generate this
161
+ #
162
+ # def to_slug_will
163
+ # if respond_to?(:ancestry)
164
+ # old_slugs = if true
165
+ # ancestry.to_s.split("/").map { |ancestor_id| self.class.cached_slug(ancestor_id.to_i) }
166
+ # else
167
+ # ancestry.to_s.split("/").map { |ancestor_id| self.class.find(ancestor_id).send(:slug) }
168
+ # end
169
+ # old_slugs << send(:slug)
170
+ # else
171
+ # send(:slug_was)
172
+ # end
173
+ # end
174
+ code =<<-method
175
+ def to_#{to}_will
176
+ if respond_to?(:ancestry)
177
+ new_slugs = if #{cache_tree}
178
+ ancestry.to_s.split("/").map { |ancestor_id| self.class.cached_#{to}(ancestor_id.to_i) }
179
+ else
180
+ ancestry.to_s.split("/").map { |ancestor_id| self.class.find(ancestor_id).send(:#{to}) }
181
+ end
182
+ new_slugs << send(:#{to}).send(:#{formatter})
183
+ else
184
+ send(:#{to}).send(:#{formatter})
185
+ end
186
+ end
187
+ method
188
+ class_eval(code)
189
+ end
128
190
  end
129
191
  end
@@ -1,3 +1,3 @@
1
1
  module Slugable
2
- VERSION = "0.0.2"
2
+ VERSION = "0.0.3"
3
3
  end
@@ -3,24 +3,37 @@ require "spec_helper"
3
3
  ActiveRecord::Base.send :extend, Slugable::HasSlug
4
4
 
5
5
  class Item < ActiveRecord::Base
6
- attr_accessor :name, :slug
6
+ attr_accessible :name, :slug
7
7
 
8
8
  has_slug
9
9
  end
10
10
 
11
11
  class Page < ActiveRecord::Base
12
- attr_accessor :title, :seo_url
12
+ attr_accessible :title, :seo_url
13
13
 
14
14
  has_slug :from => :title, :to => :seo_url
15
15
  end
16
16
 
17
17
  class Category < ActiveRecord::Base
18
- attr_accessor :name, :slug
18
+ attr_accessible :name, :slug
19
19
 
20
20
  has_ancestry
21
21
  has_slug
22
22
  end
23
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
35
+ end
36
+
24
37
 
25
38
  describe Slugable::HasSlug do
26
39
  before(:each) do
@@ -37,11 +50,14 @@ describe Slugable::HasSlug do
37
50
  end
38
51
 
39
52
  it "should fill in slug parameter from attribute name and parametrize it" do
40
- item = Item.create!(:name => "my name is")
53
+ name = "my name is"
54
+ name.should_receive(:parameterize).and_return("my-name-is")
55
+
56
+ item = Item.create!(:name => name)
41
57
  item.slug.should eq "my-name-is"
42
58
  end
43
59
 
44
- it "should fill in slug from attribute name if parameterize version of slug is blank", :focus => true do
60
+ it "should fill in slug from attribute name if parameterize version of slug is blank" do
45
61
  item = Item.create!(:name => "my name is", :slug => "/")
46
62
  item.slug.should eq "my-name-is"
47
63
  end
@@ -75,6 +91,25 @@ describe Slugable::HasSlug do
75
91
  page = Page.create!(:title => "my name is", :seo_url => "my url")
76
92
  page.seo_url.should eq "my-url"
77
93
  end
94
+
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
101
+
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
108
+
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
112
+ end
78
113
  end
79
114
 
80
115
  describe "to_slug" do
@@ -112,6 +147,82 @@ describe Slugable::HasSlug do
112
147
  end
113
148
  end
114
149
 
150
+ describe "to_slug_was" do
151
+ context "default options" do
152
+ it "should define method to_slug_was" do
153
+ Item.new.should respond_to :to_slug_was
154
+ end
155
+
156
+ it "should return old slug in string" do
157
+ item = Item.create!(:name => "my name is", :slug => "my-url")
158
+ item.slug = "new-slug"
159
+ item.to_slug_was.should eq "my-url"
160
+ end
161
+ end
162
+
163
+ context "given options" do
164
+ it "should define method to_seo_url_was" do
165
+ Page.new.should respond_to :to_seo_url_was
166
+ end
167
+
168
+ it "should return future slug in string" do
169
+ page = Page.create!(:title => "my name is", :seo_url => "my-url")
170
+ page.seo_url = "hello-world"
171
+ page.to_seo_url_was.should eq "my-url"
172
+ end
173
+ end
174
+
175
+ context "ancestry model" do
176
+ it "should return array of old slugs" do
177
+ root = Category.create!(:name => "root", :slug => "root")
178
+ child = Category.new(:name => "child", :slug => "child")
179
+ child.save!
180
+
181
+ child.parent = root
182
+ child.slug = "moved"
183
+ child.to_slug_was.should eq ["child"]
184
+ end
185
+ end
186
+ end
187
+
188
+ describe "to_slug_will" do
189
+ context "default options" do
190
+ it "should define method to_slug_will" do
191
+ Item.new.should respond_to :to_slug_will
192
+ end
193
+
194
+ it "should return future slug in string" do
195
+ item = Item.create!(:name => "my name is", :slug => "my-url")
196
+ item.slug = "new slug"
197
+ item.to_slug_will.should eq "new-slug"
198
+ end
199
+ end
200
+
201
+ context "given options" do
202
+ it "should define method to_seo_url_will" do
203
+ Page.new.should respond_to :to_seo_url_will
204
+ end
205
+
206
+ it "should return slug in string" do
207
+ page = Page.create!(:title => "my name is", :seo_url => "my-url")
208
+ page.seo_url = "hello world"
209
+ page.to_seo_url_will.should eq "hello-world"
210
+ end
211
+ end
212
+
213
+ context "ancestry model" do
214
+ it "should return array of slugs" do
215
+ root = Category.create!(:name => "root", :slug => "root")
216
+ child = Category.new(:name => "child", :slug => "child")
217
+ child.save!
218
+
219
+ child.parent = root
220
+ child.slug = "move d"
221
+ child.to_slug_will.should eq ["root", "move-d"]
222
+ end
223
+ end
224
+ end
225
+
115
226
  describe "ancestry methods" do
116
227
  describe "all_slugs" do
117
228
  it "ancestry model class should respond to all_slugs" do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: slugable
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.2
4
+ version: 0.0.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-12-05 00:00:00.000000000 Z
12
+ date: 2013-03-04 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -157,12 +157,18 @@ required_ruby_version: !ruby/object:Gem::Requirement
157
157
  - - ! '>='
158
158
  - !ruby/object:Gem::Version
159
159
  version: '0'
160
+ segments:
161
+ - 0
162
+ hash: 2198894308197098802
160
163
  required_rubygems_version: !ruby/object:Gem::Requirement
161
164
  none: false
162
165
  requirements:
163
166
  - - ! '>='
164
167
  - !ruby/object:Gem::Version
165
168
  version: '0'
169
+ segments:
170
+ - 0
171
+ hash: 2198894308197098802
166
172
  requirements: []
167
173
  rubyforge_project:
168
174
  rubygems_version: 1.8.24