slugable 0.0.2 → 0.0.3

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.
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