permalink 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,78 @@
1
+ has_permalink
2
+ =============
3
+
4
+ Instalation
5
+ -----------
6
+
7
+ You can use I18n-JS as plugin and gem. Choose what's best for you!
8
+
9
+ script/plugin install git://github.com/fnando/has_permalink.git
10
+
11
+ or
12
+ gem install permalink
13
+
14
+ Usage
15
+ -----
16
+
17
+ Add the method call `has_permalink` to your model. Your model should have a `permalink` attribute.
18
+
19
+ class Page < ActiveRecord::Base
20
+ has_permalink :title
21
+ end
22
+
23
+ You can specify the permalink field:
24
+
25
+ class page < ActiveRecord::Base
26
+ has_permalink :title, :to => :title_permalink
27
+ end
28
+
29
+ If you don't want to use `has_permalink`, you can call `'some text'.to_permalink` string method and
30
+ manage the permalink process by yourself.
31
+
32
+ Permalinks are not unique by default. `has_permalink` overrides `to_param` as following:
33
+
34
+ def to_param
35
+ "#{id}-#{permalink}"
36
+ end
37
+
38
+ You can define the `to_param` format:
39
+
40
+ class Page < ActiveRecord::Base
41
+ has_permalink :title, :to_param => %w(id permalink page)
42
+ end
43
+
44
+ The above settings will generate something link `100-some-title-page`. By overriding `to_param` method you don't have to change a thing on your app routes.
45
+
46
+ If you want to generate unique permalink, use the option `:unique`:
47
+
48
+ class Page < ActiveRecord::Base
49
+ has_permalink :title, :unique => true, :to_param => :permalink
50
+ end
51
+
52
+ The permalink is generated using `ActiveSupport::Multibyte::Chars` class; this means that characters will properly replaced from `áéíó` to `aeio`, for instance.
53
+
54
+ The permalink is created when `before_validation` callback is evaluated. This plugin also tries
55
+ to generate a permalink when `before_save` callback is evaluated and the instance has no permalink set.
56
+
57
+ ## License
58
+
59
+ Copyright (c) 2008 Nando Vieira, released under the MIT license
60
+
61
+ Permission is hereby granted, free of charge, to any person obtaining
62
+ a copy of this software and associated documentation files (the
63
+ "Software"), to deal in the Software without restriction, including
64
+ without limitation the rights to use, copy, modify, merge, publish,
65
+ distribute, sublicense, and/or sell copies of the Software, and to
66
+ permit persons to whom the Software is furnished to do so, subject to
67
+ the following conditions:
68
+
69
+ The above copyright notice and this permission notice shall be
70
+ included in all copies or substantial portions of the Software.
71
+
72
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
73
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
74
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
75
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
76
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
77
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
78
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,31 @@
1
+ require 'rake/testtask'
2
+ require 'lib/permalink/version'
3
+
4
+ desc 'Default: run unit tests.'
5
+ task :default => :test
6
+
7
+ desc 'Test the i18n-js plugin.'
8
+ Rake::TestTask.new(:test) do |t|
9
+ t.libs << 'lib'
10
+ t.libs << 'test'
11
+ t.pattern = 'test/**/*_test.rb'
12
+ t.verbose = true
13
+ end
14
+
15
+ begin
16
+ require 'jeweler'
17
+
18
+ JEWEL = Jeweler::Tasks.new do |gem|
19
+ gem.name = "permalink"
20
+ gem.email = "fnando.vieira@gmail.com"
21
+ gem.homepage = "http://github.com/fnando/has_permalink"
22
+ gem.authors = ["Nando Vieira"]
23
+ gem.version = SimplesIdeias::Permalink::Version::STRING
24
+ gem.summary = "ActiveRecord plugin for automatically converting fields to permalinks."
25
+ gem.files = FileList["README.markdown", "init.rb", "{lib,test}/**/*", "Rakefile"]
26
+ end
27
+
28
+ Jeweler::GemcutterTasks.new
29
+ rescue LoadError => e
30
+ puts "[JEWELER] You can't build a gem until you install jeweler with `gem install jeweler`"
31
+ end
data/init.rb ADDED
@@ -0,0 +1 @@
1
+ require "permalink"
@@ -0,0 +1,93 @@
1
+ require "permalink/string_ext"
2
+
3
+ module SimplesIdeias
4
+ module Permalink
5
+ def self.included(base)
6
+ base.extend ClassMethods
7
+
8
+ class << base
9
+ attr_accessor :has_permalink_options
10
+ end
11
+ end
12
+
13
+ module ClassMethods
14
+ # has_permalink :title
15
+ # has_permalink :title, :to => :custom_permalink_field
16
+ # has_permalink :title, :to => :permalink, :to_param => [:id, :permalink]
17
+ # has_permalink :title, :unique => true
18
+ def has_permalink(from, options={})
19
+ options = {
20
+ :to => :permalink,
21
+ :to_param => [:id, :permalink],
22
+ :unique => false
23
+ }.merge(options)
24
+
25
+ self.has_permalink_options = {
26
+ :from_column_name => from,
27
+ :to_column_name => options[:to],
28
+ :to_param => [options[:to_param]].flatten,
29
+ :unique => options[:unique]
30
+ }
31
+
32
+ include SimplesIdeias::Permalink::InstanceMethods
33
+
34
+ before_validation :create_permalink
35
+ before_save :create_permalink
36
+ end
37
+ end
38
+
39
+ module InstanceMethods
40
+ def to_param
41
+ to_param_option = self.class.has_permalink_options[:to_param]
42
+
43
+ to_param_option.compact.collect do |name|
44
+ if respond_to?(name)
45
+ send(name).to_s
46
+ else
47
+ name.to_s
48
+ end
49
+ end.reject(&:blank?).join('-')
50
+ end
51
+
52
+ private
53
+ def next_available_permalink(_permalink)
54
+ the_permalink = _permalink
55
+
56
+ if self.class.has_permalink_options[:unique]
57
+ suffix = 2
58
+
59
+ while self.class.first(:conditions => {to_permalink_name => the_permalink}, :select => self.class.primary_key)
60
+ the_permalink = "#{_permalink}-#{suffix}"
61
+ suffix += 1
62
+ end
63
+ end
64
+
65
+ the_permalink
66
+ end
67
+
68
+ def from_permalink_name
69
+ self.class.has_permalink_options[:from_column_name]
70
+ end
71
+
72
+ def to_permalink_name
73
+ self.class.has_permalink_options[:to_column_name]
74
+ end
75
+
76
+ def from_permalink_value
77
+ read_attribute(from_permalink_name)
78
+ end
79
+
80
+ def to_permalink_value
81
+ read_attribute(to_permalink_name)
82
+ end
83
+
84
+ def create_permalink
85
+ unless from_permalink_value.blank? || !to_permalink_value.blank?
86
+ write_attribute(to_permalink_name, next_available_permalink(from_permalink_value.to_s.to_permalink))
87
+ end
88
+ end
89
+ end
90
+ end
91
+ end
92
+
93
+ ActiveRecord::Base.send(:include, SimplesIdeias::Permalink)
@@ -0,0 +1,11 @@
1
+ class String
2
+ def to_permalink
3
+ str = ActiveSupport::Multibyte::Chars.new(self)
4
+ str = str.normalize(:kd).gsub(/[^\x00-\x7F]/,'').to_s
5
+ str.gsub!(/[^-\w\d]+/sim, "-")
6
+ str.gsub!(/-+/sm, "-")
7
+ str.gsub!(/^-?(.*?)-?$/, '\1')
8
+ str.downcase!
9
+ str
10
+ end
11
+ end
@@ -0,0 +1,10 @@
1
+ module SimplesIdeias
2
+ module Permalink
3
+ module Version
4
+ MAJOR = 0
5
+ MINOR = 1
6
+ PATCH = 0
7
+ STRING = "#{MAJOR}.#{MINOR}.#{PATCH}"
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,3 @@
1
+ class Beer < ActiveRecord::Base
2
+ has_permalink :name
3
+ end
@@ -0,0 +1,3 @@
1
+ class Donut < ActiveRecord::Base
2
+ has_permalink :flavor, :to => :slug, :to_param => [:slug, :id, 'permalink']
3
+ end
@@ -0,0 +1,5 @@
1
+ class Post < ActiveRecord::Base
2
+ has_permalink :title, :unique => true, :to_param => :permalink
3
+
4
+ validates_uniqueness_of :permalink
5
+ end
@@ -0,0 +1,3 @@
1
+ class User < ActiveRecord::Base
2
+ has_permalink :name, :to => :permalink, :to_param => [:id, " ", nil, "\t", :permalink]
3
+ end
@@ -0,0 +1,110 @@
1
+ # encoding: utf-8
2
+ require "test_helper"
3
+
4
+ class PermalinkTest < ActiveSupport::TestCase
5
+ SAMPLES = {
6
+ 'This IS a Tripped out title!!.!1 (well/ not really)' => 'this-is-a-tripped-out-title-1-well-not-really',
7
+ '////// meph1sto r0x ! \\\\\\' => 'meph1sto-r0x',
8
+ 'āčēģīķļņū' => 'acegiklnu',
9
+ '中文測試 chinese text' => 'chinese-text',
10
+ 'some-)()()-ExtRa!/// .data==?> to \/\/test' => 'some-extra-data-to-test',
11
+ 'http://simplesideias.com.br/tags/' => 'http-simplesideias-com-br-tags',
12
+ "Don't Repeat Yourself (DRY)" => 'don-t-repeat-yourself-dry',
13
+ "Text\nwith\nline\n\n\tbreaks" => 'text-with-line-breaks'
14
+ }
15
+
16
+ test "should create permalink using to_permalink" do
17
+ SAMPLES.each do |from, to|
18
+ assert_equal to, from.to_permalink
19
+ end
20
+ end
21
+
22
+ test "should create permalink" do
23
+ beer = create_beer
24
+ assert_equal 'duff', beer.permalink
25
+ end
26
+
27
+ test "should create permalink for custom field" do
28
+ donut = create_donut
29
+ assert_equal 'cream', donut.slug
30
+ end
31
+
32
+ test "should add permalink before_save" do
33
+ beer = Beer.new
34
+ assert_nil beer.permalink
35
+ beer.update_attribute(:name, 'Duff Premium')
36
+ beer.reload
37
+ assert_equal 'duff-premium', beer.permalink
38
+ end
39
+
40
+ test "should create unique permalinks" do
41
+ post1 = create_post(:title => 'Ruby is a beautiful language')
42
+ assert_equal "ruby-is-a-beautiful-language", post1.permalink
43
+
44
+ post2 = create_post(:title => 'Ruby is a beautiful language')
45
+ assert_equal "ruby-is-a-beautiful-language-2", post2.permalink
46
+
47
+ post3 = create_post(:title => 'Ruby is a beautiful language')
48
+ assert_equal "ruby-is-a-beautiful-language-3", post3.permalink
49
+ end
50
+
51
+ test "return to_param for unique permalink" do
52
+ post1 = create_post(:title => 'Ruby')
53
+ assert_equal post1.to_param, 'ruby'
54
+
55
+ post2 = create_post(:title => 'Ruby')
56
+ assert_equal post2.to_param, 'ruby-2'
57
+ end
58
+
59
+ test "should override to_param method" do
60
+ beer = create_beer
61
+ assert_equal "#{beer.id}-#{beer.permalink}", beer.to_param
62
+ end
63
+
64
+ test "should override to_param with custom fields" do
65
+ donut = create_donut
66
+ assert_equal "#{donut.slug}-#{donut.id}-permalink", donut.to_param
67
+ end
68
+
69
+ test "should ignore blank attributes from to_param" do
70
+ user = create_user
71
+ assert_equal "1-john-doe", user.to_param
72
+ end
73
+
74
+ test "should set permalink if permalink is blank" do
75
+ user = create_user(:permalink => " ")
76
+ user.reload
77
+ assert_equal "john-doe", user.permalink
78
+ end
79
+
80
+ test "should keep defined permalink" do
81
+ user = create_beer(:permalink => "jdoe")
82
+ user.reload
83
+ assert_equal "jdoe", user.permalink
84
+ end
85
+
86
+ test "should create unique permalinks for number-ended titles" do
87
+ post1 = create_post(:title => "Rails 3")
88
+ assert_equal "rails-3", post1.permalink
89
+
90
+ post2 = create_post(:title => "Rails 3")
91
+ assert_equal "rails-3-2", post2.permalink
92
+ end
93
+
94
+ private
95
+ def create_beer(options={})
96
+ Beer.create({:name => 'Duff'}.merge(options))
97
+ end
98
+
99
+ def create_donut(options={})
100
+ Donut.create({:flavor => 'Cream'}.merge(options))
101
+ end
102
+
103
+ def create_user(options={})
104
+ User.create({:name => 'John Doe'}.merge(options))
105
+ end
106
+
107
+ def create_post(options={})
108
+ Post.create({:title => 'Some nice post!'}.merge(options))
109
+ end
110
+ end
@@ -0,0 +1,18 @@
1
+ ActiveRecord::Schema.define(:version => 0) do
2
+ create_table :beers do |t|
3
+ t.string :name, :permalink
4
+ end
5
+
6
+ create_table :users do |t|
7
+ t.string :name, :permalink
8
+ end
9
+
10
+ create_table :donuts do |t|
11
+ t.string :flavor, :slug
12
+ end
13
+
14
+ create_table :posts do |t|
15
+ t.string :title
16
+ t.string :permalink, :unique => true
17
+ end
18
+ end
@@ -0,0 +1,9 @@
1
+ require "rubygems"
2
+ require "test/unit"
3
+ require "active_record"
4
+ require "active_support/test_case"
5
+ require "permalink"
6
+
7
+ Dir.glob(File.dirname(__FILE__) + "/models/*.rb").each {|r| require r }
8
+ ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ":memory:")
9
+ load('schema.rb')
metadata ADDED
@@ -0,0 +1,80 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: permalink
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 1
8
+ - 0
9
+ version: 0.1.0
10
+ platform: ruby
11
+ authors:
12
+ - Nando Vieira
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-07-09 00:00:00 -03:00
18
+ default_executable:
19
+ dependencies: []
20
+
21
+ description:
22
+ email: fnando.vieira@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README.markdown
29
+ files:
30
+ - README.markdown
31
+ - Rakefile
32
+ - init.rb
33
+ - lib/permalink.rb
34
+ - lib/permalink/string_ext.rb
35
+ - lib/permalink/version.rb
36
+ - test/models/beer.rb
37
+ - test/models/donut.rb
38
+ - test/models/post.rb
39
+ - test/models/user.rb
40
+ - test/permalink_test.rb
41
+ - test/schema.rb
42
+ - test/test_helper.rb
43
+ has_rdoc: true
44
+ homepage: http://github.com/fnando/has_permalink
45
+ licenses: []
46
+
47
+ post_install_message:
48
+ rdoc_options:
49
+ - --charset=UTF-8
50
+ require_paths:
51
+ - lib
52
+ required_ruby_version: !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ required_rubygems_version: !ruby/object:Gem::Requirement
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.6
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: ActiveRecord plugin for automatically converting fields to permalinks.
73
+ test_files:
74
+ - test/models/beer.rb
75
+ - test/models/donut.rb
76
+ - test/models/post.rb
77
+ - test/models/user.rb
78
+ - test/permalink_test.rb
79
+ - test/schema.rb
80
+ - test/test_helper.rb