slugable 0.0.1

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/.gitignore ADDED
@@ -0,0 +1,18 @@
1
+ *.gem
2
+ *.rbc
3
+ .bundle
4
+ .config
5
+ .yardoc
6
+ Gemfile.lock
7
+ InstalledFiles
8
+ _yardoc
9
+ coverage
10
+ doc/
11
+ lib/bundler/man
12
+ pkg
13
+ rdoc
14
+ spec/reports
15
+ test/tmp
16
+ test/version_tmp
17
+ tmp
18
+ .idea/
data/.rspec ADDED
@@ -0,0 +1 @@
1
+ --color
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in slugable.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2012 Miroslav Hettes
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,80 @@
1
+ # Slugable
2
+
3
+ * adds support for seo friendly url
4
+ * one helper method has_slug
5
+ * support for ancestry models 'https://github.com/stefankroes/ancestry'
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ gem 'slugable'
12
+
13
+ And then execute:
14
+
15
+ $ bundle
16
+
17
+ Or install it yourself as:
18
+
19
+ $ gem install slugable
20
+
21
+ ## Usage
22
+
23
+ in model use method has_slug
24
+
25
+
26
+ class Item < ActiveRecord::Base
27
+ attr_accessor :name, :slug
28
+
29
+ has_slug # default :from => :name, :to => :slug
30
+ end
31
+
32
+ # then in code
33
+ item = Item.create!(:name => "my name is")
34
+ item.slug # => "my-name-is"
35
+
36
+ item.to_slug # => "my-name-is"
37
+
38
+ you can override defaults by passing hash
39
+
40
+
41
+ class Page < ActiveRecord::Base
42
+ attr_accessor :title, :seo_url
43
+
44
+ has_slug :from => :title, :to => :seo_url
45
+ end
46
+
47
+ # then in code
48
+ page = Page.create!(:title => "my name is", :seo_url => "my url")
49
+ page.seo_url # => "my-url"
50
+ page.to_seo_url # => "my-url"
51
+
52
+ if you have model with ancestry gem 'https://github.com/stefankroes/ancestry'
53
+
54
+
55
+ class Category < ActiveRecord::Base
56
+ attr_accessor :name, :slug
57
+
58
+ has_ancestry
59
+ has_slug
60
+ end
61
+
62
+ # then in code
63
+ root = Category.create!(:name => "root", :slug => "root")
64
+ root.slug # => "root"
65
+ root.to_slug # => ["root"]
66
+
67
+ child = Category.new(:name => "child", :slug => "child")
68
+ child.parent = root
69
+ child.save!
70
+
71
+ child.slug # => "child"
72
+ child.to_slug # => ["root", "child"]
73
+
74
+ ## Contributing
75
+
76
+ 1. Fork it
77
+ 2. Create your feature branch (`git checkout -b my-new-feature`)
78
+ 3. Commit your changes (`git commit -am 'Add some feature'`)
79
+ 4. Push to the branch (`git push origin my-new-feature`)
80
+ 5. Create new Pull Request
data/Rakefile ADDED
@@ -0,0 +1 @@
1
+ require "bundler/gem_tasks"
data/changelog.md ADDED
@@ -0,0 +1,6 @@
1
+ # 0.0.1
2
+ ## added
3
+ * init version from real project
4
+ * support for storing seo friendly url
5
+ * caching slug for ancestry models
6
+ * all covered with tests
data/db/schema.rb ADDED
@@ -0,0 +1,25 @@
1
+ ActiveRecord::Schema.define do
2
+ create_table "items", :force => true do |t|
3
+ t.string "name"
4
+ t.string "title"
5
+ t.string "slug"
6
+ t.string "seo_url"
7
+ t.datetime "created_at", :null => false
8
+ t.datetime "updated_at", :null => false
9
+ end
10
+
11
+ create_table "pages", :force => true do |t|
12
+ t.string "title"
13
+ t.string "seo_path"
14
+ t.datetime "created_at", :null => false
15
+ t.datetime "updated_at", :null => false
16
+ end
17
+
18
+ create_table "categories", :force => true do |t|
19
+ t.string "name"
20
+ t.string "ancestry"
21
+ t.string "slug"
22
+ t.datetime "created_at", :null => false
23
+ t.datetime "updated_at", :null => false
24
+ end
25
+ end
@@ -0,0 +1,129 @@
1
+ module Slugable
2
+ module HasSlug
3
+ #
4
+ # USAGE
5
+ # generate before save filter for filling slug from name attribute, and parameterize slug attribute
6
+ # you can change default columns by passing :from and :to attributes
7
+ #
8
+ # it also generate method to_slug (depanding od :to param), which generate slug url for link_path
9
+ #
10
+ # has_slug # generate to_slug
11
+ # has_slug :from => :title # generate to_slug
12
+ # has_slug :to => :seo_url # generate to_url
13
+ # has_slug :from => :name, :to => :slug # generate to_slug
14
+ #
15
+ def has_slug(options={})
16
+ defaults = {:from => :name, :to => :slug}
17
+ options.reverse_merge!(defaults)
18
+ from = options.delete(:from)
19
+ to = options.delete(:to)
20
+ before_save :"fill_slug_from_#{from}_to_#{to}", :"format_slug_from_#{from}_to_#{to}"
21
+ after_save :"update_my_#{to}_cache"
22
+
23
+ # generate this
24
+ #
25
+ # def fill_slug
26
+ # self.slug = name unless slug.present?
27
+ # end
28
+ code =<<-method
29
+ def fill_slug_from_#{from}_to_#{to}
30
+ self.#{to} = #{from} unless #{to}.present?
31
+ end
32
+ method
33
+ class_eval(code)
34
+
35
+ # generate this
36
+ #
37
+ # def format_slug
38
+ # self.slug = slug.parameterize
39
+ # end
40
+ code =<<-method
41
+ def format_slug_from_#{from}_to_#{to}
42
+ self.#{to} = #{to}.parameterize
43
+ end
44
+ method
45
+ class_eval(code)
46
+
47
+ # generate this
48
+ # def update_my_slug_cache
49
+ # @@all ||= {}
50
+ # @@all[id] = send(:slug)
51
+ # end
52
+ code =<<-method
53
+ def update_my_#{to}_cache
54
+ @@all ||= {}
55
+ @@all[id] = send(:#{to})
56
+ end
57
+ method
58
+ class_eval(code)
59
+
60
+ # generate this
61
+ #
62
+ # def self.all_slugs
63
+ # slug_column = :slug
64
+ # @@all ||= self.all.map_to_hash{|slug_element| {slug_element.id => slug_element.send(slug_column)}}
65
+ # end
66
+ code =<<-method
67
+ def self.all_#{to}s
68
+ @@all ||= self.all.map_to_hash{|slug_element| {slug_element.id => slug_element.send(:#{to})}}
69
+ end
70
+ method
71
+ class_eval(code)
72
+
73
+ # generate this
74
+ #
75
+ # def self.clear_cached_slugs
76
+ # @@all = nil
77
+ # end
78
+ code =<<-method
79
+ def self.clear_cached_#{to}s
80
+ @@all = nil
81
+ end
82
+ method
83
+ class_eval(code)
84
+
85
+ # generate this
86
+ #
87
+ # def self.cached_slug(id)
88
+ # all_slugs[id]
89
+ # end
90
+ code =<<-method
91
+ def self.cached_#{to}(id)
92
+ all_#{to}s[id].to_s
93
+ end
94
+ method
95
+ class_eval(code)
96
+
97
+ # generate this
98
+ #
99
+ # def to_slug
100
+ # 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
+ # ""
104
+ # else
105
+ # slug
106
+ # end
107
+ # else
108
+ # send(:slug)
109
+ # end
110
+ # end
111
+ code =<<-method
112
+ def to_#{to}
113
+ 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
+ ""
117
+ else
118
+ slugs
119
+ end
120
+ else
121
+ send(:#{to})
122
+ end
123
+ end
124
+ method
125
+ class_eval(code)
126
+ end
127
+
128
+ end
129
+ end
@@ -0,0 +1,9 @@
1
+ module Slugable
2
+ class Railtie < Rails::Railtie
3
+ initializer "slugable.active_record_ext" do
4
+ ActiveSupport.on_load(:active_record) do
5
+ ActiveRecord::Base.send :extend, Slugable::HasSlug
6
+ end
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,3 @@
1
+ module Slugable
2
+ VERSION = "0.0.1"
3
+ end
data/lib/slugable.rb ADDED
@@ -0,0 +1,6 @@
1
+ require "active_record"
2
+ require "active_support"
3
+ require "wnm_support"
4
+ require "slugable/version"
5
+ require "slugable/has_slug"
6
+ require "slugable/railtie" if defined?(Rails)
data/slugable.gemspec ADDED
@@ -0,0 +1,28 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'slugable/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "slugable"
8
+ gem.version = Slugable::VERSION
9
+ gem.authors = ["Miroslav Hettes"]
10
+ gem.email = ["hettes@webynamieru.sk"]
11
+ gem.description = %q{Add dsl method for automatic storing seo friendly url in database column}
12
+ gem.summary = %q{Storing seo friendly url in column}
13
+ gem.homepage = "https://github.com/mirrec/slugable"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
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"
23
+
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"
28
+ end
@@ -0,0 +1,147 @@
1
+ require "spec_helper"
2
+
3
+ ActiveRecord::Base.send :extend, Slugable::HasSlug
4
+
5
+ class Item < ActiveRecord::Base
6
+ attr_accessor :name, :slug
7
+
8
+ has_slug
9
+ end
10
+
11
+ class Page < ActiveRecord::Base
12
+ attr_accessor :title, :seo_url
13
+
14
+ has_slug :from => :title, :to => :seo_url
15
+ end
16
+
17
+ class Category < ActiveRecord::Base
18
+ attr_accessor :name, :slug
19
+
20
+ has_ancestry
21
+ has_slug
22
+ end
23
+
24
+
25
+ describe Slugable::HasSlug do
26
+ before(:each) do
27
+ Category.clear_cached_slugs
28
+ end
29
+
30
+ context "default options" do
31
+ it "should create fill_slug_from_name_to_slug" do
32
+ Item.new.should respond_to :fill_slug_from_name_to_slug
33
+ end
34
+
35
+ it "should create format_slug_from_name_to_slug" do
36
+ Item.new.should respond_to :format_slug_from_name_to_slug
37
+ end
38
+
39
+ it "should fill in slug parameter from attribute name and parametrize it" do
40
+ item = Item.create!(:name => "my name is")
41
+ item.slug.should eq "my-name-is"
42
+ end
43
+
44
+ it "should only parametrize slug attribute if slug is present" do
45
+ item = Item.create!(:name => "my name is", :slug => "my url")
46
+ item.slug.should eq "my-url"
47
+ end
48
+ end
49
+
50
+ context "given options" do
51
+ it "should create fill_slug_from_title_to_seo_url" do
52
+ Page.new.should respond_to :fill_slug_from_title_to_seo_url
53
+ end
54
+
55
+ it "should create format_slug_from_title_to_seo_url" do
56
+ Page.new.should respond_to :format_slug_from_title_to_seo_url
57
+ end
58
+
59
+ it "should fill in slug parameter from attribute name and parametrize it" do
60
+ page = Page.create!(:title => "my name is")
61
+ page.seo_url.should eq "my-name-is"
62
+ end
63
+
64
+ it "should only parametrize slug attribute if slug is present" do
65
+ page = Page.create!(:title => "my name is", :seo_url => "my url")
66
+ page.seo_url.should eq "my-url"
67
+ end
68
+ end
69
+
70
+ describe "to_slug" do
71
+ context "default options" do
72
+ it "should define mehtod to_seo_url" do
73
+ Item.new.should respond_to :to_slug
74
+ end
75
+
76
+ it "should return slug in string" do
77
+ item = Item.create!(:name => "my name is", :slug => "my-url")
78
+ item.to_slug.should eq "my-url"
79
+ end
80
+ end
81
+
82
+ context "given options" do
83
+ it "should define mehtod to_seo_url" do
84
+ Page.new.should respond_to :to_seo_url
85
+ end
86
+
87
+ it "should return slug in string" do
88
+ page = Page.create!(:title => "my name is", :seo_url => "my-url")
89
+ page.to_seo_url.should eq "my-url"
90
+ end
91
+ end
92
+
93
+ context "ancestry model" do
94
+ it "should return array of slugs" do
95
+ root = Category.create!(:name => "root", :slug => "root")
96
+ child = Category.new(:name => "child", :slug => "child")
97
+ child.parent = root
98
+ child.save!
99
+
100
+ child.to_slug.should eq ["root", "child"]
101
+ end
102
+ end
103
+ end
104
+
105
+ describe "ancestry methods" do
106
+ describe "all_slugs" do
107
+ it "ancestry model class should respond to all_slugs" do
108
+ Category.should respond_to :all_slugs
109
+ end
110
+
111
+ it "should return all slugs in hash where key is id and value is slug by itself" do
112
+ root = Category.create!(:name => "root", :slug => "root")
113
+ child = Category.new(:name => "child", :slug => "child")
114
+ child.parent = root
115
+ child.save!
116
+
117
+ Category.all_slugs.should eq({root.id => "root", child.id => "child"})
118
+ end
119
+
120
+ it "should update slug cache after save" do
121
+ root = Category.create!(:name => "root", :slug => "root")
122
+ Category.all_slugs.should eq({root.id => "root"})
123
+
124
+ child = Category.new(:name => "child", :slug => "child")
125
+ child.save! # force save
126
+ Category.all_slugs.should eq({root.id => "root", child.id => "child"})
127
+
128
+ child.slug = "updated-child"
129
+ child.save # standard save
130
+ Category.all_slugs.should eq({root.id => "root", child.id => "updated-child"})
131
+ end
132
+ end
133
+
134
+ describe "clear_cached_slugs" do
135
+ it "should clear cache for slug" do
136
+ root = Category.create!(:name => "root", :slug => "root")
137
+ Category.all_slugs.should eq({root.id => "root"})
138
+
139
+ root.destroy
140
+ Category.all_slugs.should eq({root.id => "root"})
141
+
142
+ Category.clear_cached_slugs
143
+ Category.all_slugs.should eq({})
144
+ end
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,17 @@
1
+ require "slugable"
2
+ require "sqlite3"
3
+ require "ancestry"
4
+
5
+ ActiveRecord::Base.establish_connection adapter: "sqlite3", database: ":memory:"
6
+
7
+ load "db/schema.rb"
8
+
9
+ RSpec.configure do |config|
10
+ config.around do |example|
11
+ ActiveRecord::Base.transaction do
12
+ example.run
13
+ raise ActiveRecord::Rollback
14
+ end
15
+ end
16
+ end
17
+
metadata ADDED
@@ -0,0 +1,174 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: slugable
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Miroslav Hettes
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2012-10-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: activerecord
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '3.0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: '3.0'
30
+ - !ruby/object:Gem::Dependency
31
+ name: activesupport
32
+ requirement: !ruby/object:Gem::Requirement
33
+ none: false
34
+ requirements:
35
+ - - ! '>='
36
+ - !ruby/object:Gem::Version
37
+ version: '3.0'
38
+ type: :runtime
39
+ prerelease: false
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: '3.0'
46
+ - !ruby/object:Gem::Dependency
47
+ name: wnm_support
48
+ requirement: !ruby/object:Gem::Requirement
49
+ none: false
50
+ requirements:
51
+ - - ~>
52
+ - !ruby/object:Gem::Version
53
+ version: 0.0.4
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - ~>
60
+ - !ruby/object:Gem::Version
61
+ version: 0.0.4
62
+ - !ruby/object:Gem::Dependency
63
+ name: rspec
64
+ requirement: !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ~>
68
+ - !ruby/object:Gem::Version
69
+ version: 2.11.0
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ none: false
74
+ requirements:
75
+ - - ~>
76
+ - !ruby/object:Gem::Version
77
+ version: 2.11.0
78
+ - !ruby/object:Gem::Dependency
79
+ name: rake
80
+ requirement: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ~>
84
+ - !ruby/object:Gem::Version
85
+ version: 0.9.2.2
86
+ type: :development
87
+ prerelease: false
88
+ version_requirements: !ruby/object:Gem::Requirement
89
+ none: false
90
+ requirements:
91
+ - - ~>
92
+ - !ruby/object:Gem::Version
93
+ version: 0.9.2.2
94
+ - !ruby/object:Gem::Dependency
95
+ name: sqlite3
96
+ requirement: !ruby/object:Gem::Requirement
97
+ none: false
98
+ requirements:
99
+ - - ~>
100
+ - !ruby/object:Gem::Version
101
+ version: 1.3.6
102
+ type: :development
103
+ prerelease: false
104
+ version_requirements: !ruby/object:Gem::Requirement
105
+ none: false
106
+ requirements:
107
+ - - ~>
108
+ - !ruby/object:Gem::Version
109
+ version: 1.3.6
110
+ - !ruby/object:Gem::Dependency
111
+ name: ancestry
112
+ requirement: !ruby/object:Gem::Requirement
113
+ none: false
114
+ requirements:
115
+ - - ~>
116
+ - !ruby/object:Gem::Version
117
+ version: 1.3.0
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ none: false
122
+ requirements:
123
+ - - ~>
124
+ - !ruby/object:Gem::Version
125
+ version: 1.3.0
126
+ description: Add dsl method for automatic storing seo friendly url in database column
127
+ email:
128
+ - hettes@webynamieru.sk
129
+ executables: []
130
+ extensions: []
131
+ extra_rdoc_files: []
132
+ files:
133
+ - .gitignore
134
+ - .rspec
135
+ - Gemfile
136
+ - LICENSE.txt
137
+ - README.md
138
+ - Rakefile
139
+ - changelog.md
140
+ - db/schema.rb
141
+ - lib/slugable.rb
142
+ - lib/slugable/has_slug.rb
143
+ - lib/slugable/railtie.rb
144
+ - lib/slugable/version.rb
145
+ - slugable.gemspec
146
+ - spec/slugable/has_slug_spec.rb
147
+ - spec/spec_helper.rb
148
+ homepage: https://github.com/mirrec/slugable
149
+ licenses: []
150
+ post_install_message:
151
+ rdoc_options: []
152
+ require_paths:
153
+ - lib
154
+ required_ruby_version: !ruby/object:Gem::Requirement
155
+ none: false
156
+ requirements:
157
+ - - ! '>='
158
+ - !ruby/object:Gem::Version
159
+ version: '0'
160
+ required_rubygems_version: !ruby/object:Gem::Requirement
161
+ none: false
162
+ requirements:
163
+ - - ! '>='
164
+ - !ruby/object:Gem::Version
165
+ version: '0'
166
+ requirements: []
167
+ rubyforge_project:
168
+ rubygems_version: 1.8.24
169
+ signing_key:
170
+ specification_version: 3
171
+ summary: Storing seo friendly url in column
172
+ test_files:
173
+ - spec/slugable/has_slug_spec.rb
174
+ - spec/spec_helper.rb