permalink 0.1.0

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