Package not found. Please check the package name and try again.
sayso-permalink_fu 0.0.1.001
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/.autotest +36 -0
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/README +40 -0
- data/Rakefile +13 -0
- data/lib/permalink_fu.rb +39 -0
- data/lib/permalink_fu/active_record.rb +160 -0
- data/lib/permalink_fu/railtie.rb +19 -0
- data/permalink_fu.gemspec +20 -0
- data/test/permalink_fu_test.rb +323 -0
- data/test/test_helper.rb +162 -0
- metadata +99 -0
data/.autotest
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
class Autotest
|
|
2
|
+
##
|
|
3
|
+
# Convert a path in a string, s, into a class name, changing
|
|
4
|
+
# underscores to CamelCase, etc.
|
|
5
|
+
|
|
6
|
+
def path_to_classname(s)
|
|
7
|
+
sep = File::SEPARATOR
|
|
8
|
+
f = s.sub(/^test#{sep}/, '').sub(/\.rb$/, '').split(sep)
|
|
9
|
+
f = f.map { |path| path.split(/_|(\d+)/).map { |seg| seg.capitalize }.join }
|
|
10
|
+
f = f.map { |path| path =~ /Test$/ ? path : "#{path}Test" }
|
|
11
|
+
f.join('::')
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
Autotest.add_hook :initialize do |at|
|
|
16
|
+
unless ARGV.empty?
|
|
17
|
+
if ARGV[0] == '-d'
|
|
18
|
+
at.find_directories = ARGV[1..-1].dup
|
|
19
|
+
else
|
|
20
|
+
at.find_directories = []
|
|
21
|
+
at.extra_files = ARGV.dup
|
|
22
|
+
end
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# doesn't seem to work
|
|
26
|
+
# at.clear_mappings
|
|
27
|
+
|
|
28
|
+
at.add_mapping(/^lib\/.*\.rb$/) do |filename, _|
|
|
29
|
+
possible = File.basename(filename, 'rb').gsub '_', '_?'
|
|
30
|
+
files_matching %r%^test/.*#{possible}_test\.rb$%
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
at.add_mapping(/^test.*\/.*test\.rb$/) do |filename, _|
|
|
34
|
+
filename
|
|
35
|
+
end
|
|
36
|
+
end
|
data/.gitignore
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
nbproject/
|
data/Gemfile
ADDED
data/README
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
PermalinkFu
|
|
2
|
+
|
|
3
|
+
This is a simple plugin extracted from Mephisto for creating permalinks from attributes.
|
|
4
|
+
|
|
5
|
+
class Article < ActiveRecord::Base
|
|
6
|
+
has_permalink :title
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
This will escape the title, making it fit to use in a URL in the after_validation callback.
|
|
10
|
+
|
|
11
|
+
Use PermalinkFu.escape to escape a string manually if you like.
|
|
12
|
+
|
|
13
|
+
If you're having issues with Iconv, you can manually tweak PermalinkFu.translation_to PermalinkFu.translation_from.
|
|
14
|
+
These are set to nil if Iconv is not loaded. You can also manually set them to nil if you don't want to use iconv.
|
|
15
|
+
|
|
16
|
+
[Added 3.13.2008 by Pat Nakajima] You can now add conditions to #has_permalink like so:
|
|
17
|
+
|
|
18
|
+
class Article < ActiveRecord::Base
|
|
19
|
+
has_permalink :title, :if => Proc.new { |article| article.needs_permalink? }
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
Use the :if or :unless options to specify a Proc, method, or string to be called or evaluated. The permalink
|
|
23
|
+
will only be generated if the option evaluates to true.
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
[Added 3.11.2009 by Martin Emde] Make permalink_fu update your permalink everytime the dependent field(s) change.
|
|
27
|
+
|
|
28
|
+
class Article < ActiveRecord::Base
|
|
29
|
+
has_permalink :title, :update => true
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
This will update your permalink every time title changes. Rails versions with _changed? methods will reduce the checks for uniqueness to only when the permalink field is changed.
|
|
33
|
+
|
|
34
|
+
Without :update set to true, your permalink will be set one time and subsequent changes to the field
|
|
35
|
+
(title in this example) will not affect the permalink field. To regenerate the permalink field,
|
|
36
|
+
set it to nil or a blank string within your model.
|
|
37
|
+
|
|
38
|
+
Old versions of rails without _changed? attribute support will result in the permalink field being regenerated every save.
|
|
39
|
+
|
|
40
|
+
[Bug Fixed 3.11.2009] Permalink was not being checked for uniqueness when set directly with permalink= on rails versions with _changed?
|
data/Rakefile
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
require 'rake'
|
|
2
|
+
|
|
3
|
+
require 'bundler'
|
|
4
|
+
Bundler::GemHelper.install_tasks
|
|
5
|
+
|
|
6
|
+
require 'rake/testtask'
|
|
7
|
+
Rake::TestTask.new do |t|
|
|
8
|
+
t.test_files = FileList['test/*_test.rb']
|
|
9
|
+
t.verbose = true
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
desc 'Default: run test examples'
|
|
13
|
+
task :default => 'test'
|
data/lib/permalink_fu.rb
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'permalink_fu', 'railtie')
|
|
2
|
+
require File.join(File.dirname(__FILE__), 'permalink_fu', 'active_record')
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'iconv'
|
|
6
|
+
rescue Object
|
|
7
|
+
puts "No Iconv found, you might want to look into it."
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
module PermalinkFu
|
|
11
|
+
|
|
12
|
+
class << self
|
|
13
|
+
|
|
14
|
+
# This method does the actual permalink escaping.
|
|
15
|
+
def escape(string)
|
|
16
|
+
result = ::ActiveSupport::Inflector.transliterate(string.to_s)
|
|
17
|
+
result = self.iconvify(result)
|
|
18
|
+
result.gsub!(/[^\x00-\x7F]+/, '') # Remove anything non-ASCII entirely (e.g. diacritics).
|
|
19
|
+
result.gsub!(/[^\w_ \-]+/i, '') # Remove unwanted chars.
|
|
20
|
+
result.gsub!(/[ \-]+/i, '-') # No more than one of the separator in a row.
|
|
21
|
+
result.gsub!(/^\-|\-$/i, '') # Remove leading/trailing separator.
|
|
22
|
+
result.downcase!
|
|
23
|
+
result.size.zero? ? random_permalink : result
|
|
24
|
+
rescue
|
|
25
|
+
random_permalink
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def random_permalink
|
|
29
|
+
::ActiveSupport::SecureRandom.hex(16)
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def iconvify(string)
|
|
33
|
+
return string unless defined?(Iconv)
|
|
34
|
+
return Iconv.iconv('ascii//translit//IGNORE', 'utf-8', string).to_s
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
end
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
module PermalinkFu
|
|
2
|
+
|
|
3
|
+
module ActiveRecord
|
|
4
|
+
|
|
5
|
+
def self.included(base)
|
|
6
|
+
base.extend(ClassMethods)
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
# This is the plugin method available on all ActiveRecord models.
|
|
10
|
+
module ClassMethods
|
|
11
|
+
# Specifies the given field(s) as a permalink, meaning it is passed through PermalinkFu.escape and set to the permalink_field. This
|
|
12
|
+
# is done
|
|
13
|
+
#
|
|
14
|
+
# class Foo < ActiveRecord::Base
|
|
15
|
+
# # stores permalink form of #title to the #permalink attribute
|
|
16
|
+
# has_permalink :title
|
|
17
|
+
#
|
|
18
|
+
# # stores a permalink form of "#{category}-#{title}" to the #permalink attribute
|
|
19
|
+
#
|
|
20
|
+
# has_permalink [:category, :title]
|
|
21
|
+
#
|
|
22
|
+
# # stores permalink form of #title to the #category_permalink attribute
|
|
23
|
+
# has_permalink [:category, :title], :category_permalink
|
|
24
|
+
#
|
|
25
|
+
# # add a scope
|
|
26
|
+
# has_permalink :title, :scope => :blog_id
|
|
27
|
+
#
|
|
28
|
+
# # add a scope and specify the permalink field name
|
|
29
|
+
# has_permalink :title, :slug, :scope => :blog_id
|
|
30
|
+
#
|
|
31
|
+
# # do not bother checking for a unique scope
|
|
32
|
+
# has_permalink :title, :unique => false
|
|
33
|
+
#
|
|
34
|
+
# # update the permalink every time the attribute(s) change
|
|
35
|
+
# # without _changed? methods (old rails version) this will rewrite the permalink every time
|
|
36
|
+
# has_permalink :title, :update => true
|
|
37
|
+
#
|
|
38
|
+
# end
|
|
39
|
+
#
|
|
40
|
+
def has_permalink(attr_names = [], permalink_field = nil, options = {})
|
|
41
|
+
include InstanceMethods
|
|
42
|
+
|
|
43
|
+
if permalink_field.is_a?(Hash)
|
|
44
|
+
options = permalink_field
|
|
45
|
+
permalink_field = nil
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
|
|
49
|
+
cattr_accessor :permalink_options
|
|
50
|
+
cattr_accessor :permalink_attributes
|
|
51
|
+
cattr_accessor :permalink_field
|
|
52
|
+
|
|
53
|
+
self.permalink_attributes = Array(attr_names)
|
|
54
|
+
self.permalink_field = (permalink_field || 'permalink').to_s
|
|
55
|
+
self.permalink_options = {:unique => true}.update(options)
|
|
56
|
+
|
|
57
|
+
if self.permalink_options[:unique]
|
|
58
|
+
before_validation :create_unique_permalink
|
|
59
|
+
else
|
|
60
|
+
before_validation :create_common_permalink
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
define_method :"#{self.permalink_field}=" do |value|
|
|
64
|
+
write_attribute(self.permalink_field, value.blank? ? '' : PermalinkFu.escape(value))
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# This contains instance methods for ActiveRecord models that have permalinks.
|
|
71
|
+
module InstanceMethods
|
|
72
|
+
|
|
73
|
+
protected
|
|
74
|
+
|
|
75
|
+
def create_common_permalink
|
|
76
|
+
return unless should_create_permalink?
|
|
77
|
+
if read_attribute(self.class.permalink_field).blank? || permalink_fields_changed?
|
|
78
|
+
send("#{self.class.permalink_field}=", create_permalink_for(self.class.permalink_attributes))
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# Quit now if we have the changed method available and nothing has changed
|
|
82
|
+
permalink_changed = "#{self.class.permalink_field}_changed?"
|
|
83
|
+
return if respond_to?(permalink_changed) && !send(permalink_changed)
|
|
84
|
+
|
|
85
|
+
# Otherwise find the limit and crop the permalink
|
|
86
|
+
limit = self.class.columns_hash[self.class.permalink_field].limit
|
|
87
|
+
base = send("#{self.class.permalink_field}=", read_attribute(self.class.permalink_field)[0..limit - 1])
|
|
88
|
+
[limit, base]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def create_unique_permalink
|
|
92
|
+
limit, base = create_common_permalink
|
|
93
|
+
return if limit.nil? # nil if the permalink has not changed or :if/:unless fail
|
|
94
|
+
counter = 1
|
|
95
|
+
# oh how i wish i could use a hash for conditions
|
|
96
|
+
conditions = ["#{self.class.permalink_field} = ?", base]
|
|
97
|
+
unless new_record?
|
|
98
|
+
conditions.first << " and id != ?"
|
|
99
|
+
conditions << id
|
|
100
|
+
end
|
|
101
|
+
if self.class.permalink_options[:scope]
|
|
102
|
+
[self.class.permalink_options[:scope]].flatten.each do |scope|
|
|
103
|
+
value = send(scope)
|
|
104
|
+
if value
|
|
105
|
+
conditions.first << " and #{scope} = ?"
|
|
106
|
+
conditions << send(scope)
|
|
107
|
+
else
|
|
108
|
+
conditions.first << " and #{scope} IS NULL"
|
|
109
|
+
end
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
while ::ActiveRecord::Base.uncached{self.class.exists?(conditions)}
|
|
114
|
+
suffix = "-#{counter += 1}"
|
|
115
|
+
conditions[1] = "#{base[0..limit-suffix.size-1]}#{suffix}"
|
|
116
|
+
send("#{self.class.permalink_field}=", conditions[1])
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
def create_permalink_for(attr_names)
|
|
121
|
+
str = attr_names.collect { |attr_name| send(attr_name).to_s } * " "
|
|
122
|
+
str.blank? ? PermalinkFu.random_permalink : str
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
private
|
|
126
|
+
def should_create_permalink?
|
|
127
|
+
if self.class.permalink_field.blank?
|
|
128
|
+
false
|
|
129
|
+
elsif self.class.permalink_options[:if]
|
|
130
|
+
evaluate_method(self.class.permalink_options[:if])
|
|
131
|
+
elsif self.class.permalink_options[:unless]
|
|
132
|
+
!evaluate_method(self.class.permalink_options[:unless])
|
|
133
|
+
else
|
|
134
|
+
true
|
|
135
|
+
end
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# Don't even check _changed? methods unless :update is set
|
|
139
|
+
def permalink_fields_changed?
|
|
140
|
+
return false unless self.class.permalink_options[:update]
|
|
141
|
+
self.class.permalink_attributes.any? do |attribute|
|
|
142
|
+
changed_method = "#{attribute}_changed?"
|
|
143
|
+
respond_to?(changed_method) ? send(changed_method) : true
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def evaluate_method(method)
|
|
148
|
+
case method
|
|
149
|
+
when Symbol
|
|
150
|
+
send(method)
|
|
151
|
+
when String
|
|
152
|
+
eval(method, instance_eval { binding })
|
|
153
|
+
when Proc, Method
|
|
154
|
+
method.call(self)
|
|
155
|
+
end
|
|
156
|
+
end
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
end
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
require 'rails'
|
|
2
|
+
|
|
3
|
+
module PermalinkFu
|
|
4
|
+
|
|
5
|
+
class Railtie < ::Rails::Railtie
|
|
6
|
+
|
|
7
|
+
initializer 'permalink_fu.insert_into_active_record' do
|
|
8
|
+
::ActiveSupport.on_load :active_record do
|
|
9
|
+
include PermalinkFu::ActiveRecord
|
|
10
|
+
end
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
# rake_tasks do
|
|
14
|
+
# load "tasks/permalink_fu.rake"
|
|
15
|
+
# end
|
|
16
|
+
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
Gem::Specification.new do |s|
|
|
2
|
+
s.name = "sayso-permalink_fu"
|
|
3
|
+
s.version = "0.0.1.001"
|
|
4
|
+
s.authors = ['SaySo']
|
|
5
|
+
s.platform = Gem::Platform::RUBY
|
|
6
|
+
s.rubyforge_project = "knapo-permalink_fu"
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
s.homepage = "http://github.com/sayso/permalink_fu"
|
|
10
|
+
s.summary = 'Simple plugin extracted from Mephisto for creating permalinks from attributes - forked and gemified for sayso'
|
|
11
|
+
|
|
12
|
+
s.files = `git ls-files`.split("\n")
|
|
13
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
14
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
15
|
+
s.require_paths = ["lib"]
|
|
16
|
+
|
|
17
|
+
s.add_dependency('rails', '>= 3.0.5')
|
|
18
|
+
s.add_dependency('activerecord', '>= 3.0.5')
|
|
19
|
+
s.add_dependency('activesupport', '>= 3.0.5')
|
|
20
|
+
end
|
|
@@ -0,0 +1,323 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require File.join(File.dirname(__FILE__), 'test_helper')
|
|
3
|
+
|
|
4
|
+
class PermalinkFuTest < Test::Unit::TestCase
|
|
5
|
+
@@samples = {
|
|
6
|
+
'This IS a Tripped out title!!.!1 (well/ not really)'.freeze => 'this-is-a-tripped-out-title1-well-not-really'.freeze,
|
|
7
|
+
'////// meph1sto r0x ! \\\\\\'.freeze => 'meph1sto-r0x'.freeze,
|
|
8
|
+
'āčēģīķļņū'.freeze => 'acegiklnu'.freeze,
|
|
9
|
+
'中文測試 chinese text'.freeze => 'chinese-text'.freeze,
|
|
10
|
+
'fööbär'.freeze => 'foobar'.freeze
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
@@extra = { 'some-)()()-ExtRa!/// .data==?> to \/\/test'.freeze => 'some-extra-data-to-test'.freeze }
|
|
14
|
+
|
|
15
|
+
def test_basemodel
|
|
16
|
+
@m = BaseModel.new
|
|
17
|
+
assert @m.valid?
|
|
18
|
+
assert_equal @m.id, nil
|
|
19
|
+
assert_equal @m.title, nil
|
|
20
|
+
assert_equal @m.permalink, nil
|
|
21
|
+
assert_equal @m.extra, nil
|
|
22
|
+
assert_equal @m.foo, nil
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def test_set_new_permalink_attributes_on_sub_class
|
|
26
|
+
@m = ClassModel.new
|
|
27
|
+
@m.title = 'foo'
|
|
28
|
+
@m.extra = 'bar'
|
|
29
|
+
assert @m.valid?
|
|
30
|
+
assert_equal @m.permalink, 'foo'
|
|
31
|
+
|
|
32
|
+
@m = SubClassHasPermalinkModel.new
|
|
33
|
+
@m.title = 'foo'
|
|
34
|
+
@m.extra = 'bar'
|
|
35
|
+
assert @m.valid?
|
|
36
|
+
assert_equal @m.permalink, 'foo-bar'
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def test_should_not_inherit_permalink_attributes
|
|
40
|
+
@m = SubClassNoPermalinkModel.new
|
|
41
|
+
@m.title = 'foo'
|
|
42
|
+
assert @m.valid?
|
|
43
|
+
assert_equal @m.permalink, nil
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def test_should_escape_permalinks
|
|
47
|
+
@@samples.each do |from, to|
|
|
48
|
+
assert_equal to, PermalinkFu.escape(from)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def test_should_escape_activerecord_model
|
|
53
|
+
@m = MockModel.new
|
|
54
|
+
@@samples.each do |from, to|
|
|
55
|
+
@m.title = from; @m.permalink = nil
|
|
56
|
+
assert @m.valid?
|
|
57
|
+
assert_equal to, @m.permalink
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def test_should_escape_activerecord_model_with_existing_permalink
|
|
62
|
+
@m = MockModel.new
|
|
63
|
+
@@samples.each do |from, to|
|
|
64
|
+
@m.title = 'whatever'; @m.permalink = from
|
|
65
|
+
assert @m.valid?
|
|
66
|
+
assert_equal to, @m.permalink
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_multiple_attribute_permalink
|
|
71
|
+
@m = MockModelExtra.new
|
|
72
|
+
@@samples.each do |from, to|
|
|
73
|
+
@@extra.each do |from_extra, to_extra|
|
|
74
|
+
@m.title = from; @m.extra = from_extra; @m.permalink = nil
|
|
75
|
+
assert @m.valid?
|
|
76
|
+
assert_equal "#{to}-#{to_extra}", @m.permalink
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
def test_should_create_unique_permalink
|
|
82
|
+
@m = MockModel.new
|
|
83
|
+
@m.title = 'foo'
|
|
84
|
+
assert @m.valid?
|
|
85
|
+
assert_equal 'foo-2', @m.permalink
|
|
86
|
+
|
|
87
|
+
@m.title = 'bar'
|
|
88
|
+
@m.permalink = nil
|
|
89
|
+
assert @m.valid?
|
|
90
|
+
assert_equal 'bar-3', @m.permalink
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
def test_should_create_unique_permalink_when_assigned_directly
|
|
94
|
+
@m = MockModel.new
|
|
95
|
+
@m.permalink = 'foo'
|
|
96
|
+
assert @m.valid?
|
|
97
|
+
assert_equal 'foo-2', @m.permalink
|
|
98
|
+
|
|
99
|
+
# should always check itself for uniqueness when not respond_to?(:permalink_changed?)
|
|
100
|
+
@m.permalink = 'bar'
|
|
101
|
+
assert @m.valid?
|
|
102
|
+
assert_equal 'bar-3', @m.permalink
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
def test_should_common_permalink_if_unique_is_false
|
|
106
|
+
@m = CommonMockModel.new
|
|
107
|
+
@m.permalink = 'foo'
|
|
108
|
+
assert @m.valid?
|
|
109
|
+
assert_equal 'foo', @m.permalink
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
def test_should_not_check_itself_for_unique_permalink_if_unchanged
|
|
113
|
+
@m = MockModel.new
|
|
114
|
+
@m.id = 2
|
|
115
|
+
@m.permalink = 'bar-2'
|
|
116
|
+
@m.instance_eval do
|
|
117
|
+
@changed_attributes = {}
|
|
118
|
+
end
|
|
119
|
+
assert @m.valid?
|
|
120
|
+
assert_equal 'bar-2', @m.permalink
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
def test_should_check_itself_for_unique_permalink_if_permalink_field_changed
|
|
124
|
+
@m = PermalinkChangeableMockModel.new
|
|
125
|
+
@m.permalink_will_change!
|
|
126
|
+
@m.permalink = 'foo'
|
|
127
|
+
assert @m.valid?
|
|
128
|
+
assert_equal 'foo-2', @m.permalink
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
def test_should_not_check_itself_for_unique_permalink_if_permalink_field_not_changed
|
|
132
|
+
@m = PermalinkChangeableMockModel.new
|
|
133
|
+
@m.permalink = 'foo'
|
|
134
|
+
assert @m.valid?
|
|
135
|
+
assert_equal 'foo', @m.permalink
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
def test_should_create_unique_scoped_permalink
|
|
139
|
+
@m = ScopedModel.new
|
|
140
|
+
@m.permalink = 'foo'
|
|
141
|
+
assert @m.valid?
|
|
142
|
+
assert_equal 'foo-2', @m.permalink
|
|
143
|
+
|
|
144
|
+
@m.foo = 5
|
|
145
|
+
@m.permalink = 'foo'
|
|
146
|
+
assert @m.valid?
|
|
147
|
+
assert_equal 'foo', @m.permalink
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
def test_should_limit_permalink
|
|
151
|
+
@old = MockModel.columns_hash['permalink'].instance_variable_get(:@limit)
|
|
152
|
+
MockModel.columns_hash['permalink'].instance_variable_set(:@limit, 2)
|
|
153
|
+
@m = MockModel.new
|
|
154
|
+
@m.title = 'BOO'
|
|
155
|
+
assert @m.valid?
|
|
156
|
+
assert_equal 'bo', @m.permalink
|
|
157
|
+
ensure
|
|
158
|
+
MockModel.columns_hash['permalink'].instance_variable_set(:@limit, @old)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def test_should_limit_unique_permalink
|
|
162
|
+
@old = MockModel.columns_hash['permalink'].instance_variable_get(:@limit)
|
|
163
|
+
MockModel.columns_hash['permalink'].instance_variable_set(:@limit, 3)
|
|
164
|
+
@m = MockModel.new
|
|
165
|
+
@m.title = 'foo'
|
|
166
|
+
assert @m.valid?
|
|
167
|
+
assert_equal 'f-2', @m.permalink
|
|
168
|
+
ensure
|
|
169
|
+
MockModel.columns_hash['permalink'].instance_variable_set(:@limit, @old)
|
|
170
|
+
end
|
|
171
|
+
|
|
172
|
+
def test_should_abide_by_if_proc_condition
|
|
173
|
+
@m = IfProcConditionModel.new
|
|
174
|
+
@m.title = 'dont make me a permalink'
|
|
175
|
+
assert @m.valid?
|
|
176
|
+
assert_nil @m.permalink
|
|
177
|
+
end
|
|
178
|
+
|
|
179
|
+
def test_should_abide_by_if_method_condition
|
|
180
|
+
@m = IfMethodConditionModel.new
|
|
181
|
+
@m.title = 'dont make me a permalink'
|
|
182
|
+
assert @m.valid?
|
|
183
|
+
assert_nil @m.permalink
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def test_should_abide_by_if_string_condition
|
|
187
|
+
@m = IfStringConditionModel.new
|
|
188
|
+
@m.title = 'dont make me a permalink'
|
|
189
|
+
assert @m.valid?
|
|
190
|
+
assert_nil @m.permalink
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def test_should_abide_by_unless_proc_condition
|
|
194
|
+
@m = UnlessProcConditionModel.new
|
|
195
|
+
@m.title = 'make me a permalink'
|
|
196
|
+
assert @m.valid?
|
|
197
|
+
assert_not_nil @m.permalink
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
def test_should_abide_by_unless_method_condition
|
|
201
|
+
@m = UnlessMethodConditionModel.new
|
|
202
|
+
@m.title = 'make me a permalink'
|
|
203
|
+
assert @m.valid?
|
|
204
|
+
assert_not_nil @m.permalink
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def test_should_abide_by_unless_string_condition
|
|
208
|
+
@m = UnlessStringConditionModel.new
|
|
209
|
+
@m.title = 'make me a permalink'
|
|
210
|
+
assert @m.valid?
|
|
211
|
+
assert_not_nil @m.permalink
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
def test_should_allow_override_of_permalink_method
|
|
215
|
+
@m = OverrideModel.new
|
|
216
|
+
@m.write_attribute(:permalink, 'the permalink')
|
|
217
|
+
assert_not_equal @m.permalink, @m.read_attribute(:permalink)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
def test_should_create_permalink_from_attribute_not_attribute_accessor
|
|
221
|
+
@m = OverrideModel.new
|
|
222
|
+
@m.title = 'the permalink'
|
|
223
|
+
assert @m.valid?
|
|
224
|
+
assert_equal 'the-permalink', @m.read_attribute(:permalink)
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
def test_should_not_update_permalink_unless_field_changed
|
|
228
|
+
@m = NoChangeModel.new
|
|
229
|
+
@m.title = 'the permalink'
|
|
230
|
+
@m.permalink = 'unchanged'
|
|
231
|
+
assert @m.valid?
|
|
232
|
+
assert_equal 'unchanged', @m.read_attribute(:permalink)
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def test_should_not_update_permalink_without_update_set_even_if_field_changed
|
|
236
|
+
@m = ChangedWithoutUpdateModel.new
|
|
237
|
+
@m.title = 'the permalink'
|
|
238
|
+
@m.permalink = 'unchanged'
|
|
239
|
+
assert @m.valid?
|
|
240
|
+
assert_equal 'unchanged', @m.read_attribute(:permalink)
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
def test_should_update_permalink_if_changed_method_does_not_exist
|
|
244
|
+
@m = OverrideModel.new
|
|
245
|
+
@m.title = 'the permalink'
|
|
246
|
+
assert @m.valid?
|
|
247
|
+
assert_equal 'the-permalink', @m.read_attribute(:permalink)
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def test_should_update_permalink_if_the_existing_permalink_is_nil
|
|
251
|
+
@m = NoChangeModel.new
|
|
252
|
+
@m.title = 'the permalink'
|
|
253
|
+
@m.permalink = nil
|
|
254
|
+
assert @m.valid?
|
|
255
|
+
assert_equal 'the-permalink', @m.read_attribute(:permalink)
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
def test_should_update_permalink_if_the_existing_permalink_is_blank
|
|
259
|
+
@m = NoChangeModel.new
|
|
260
|
+
@m.title = 'the permalink'
|
|
261
|
+
@m.permalink = ''
|
|
262
|
+
assert @m.valid?
|
|
263
|
+
assert_equal 'the-permalink', @m.read_attribute(:permalink)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def test_should_assign_a_random_permalink_if_the_title_is_nil
|
|
267
|
+
@m = NoChangeModel.new
|
|
268
|
+
@m.title = nil
|
|
269
|
+
assert @m.valid?
|
|
270
|
+
assert_not_nil @m.read_attribute(:permalink)
|
|
271
|
+
assert @m.read_attribute(:permalink).size > 0
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
def test_should_assign_a_random_permalink_if_the_title_has_no_permalinkable_characters
|
|
275
|
+
@m = NoChangeModel.new
|
|
276
|
+
@m.title = '////'
|
|
277
|
+
assert @m.valid?
|
|
278
|
+
assert_not_nil @m.read_attribute(:permalink)
|
|
279
|
+
assert @m.read_attribute(:permalink).size > 0
|
|
280
|
+
end
|
|
281
|
+
|
|
282
|
+
def test_should_update_permalink_the_first_time_the_title_is_set
|
|
283
|
+
@m = ChangedWithoutUpdateModel.new
|
|
284
|
+
@m.title = "old title"
|
|
285
|
+
assert @m.valid?
|
|
286
|
+
assert_equal "old-title", @m.read_attribute(:permalink)
|
|
287
|
+
@m.title = "new title"
|
|
288
|
+
assert @m.valid?
|
|
289
|
+
assert_equal "old-title", @m.read_attribute(:permalink)
|
|
290
|
+
end
|
|
291
|
+
|
|
292
|
+
def test_should_not_update_permalink_if_already_set_even_if_title_changed
|
|
293
|
+
@m = ChangedWithoutUpdateModel.new
|
|
294
|
+
@m.permalink = "old permalink"
|
|
295
|
+
@m.title = "new title"
|
|
296
|
+
assert @m.valid?
|
|
297
|
+
assert_equal "old-permalink", @m.read_attribute(:permalink)
|
|
298
|
+
end
|
|
299
|
+
|
|
300
|
+
def test_should_update_permalink_every_time_the_title_is_changed
|
|
301
|
+
@m = ChangedWithUpdateModel.new
|
|
302
|
+
@m.title = "old title"
|
|
303
|
+
assert @m.valid?
|
|
304
|
+
assert_equal "old-title", @m.read_attribute(:permalink)
|
|
305
|
+
@m.title = "new title"
|
|
306
|
+
assert @m.valid?
|
|
307
|
+
assert_equal "new-title", @m.read_attribute(:permalink)
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
def test_should_work_correctly_for_scoped_fields_with_nil_value
|
|
311
|
+
s1 = ScopedModelForNilScope.new
|
|
312
|
+
s1.title = 'ack'
|
|
313
|
+
s1.foo = 3
|
|
314
|
+
assert s1.valid?
|
|
315
|
+
assert_equal 'ack', s1.permalink
|
|
316
|
+
|
|
317
|
+
s2 = ScopedModelForNilScope.new
|
|
318
|
+
s2.title = 'ack'
|
|
319
|
+
s2.foo = nil
|
|
320
|
+
assert s2.valid?
|
|
321
|
+
assert_equal 'ack-2', s2.permalink
|
|
322
|
+
end
|
|
323
|
+
end
|
data/test/test_helper.rb
ADDED
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
require 'test/unit'
|
|
2
|
+
require File.join(File.dirname(__FILE__), '../lib/permalink_fu')
|
|
3
|
+
|
|
4
|
+
begin
|
|
5
|
+
require 'rubygems'
|
|
6
|
+
require 'ruby-debug'
|
|
7
|
+
Debugger.start
|
|
8
|
+
rescue LoadError
|
|
9
|
+
# no ruby debugger
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
gem 'activerecord'
|
|
13
|
+
require 'active_record'
|
|
14
|
+
require File.join(File.dirname(__FILE__), '../init')
|
|
15
|
+
|
|
16
|
+
class BaseModel < ActiveRecord::Base
|
|
17
|
+
cattr_accessor :columns
|
|
18
|
+
@@columns ||= []
|
|
19
|
+
|
|
20
|
+
def self.column(name, sql_type = nil, default = nil, null = true)
|
|
21
|
+
columns << ActiveRecord::ConnectionAdapters::Column.new(name.to_s, default, sql_type, null)
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def self.exists?(*args)
|
|
25
|
+
false
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
column :id, 'int(11)'
|
|
29
|
+
column :title, 'varchar(100)'
|
|
30
|
+
column :permalink, 'varchar(100)'
|
|
31
|
+
column :extra, 'varchar(100)'
|
|
32
|
+
column :foo, 'varchar(100)'
|
|
33
|
+
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
class ClassModel < BaseModel
|
|
37
|
+
has_permalink :title
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
class SubClassHasPermalinkModel < ClassModel
|
|
41
|
+
has_permalink [:title, :extra]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
class SubClassNoPermalinkModel < ClassModel
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
class MockModel < BaseModel
|
|
48
|
+
def self.exists?(conditions)
|
|
49
|
+
if conditions[1] == 'foo' || conditions[1] == 'bar' ||
|
|
50
|
+
(conditions[1] == 'bar-2' && conditions[2] != 2)
|
|
51
|
+
true
|
|
52
|
+
else
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
has_permalink :title
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
class PermalinkChangeableMockModel < BaseModel
|
|
61
|
+
def self.exists?(conditions)
|
|
62
|
+
if conditions[1] == 'foo'
|
|
63
|
+
true
|
|
64
|
+
else
|
|
65
|
+
false
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
has_permalink :title
|
|
70
|
+
|
|
71
|
+
def permalink_changed?
|
|
72
|
+
@permalink_changed
|
|
73
|
+
end
|
|
74
|
+
|
|
75
|
+
def permalink_will_change!
|
|
76
|
+
@permalink_changed = true
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
class CommonMockModel < BaseModel
|
|
81
|
+
def self.exists?(conditions)
|
|
82
|
+
false # oh noes
|
|
83
|
+
end
|
|
84
|
+
|
|
85
|
+
has_permalink :title, :unique => false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
class ScopedModel < BaseModel
|
|
89
|
+
def self.exists?(conditions)
|
|
90
|
+
if conditions[1] == 'foo' && conditions[2] != 5
|
|
91
|
+
true
|
|
92
|
+
else
|
|
93
|
+
false
|
|
94
|
+
end
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
has_permalink :title, :scope => :foo
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
class ScopedModelForNilScope < BaseModel
|
|
101
|
+
def self.exists?(conditions)
|
|
102
|
+
(conditions[0] == 'permalink = ? and foo IS NULL') ? (conditions[1] == 'ack') : false
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
has_permalink :title, :scope => :foo
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
class OverrideModel < BaseModel
|
|
109
|
+
has_permalink :title
|
|
110
|
+
|
|
111
|
+
def permalink
|
|
112
|
+
'not the permalink'
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
class ChangedWithoutUpdateModel < BaseModel
|
|
117
|
+
has_permalink :title
|
|
118
|
+
def title_changed?; true; end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
class ChangedWithUpdateModel < BaseModel
|
|
122
|
+
has_permalink :title, :update => true
|
|
123
|
+
def title_changed?; true; end
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
class NoChangeModel < BaseModel
|
|
127
|
+
has_permalink :title, :update => true
|
|
128
|
+
def title_changed?; false; end
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
class IfProcConditionModel < BaseModel
|
|
132
|
+
has_permalink :title, :if => Proc.new { |obj| false }
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
class IfMethodConditionModel < BaseModel
|
|
136
|
+
has_permalink :title, :if => :false_method
|
|
137
|
+
|
|
138
|
+
def false_method; false; end
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
class IfStringConditionModel < BaseModel
|
|
142
|
+
has_permalink :title, :if => 'false'
|
|
143
|
+
end
|
|
144
|
+
|
|
145
|
+
class UnlessProcConditionModel < BaseModel
|
|
146
|
+
has_permalink :title, :unless => Proc.new { |obj| false }
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
class UnlessMethodConditionModel < BaseModel
|
|
150
|
+
has_permalink :title, :unless => :false_method
|
|
151
|
+
|
|
152
|
+
def false_method; false; end
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
class UnlessStringConditionModel < BaseModel
|
|
156
|
+
has_permalink :title, :unless => 'false'
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
class MockModelExtra < BaseModel
|
|
160
|
+
has_permalink [:title, :extra]
|
|
161
|
+
end
|
|
162
|
+
|
metadata
ADDED
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: sayso-permalink_fu
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
prerelease:
|
|
5
|
+
version: 0.0.1.001
|
|
6
|
+
platform: ruby
|
|
7
|
+
authors:
|
|
8
|
+
- SaySo
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
|
|
13
|
+
date: 2011-05-23 00:00:00 +02:00
|
|
14
|
+
default_executable:
|
|
15
|
+
dependencies:
|
|
16
|
+
- !ruby/object:Gem::Dependency
|
|
17
|
+
name: rails
|
|
18
|
+
prerelease: false
|
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
|
20
|
+
none: false
|
|
21
|
+
requirements:
|
|
22
|
+
- - ">="
|
|
23
|
+
- !ruby/object:Gem::Version
|
|
24
|
+
version: 3.0.5
|
|
25
|
+
type: :runtime
|
|
26
|
+
version_requirements: *id001
|
|
27
|
+
- !ruby/object:Gem::Dependency
|
|
28
|
+
name: activerecord
|
|
29
|
+
prerelease: false
|
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
|
31
|
+
none: false
|
|
32
|
+
requirements:
|
|
33
|
+
- - ">="
|
|
34
|
+
- !ruby/object:Gem::Version
|
|
35
|
+
version: 3.0.5
|
|
36
|
+
type: :runtime
|
|
37
|
+
version_requirements: *id002
|
|
38
|
+
- !ruby/object:Gem::Dependency
|
|
39
|
+
name: activesupport
|
|
40
|
+
prerelease: false
|
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
|
42
|
+
none: false
|
|
43
|
+
requirements:
|
|
44
|
+
- - ">="
|
|
45
|
+
- !ruby/object:Gem::Version
|
|
46
|
+
version: 3.0.5
|
|
47
|
+
type: :runtime
|
|
48
|
+
version_requirements: *id003
|
|
49
|
+
description:
|
|
50
|
+
email:
|
|
51
|
+
executables: []
|
|
52
|
+
|
|
53
|
+
extensions: []
|
|
54
|
+
|
|
55
|
+
extra_rdoc_files: []
|
|
56
|
+
|
|
57
|
+
files:
|
|
58
|
+
- .autotest
|
|
59
|
+
- .gitignore
|
|
60
|
+
- Gemfile
|
|
61
|
+
- README
|
|
62
|
+
- Rakefile
|
|
63
|
+
- lib/permalink_fu.rb
|
|
64
|
+
- lib/permalink_fu/active_record.rb
|
|
65
|
+
- lib/permalink_fu/railtie.rb
|
|
66
|
+
- permalink_fu.gemspec
|
|
67
|
+
- test/permalink_fu_test.rb
|
|
68
|
+
- test/test_helper.rb
|
|
69
|
+
has_rdoc: true
|
|
70
|
+
homepage: http://github.com/sayso/permalink_fu
|
|
71
|
+
licenses: []
|
|
72
|
+
|
|
73
|
+
post_install_message:
|
|
74
|
+
rdoc_options: []
|
|
75
|
+
|
|
76
|
+
require_paths:
|
|
77
|
+
- lib
|
|
78
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
79
|
+
none: false
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: "0"
|
|
84
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
85
|
+
none: false
|
|
86
|
+
requirements:
|
|
87
|
+
- - ">="
|
|
88
|
+
- !ruby/object:Gem::Version
|
|
89
|
+
version: "0"
|
|
90
|
+
requirements: []
|
|
91
|
+
|
|
92
|
+
rubyforge_project: knapo-permalink_fu
|
|
93
|
+
rubygems_version: 1.6.2
|
|
94
|
+
signing_key:
|
|
95
|
+
specification_version: 3
|
|
96
|
+
summary: Simple plugin extracted from Mephisto for creating permalinks from attributes - forked and gemified for sayso
|
|
97
|
+
test_files:
|
|
98
|
+
- test/permalink_fu_test.rb
|
|
99
|
+
- test/test_helper.rb
|