seofy 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 +3 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +50 -0
- data/Guardfile +5 -0
- data/README.md +40 -0
- data/Rakefile +2 -0
- data/lib/seofy.rb +14 -0
- data/lib/seofy/active_record.rb +50 -0
- data/lib/seofy/adapter.rb +0 -0
- data/lib/seofy/adapters/base.rb +27 -0
- data/lib/seofy/adapters/base36.rb +19 -0
- data/lib/seofy/adapters/existing_column.rb +19 -0
- data/lib/seofy/configuration.rb +11 -0
- data/lib/seofy/encoders/base36.rb +41 -0
- data/lib/seofy/railtie.rb +7 -0
- data/lib/seofy/task_runner.rb +36 -0
- data/lib/seofy/version.rb +3 -0
- data/lib/tasks/seofy.rake +10 -0
- data/seofy.gemspec +29 -0
- data/spec/database.yml +2 -0
- data/spec/integration/base36_spec.rb +18 -0
- data/spec/integration/existing_column_spec.rb +19 -0
- data/spec/lib/seofy/active_record_spec.rb +80 -0
- data/spec/lib/seofy/adapters/.base_spec.rb.swo +0 -0
- data/spec/lib/seofy/adapters/base36_spec.rb +27 -0
- data/spec/lib/seofy/adapters/base_spec.rb +22 -0
- data/spec/lib/seofy/adapters/exiting_column_spec.rb +26 -0
- data/spec/lib/seofy/configuration_spec.rb +14 -0
- data/spec/lib/seofy/seofy_spec.rb +4 -0
- data/spec/lib/seofy/task_runner_spec.rb +28 -0
- data/spec/models.rb +9 -0
- data/spec/models_migration.rb +15 -0
- data/spec/spec_helper.rb +24 -0
- metadata +218 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
seofy (0.0.1)
|
5
|
+
activerecord (~> 3.0.0)
|
6
|
+
activesupport (~> 3.0.0)
|
7
|
+
babosa (~> 0.3.0)
|
8
|
+
|
9
|
+
GEM
|
10
|
+
remote: http://rubygems.org/
|
11
|
+
specs:
|
12
|
+
activemodel (3.0.7)
|
13
|
+
activesupport (= 3.0.7)
|
14
|
+
builder (~> 2.1.2)
|
15
|
+
i18n (~> 0.5.0)
|
16
|
+
activerecord (3.0.7)
|
17
|
+
activemodel (= 3.0.7)
|
18
|
+
activesupport (= 3.0.7)
|
19
|
+
arel (~> 2.0.2)
|
20
|
+
tzinfo (~> 0.3.23)
|
21
|
+
activesupport (3.0.7)
|
22
|
+
arel (2.0.10)
|
23
|
+
babosa (0.3.4)
|
24
|
+
builder (2.1.2)
|
25
|
+
diff-lcs (1.1.2)
|
26
|
+
growl (1.0.3)
|
27
|
+
guard (0.3.4)
|
28
|
+
thor (~> 0.14.6)
|
29
|
+
i18n (0.5.0)
|
30
|
+
rspec (2.5.0)
|
31
|
+
rspec-core (~> 2.5.0)
|
32
|
+
rspec-expectations (~> 2.5.0)
|
33
|
+
rspec-mocks (~> 2.5.0)
|
34
|
+
rspec-core (2.5.2)
|
35
|
+
rspec-expectations (2.5.0)
|
36
|
+
diff-lcs (~> 1.1.2)
|
37
|
+
rspec-mocks (2.5.0)
|
38
|
+
sqlite3 (1.3.3)
|
39
|
+
thor (0.14.6)
|
40
|
+
tzinfo (0.3.27)
|
41
|
+
|
42
|
+
PLATFORMS
|
43
|
+
ruby
|
44
|
+
|
45
|
+
DEPENDENCIES
|
46
|
+
growl
|
47
|
+
guard
|
48
|
+
rspec (~> 2.5.0)
|
49
|
+
seofy!
|
50
|
+
sqlite3
|
data/Guardfile
ADDED
data/README.md
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
Seofy
|
2
|
+
====
|
3
|
+
|
4
|
+
A simple plugin make permalink for you records.
|
5
|
+
|
6
|
+
Note: only supprt Rails 3
|
7
|
+
|
8
|
+
|
9
|
+
Installation
|
10
|
+
-----
|
11
|
+
|
12
|
+
gem install seofy
|
13
|
+
|
14
|
+
Rails 3
|
15
|
+
|
16
|
+
gem 'seofy'
|
17
|
+
|
18
|
+
|
19
|
+
Usage
|
20
|
+
-----
|
21
|
+
|
22
|
+
# existing_column adapter
|
23
|
+
class User < ActiveRecord::Base
|
24
|
+
seofy :source => :name, :adapter => :existing_column, :adapter_option => {:column => :slug}
|
25
|
+
end
|
26
|
+
|
27
|
+
# base36 adapter
|
28
|
+
class Store < ActiveRecord::Base
|
29
|
+
seofy :source => :title, :adapter => :base36, :adapter_option => {:length => 3, :column => :slug }
|
30
|
+
end
|
31
|
+
|
32
|
+
User.for_slug("SLUG")
|
33
|
+
|
34
|
+
|
35
|
+
Rake task
|
36
|
+
--------
|
37
|
+
|
38
|
+
rake seofy:update_all MODELS=User,Store
|
39
|
+
|
40
|
+
rake seofy:update_null MODELS=User,Store
|
data/Rakefile
ADDED
data/lib/seofy.rb
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'babosa'
|
2
|
+
require 'seofy/active_record'
|
3
|
+
require 'seofy/configuration'
|
4
|
+
require 'seofy/task_runner'
|
5
|
+
require 'seofy/adapters/base'
|
6
|
+
require 'seofy/adapters/existing_column'
|
7
|
+
require 'seofy/adapters/base36'
|
8
|
+
require 'seofy/encoders/base36'
|
9
|
+
|
10
|
+
module Seofy
|
11
|
+
end
|
12
|
+
|
13
|
+
require "seofy/railtie" if defined?(Rails) && Rails.version >= "3"
|
14
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module Seofy
|
2
|
+
module ActiveRecord
|
3
|
+
module ClassMethods
|
4
|
+
def seofy(options={})
|
5
|
+
init_seofy_config(options)
|
6
|
+
include ::Seofy::ActiveRecord::InstanceMethods
|
7
|
+
before_save :seofy_before_save
|
8
|
+
after_save :seofy_after_save
|
9
|
+
end
|
10
|
+
|
11
|
+
def init_seofy_config(options={})
|
12
|
+
class_attribute :seofy_config
|
13
|
+
self.seofy_config = ::Seofy::Configuration.new(options)
|
14
|
+
end
|
15
|
+
|
16
|
+
def seofy_adapter
|
17
|
+
self.seofy_config.adapter
|
18
|
+
end
|
19
|
+
|
20
|
+
def for_slug(param)
|
21
|
+
self.send("find_by_#{seofy_adapter.column}", param.split("-").last)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module InstanceMethods
|
26
|
+
def to_param
|
27
|
+
[seofy_source.to_s, seofy_slug].join("-").to_slug.normalize.to_s
|
28
|
+
end
|
29
|
+
|
30
|
+
def seofy_slug
|
31
|
+
self.class.seofy_adapter.seofy_slug(self)
|
32
|
+
end
|
33
|
+
|
34
|
+
def seofy_source
|
35
|
+
self.send(self.class.seofy_config.source).to_s
|
36
|
+
end
|
37
|
+
|
38
|
+
def seofy_before_save
|
39
|
+
self.class.seofy_adapter.before_save(self)
|
40
|
+
end
|
41
|
+
|
42
|
+
def seofy_after_save
|
43
|
+
self.class.seofy_adapter.after_save(self)
|
44
|
+
end
|
45
|
+
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
ActiveRecord::Base.extend Seofy::ActiveRecord::ClassMethods
|
File without changes
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module Seofy
|
2
|
+
module Adapters
|
3
|
+
class Base
|
4
|
+
attr_reader :options, :column
|
5
|
+
def initialize(options={})
|
6
|
+
@options = options
|
7
|
+
@column = options[:column]
|
8
|
+
end
|
9
|
+
|
10
|
+
def seofy_slug(inst)
|
11
|
+
raise "not implement"
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_seofy_slug(inst)
|
15
|
+
raise "not implement"
|
16
|
+
end
|
17
|
+
|
18
|
+
def before_save(inst)
|
19
|
+
set_seofy_slug(inst)
|
20
|
+
end
|
21
|
+
|
22
|
+
def after_save(inst)
|
23
|
+
# do nothing
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Seofy
|
2
|
+
module Adapters
|
3
|
+
class Base36 < Base
|
4
|
+
attr_reader :options, :length, :column
|
5
|
+
def initialize(options={})
|
6
|
+
super(options)
|
7
|
+
@length = options[:length]
|
8
|
+
end
|
9
|
+
|
10
|
+
def seofy_slug(inst)
|
11
|
+
inst.send(self.column)
|
12
|
+
end
|
13
|
+
|
14
|
+
def set_seofy_slug(inst)
|
15
|
+
inst.send("#{column}=", ::Seofy::Encoders::Base36.random(self.length))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
module Seofy
|
2
|
+
module Adapters
|
3
|
+
class ExistingColumn < Base
|
4
|
+
attr_reader :column
|
5
|
+
def initialize(options={})
|
6
|
+
super(options)
|
7
|
+
end
|
8
|
+
|
9
|
+
def seofy_slug(inst)
|
10
|
+
inst.send(self.column)
|
11
|
+
end
|
12
|
+
|
13
|
+
def set_seofy_slug(inst)
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
@@ -0,0 +1,11 @@
|
|
1
|
+
module Seofy
|
2
|
+
class Configuration
|
3
|
+
attr_reader :source, :adapter
|
4
|
+
def initialize(options)
|
5
|
+
@source = options[:source]
|
6
|
+
adapter_klass = "seofy/adapters/#{options[:adapter]}".camelize.constantize
|
7
|
+
@adapter = adapter_klass.new(options[:adapter_option])
|
8
|
+
end
|
9
|
+
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
module Seofy
|
2
|
+
module Encoders
|
3
|
+
module Base36
|
4
|
+
THIRTY_SIX = ('0'..'9').to_a + ('a'..'z').to_a
|
5
|
+
LENGTH = THIRTY_SIX.size
|
6
|
+
|
7
|
+
def encode( numeric )
|
8
|
+
raise ArgumentError unless Numeric === numeric
|
9
|
+
|
10
|
+
return '0' if numeric == 0
|
11
|
+
s = ''
|
12
|
+
|
13
|
+
while numeric > 0
|
14
|
+
s << Base36::THIRTY_SIX[numeric.modulo(LENGTH)]
|
15
|
+
numeric /= LENGTH
|
16
|
+
end
|
17
|
+
s.reverse
|
18
|
+
end
|
19
|
+
|
20
|
+
def decode( base36 )
|
21
|
+
s = base36.to_s.reverse.split('')
|
22
|
+
|
23
|
+
total = 0
|
24
|
+
s.each_with_index do |char, index|
|
25
|
+
if ord = THIRTY_SIX.index(char)
|
26
|
+
total += ord * (LENGTH ** index)
|
27
|
+
else
|
28
|
+
raise ArgumentError, "#{base36} has #{char} which is not valid"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
total.to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
def random(length)
|
35
|
+
Array.new(length) { THIRTY_SIX[rand(THIRTY_SIX.size - 1)] }.join
|
36
|
+
end
|
37
|
+
|
38
|
+
module_function :encode, :decode, :random
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,36 @@
|
|
1
|
+
module Seofy
|
2
|
+
class TaskRunner
|
3
|
+
attr_reader :klasses
|
4
|
+
def initialize
|
5
|
+
@klasses = ENV["MODELS"]
|
6
|
+
end
|
7
|
+
|
8
|
+
def each_model
|
9
|
+
self.klasses.split(",").each do |class_name|
|
10
|
+
klass = class_name.constantize
|
11
|
+
yield klass if block_given?
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def update_all
|
16
|
+
each_model do |klass|
|
17
|
+
klass.find_each do |record|
|
18
|
+
update(record)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def update_null
|
24
|
+
each_model do |klass|
|
25
|
+
klass.find_each(:conditions => ["#{klass.seofy_adapter.column} is null"]) do |record|
|
26
|
+
update(record)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def update(record)
|
32
|
+
record.class.seofy_adapter.set_seofy_slug(record)
|
33
|
+
record.save(:validate => false)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
namespace :seofy do
|
2
|
+
desc "update all slug, specify models use ENV['MODELS']"
|
3
|
+
task :update_all => :environment do
|
4
|
+
Seofy::TaskRunner.new.update_all
|
5
|
+
end
|
6
|
+
desc "update null slug, specify models use ENV['MODELS']"
|
7
|
+
task :update_null => :environment do
|
8
|
+
Seofy::TaskRunner.new.update_null
|
9
|
+
end
|
10
|
+
end
|
data/seofy.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "seofy/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "seofy"
|
7
|
+
s.version = Seofy::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Allen Wei"]
|
10
|
+
s.email = ["digruby@gmail.com"]
|
11
|
+
s.homepage = ""
|
12
|
+
s.summary = %q{A flexiable permalink plugin for Rails}
|
13
|
+
s.description = %q{https://github.com/allenwei/seofy}
|
14
|
+
|
15
|
+
s.rubyforge_project = "seofy"
|
16
|
+
|
17
|
+
s.files = `git ls-files`.split("\n")
|
18
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
19
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
20
|
+
s.require_paths = ["lib"]
|
21
|
+
|
22
|
+
s.add_dependency "babosa", "~> 0.3.0"
|
23
|
+
s.add_dependency "activerecord", "~> 3.0.0"
|
24
|
+
s.add_dependency "activesupport", "~> 3.0.0"
|
25
|
+
s.add_development_dependency "sqlite3"
|
26
|
+
s.add_development_dependency "rspec", "~> 2.5.0"
|
27
|
+
s.add_development_dependency "guard"
|
28
|
+
s.add_development_dependency "growl"
|
29
|
+
end
|
data/spec/database.yml
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "slug use base36", :integration => true do
|
4
|
+
before(:all) do
|
5
|
+
@store = Store.create!(:title => "a store")
|
6
|
+
end
|
7
|
+
it "should generate slug automaticly use base36" do
|
8
|
+
@store.slug.length.should == 3
|
9
|
+
@store.to_param.should == "a-store-#{@store.slug}"
|
10
|
+
end
|
11
|
+
|
12
|
+
describe "for_slug" do
|
13
|
+
it "should find the record" do
|
14
|
+
Store.for_slug(@store.to_param).should == @store
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe "slug for existing_column", :integration => true do
|
4
|
+
before(:all) do
|
5
|
+
@user = User.create!(:name => "a user name", :slug => "slug")
|
6
|
+
end
|
7
|
+
|
8
|
+
describe "to_param" do
|
9
|
+
it "should equal to combined slugs" do
|
10
|
+
@user.to_param.should == "a-user-name-slug"
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe "for_slug" do
|
15
|
+
it "should find the record" do
|
16
|
+
User.for_slug(@user.to_param).should == @user
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Seofy::ActiveRecord do
|
4
|
+
context "after mxin ActiveRecord::Base" do
|
5
|
+
it "should have class method :seofy" do
|
6
|
+
ActiveRecord::Base.should be_respond_to(:seofy)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
context "a class extend Seofy::ActiveRecord::ClassMethods" do
|
10
|
+
before(:each) do
|
11
|
+
@klass = Class.new
|
12
|
+
@klass.extend Seofy::ActiveRecord::ClassMethods
|
13
|
+
@klass.should_receive(:init_seofy_config)
|
14
|
+
@klass.should_receive(:after_save)
|
15
|
+
@klass.should_receive(:before_save)
|
16
|
+
@klass.seofy
|
17
|
+
end
|
18
|
+
|
19
|
+
context "klass methods" do
|
20
|
+
subject { @klass }
|
21
|
+
it { should be_respond_to(:seofy) }
|
22
|
+
|
23
|
+
describe "seofy_adapter" do
|
24
|
+
it "should get adapter from config" do
|
25
|
+
@klass.should_receive(:seofy_config).and_return double(:adapter => "dummy adapter")
|
26
|
+
@klass.seofy_adapter
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "for_slug" do
|
31
|
+
it "should get slug from id and find record use it" do
|
32
|
+
@klass.should_receive(:seofy_adapter).and_return double(:column => "id")
|
33
|
+
@klass.should_receive("find_by_id").with("123")
|
34
|
+
@klass.for_slug("a-b-c-123")
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "instance methods" do
|
40
|
+
subject {@klass.new }
|
41
|
+
it { should be_respond_to(:to_param)}
|
42
|
+
it { should be_respond_to(:seofy_slug)}
|
43
|
+
it { should be_respond_to(:seofy_source)}
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "#seofy_source" do
|
47
|
+
it "will get source from inst" do
|
48
|
+
inst = @klass.new
|
49
|
+
@klass.should_receive(:seofy_config).and_return double(:source =>:name)
|
50
|
+
inst.should_receive(:name).and_return("a name")
|
51
|
+
inst.seofy_source.should == "a name"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe "#seofy_slug" do
|
56
|
+
it "should get seofy_slug from adapter" do
|
57
|
+
inst = @klass.new
|
58
|
+
@klass.should_receive(:seofy_adapter).and_return double(:seofy_slug => "abc")
|
59
|
+
inst.seofy_slug.should == "abc"
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
describe "#to_param" do
|
64
|
+
it "should normalize source and join with slug" do
|
65
|
+
inst = @klass.new
|
66
|
+
inst.should_receive(:seofy_slug).and_return("abc")
|
67
|
+
inst.should_receive(:seofy_source).and_return("a normalize name")
|
68
|
+
inst.to_param.should == "a-normalize-name-abc"
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should ask adapter handle callback" do
|
73
|
+
inst = @klass.new
|
74
|
+
@klass.should_receive(:seofy_adapter).and_return double(:before_save => true)
|
75
|
+
@klass.should_receive(:seofy_adapter).and_return double(:after_save => true)
|
76
|
+
inst.seofy_before_save
|
77
|
+
inst.seofy_after_save
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
Binary file
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Seofy::Adapters::Base36 do
|
4
|
+
describe "#initialize" do
|
5
|
+
let(:adapter) { Seofy::Adapters::Base36.new(:length => 3, :column => :slug) }
|
6
|
+
|
7
|
+
it { adapter.length.should == 3 }
|
8
|
+
it { adapter.column.should == :slug }
|
9
|
+
|
10
|
+
describe "#set_seofy_slug" do
|
11
|
+
it "should generate random 3 characters" do
|
12
|
+
stub = Object.new
|
13
|
+
::Seofy::Encoders::Base36.should_receive(:random).with(3).and_return("abc")
|
14
|
+
stub.should_receive("slug=").with("abc")
|
15
|
+
adapter.set_seofy_slug(stub)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#seofy_slug" do
|
20
|
+
it "should equal to slug column" do
|
21
|
+
stub = Object.new
|
22
|
+
stub.should_receive(:slug).and_return("abc")
|
23
|
+
adapter.seofy_slug(stub).should == "abc"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Seofy::Adapters::Base do
|
4
|
+
context "methods" do
|
5
|
+
subject { Seofy::Adapters::Base.new }
|
6
|
+
|
7
|
+
it { should be_respond_to(:seofy_slug) }
|
8
|
+
it { should be_respond_to(:set_seofy_slug) }
|
9
|
+
it { should be_respond_to(:before_save) }
|
10
|
+
it { should be_respond_to(:after_save) }
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#before_save" do
|
14
|
+
it "should set_seofy_slug" do
|
15
|
+
adapter = Seofy::Adapters::Base.new
|
16
|
+
adapter.should_receive(:set_seofy_slug)
|
17
|
+
adapter.before_save("anything")
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Seofy::Adapters::ExistingColumn do
|
4
|
+
it "should get column from options" do
|
5
|
+
inst = Seofy::Adapters::ExistingColumn.new(:column => :id)
|
6
|
+
inst.column.should == :id
|
7
|
+
end
|
8
|
+
|
9
|
+
|
10
|
+
describe "seofy_slug" do
|
11
|
+
it "should get seofy_slug from existing data" do
|
12
|
+
stub = Object.new
|
13
|
+
stub.should_receive(:id).and_return(1)
|
14
|
+
adapter = Seofy::Adapters::ExistingColumn.new(:column => :id)
|
15
|
+
adapter.seofy_slug(stub).should == 1
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "set_seofy_slug" do
|
20
|
+
it "should be false" do
|
21
|
+
adapter = Seofy::Adapters::ExistingColumn.new(:column => :id)
|
22
|
+
adapter.set_seofy_slug("anything").should be_false
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Seofy::Configuration do
|
4
|
+
describe "#initialize" do
|
5
|
+
it "should parse source, adapter and adapter options" do
|
6
|
+
params = {:source => :name, :adapter => :existing_column, :adapter_option => {:column => :id}}
|
7
|
+
stub_adapter = Seofy::Adapters::Base.new
|
8
|
+
Seofy::Adapters::ExistingColumn.should_receive(:new).with(params[:adapter_option]).and_return(stub_adapter)
|
9
|
+
conf = Seofy::Configuration.new(params)
|
10
|
+
conf.source.should == :name
|
11
|
+
conf.adapter.should == stub_adapter
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Seofy::TaskRunner do
|
4
|
+
|
5
|
+
describe "#update_all" do
|
6
|
+
it "should update all slugs" do
|
7
|
+
s1 = Store.create!("store 1")
|
8
|
+
slug1 = s1.slug
|
9
|
+
ENV["MODELS"] = "Store"
|
10
|
+
Seofy::TaskRunner.new.update_all
|
11
|
+
s1.reload.should_not == slug1
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
describe "#update_null" do
|
16
|
+
it "should update all null slugs" do
|
17
|
+
s1 = Store.create!("store 1")
|
18
|
+
Store.connection.execute("update stores set slug = NULL")
|
19
|
+
s1.reload.slug.should be_nil
|
20
|
+
s2 = Store.create!("store 1")
|
21
|
+
old_slug = s2.slug
|
22
|
+
ENV["MODELS"] = "Store"
|
23
|
+
Seofy::TaskRunner.new.update_all
|
24
|
+
s1.reload.should_not be_nil
|
25
|
+
s2.reload.slug.should_not == old_slug
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/spec/models.rb
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# existing_column adapter
|
2
|
+
class User < ActiveRecord::Base
|
3
|
+
seofy :source => :name, :adapter => :existing_column, :adapter_option => {:column => :slug}
|
4
|
+
end
|
5
|
+
|
6
|
+
# base36 adapter
|
7
|
+
class Store < ActiveRecord::Base
|
8
|
+
seofy :source => :title, :adapter => :base36, :adapter_option => {:length => 3, :column => :slug }
|
9
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateModels < ActiveRecord::Migration
|
2
|
+
def self.up
|
3
|
+
create_table :users, :force => true do |t|
|
4
|
+
t.string :name
|
5
|
+
t.string :slug
|
6
|
+
end
|
7
|
+
|
8
|
+
create_table :stores, :force => true do |t|
|
9
|
+
t.string :title
|
10
|
+
t.string :slug
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
14
|
+
|
15
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'rspec'
|
2
|
+
require 'logger'
|
3
|
+
require 'active_record'
|
4
|
+
require 'active_support'
|
5
|
+
require 'yaml'
|
6
|
+
require 'sqlite3'
|
7
|
+
|
8
|
+
$:.unshift File.expand_path("../../lib", __FILE__)
|
9
|
+
require 'seofy'
|
10
|
+
|
11
|
+
require 'models'
|
12
|
+
require 'models_migration'
|
13
|
+
dbconfig = YAML.load_file(File.expand_path("../database.yml",__FILE__))
|
14
|
+
ActiveRecord::Base.establish_connection(dbconfig)
|
15
|
+
|
16
|
+
ActiveRecord::Base.logger = Logger.new($stdout)
|
17
|
+
|
18
|
+
|
19
|
+
CreateModels.up
|
20
|
+
|
21
|
+
RSpec.configure do |c|
|
22
|
+
#c.filter_run_excluding :integration => true
|
23
|
+
end
|
24
|
+
|
metadata
ADDED
@@ -0,0 +1,218 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: seofy
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 29
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 0
|
9
|
+
- 1
|
10
|
+
version: 0.0.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Allen Wei
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2011-05-24 00:00:00 +08:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: babosa
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 19
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
- 3
|
33
|
+
- 0
|
34
|
+
version: 0.3.0
|
35
|
+
type: :runtime
|
36
|
+
version_requirements: *id001
|
37
|
+
- !ruby/object:Gem::Dependency
|
38
|
+
name: activerecord
|
39
|
+
prerelease: false
|
40
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
41
|
+
none: false
|
42
|
+
requirements:
|
43
|
+
- - ~>
|
44
|
+
- !ruby/object:Gem::Version
|
45
|
+
hash: 7
|
46
|
+
segments:
|
47
|
+
- 3
|
48
|
+
- 0
|
49
|
+
- 0
|
50
|
+
version: 3.0.0
|
51
|
+
type: :runtime
|
52
|
+
version_requirements: *id002
|
53
|
+
- !ruby/object:Gem::Dependency
|
54
|
+
name: activesupport
|
55
|
+
prerelease: false
|
56
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ~>
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 7
|
62
|
+
segments:
|
63
|
+
- 3
|
64
|
+
- 0
|
65
|
+
- 0
|
66
|
+
version: 3.0.0
|
67
|
+
type: :runtime
|
68
|
+
version_requirements: *id003
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: sqlite3
|
71
|
+
prerelease: false
|
72
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
73
|
+
none: false
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
hash: 3
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
type: :development
|
82
|
+
version_requirements: *id004
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rspec
|
85
|
+
prerelease: false
|
86
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ~>
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
hash: 27
|
92
|
+
segments:
|
93
|
+
- 2
|
94
|
+
- 5
|
95
|
+
- 0
|
96
|
+
version: 2.5.0
|
97
|
+
type: :development
|
98
|
+
version_requirements: *id005
|
99
|
+
- !ruby/object:Gem::Dependency
|
100
|
+
name: guard
|
101
|
+
prerelease: false
|
102
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
103
|
+
none: false
|
104
|
+
requirements:
|
105
|
+
- - ">="
|
106
|
+
- !ruby/object:Gem::Version
|
107
|
+
hash: 3
|
108
|
+
segments:
|
109
|
+
- 0
|
110
|
+
version: "0"
|
111
|
+
type: :development
|
112
|
+
version_requirements: *id006
|
113
|
+
- !ruby/object:Gem::Dependency
|
114
|
+
name: growl
|
115
|
+
prerelease: false
|
116
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
117
|
+
none: false
|
118
|
+
requirements:
|
119
|
+
- - ">="
|
120
|
+
- !ruby/object:Gem::Version
|
121
|
+
hash: 3
|
122
|
+
segments:
|
123
|
+
- 0
|
124
|
+
version: "0"
|
125
|
+
type: :development
|
126
|
+
version_requirements: *id007
|
127
|
+
description: https://github.com/allenwei/seofy
|
128
|
+
email:
|
129
|
+
- digruby@gmail.com
|
130
|
+
executables: []
|
131
|
+
|
132
|
+
extensions: []
|
133
|
+
|
134
|
+
extra_rdoc_files: []
|
135
|
+
|
136
|
+
files:
|
137
|
+
- .gitignore
|
138
|
+
- Gemfile
|
139
|
+
- Gemfile.lock
|
140
|
+
- Guardfile
|
141
|
+
- README.md
|
142
|
+
- Rakefile
|
143
|
+
- lib/seofy.rb
|
144
|
+
- lib/seofy/active_record.rb
|
145
|
+
- lib/seofy/adapter.rb
|
146
|
+
- lib/seofy/adapters/base.rb
|
147
|
+
- lib/seofy/adapters/base36.rb
|
148
|
+
- lib/seofy/adapters/existing_column.rb
|
149
|
+
- lib/seofy/configuration.rb
|
150
|
+
- lib/seofy/encoders/base36.rb
|
151
|
+
- lib/seofy/railtie.rb
|
152
|
+
- lib/seofy/task_runner.rb
|
153
|
+
- lib/seofy/version.rb
|
154
|
+
- lib/tasks/seofy.rake
|
155
|
+
- seofy.gemspec
|
156
|
+
- spec/database.yml
|
157
|
+
- spec/integration/base36_spec.rb
|
158
|
+
- spec/integration/existing_column_spec.rb
|
159
|
+
- spec/lib/seofy/active_record_spec.rb
|
160
|
+
- spec/lib/seofy/adapters/.base_spec.rb.swo
|
161
|
+
- spec/lib/seofy/adapters/base36_spec.rb
|
162
|
+
- spec/lib/seofy/adapters/base_spec.rb
|
163
|
+
- spec/lib/seofy/adapters/exiting_column_spec.rb
|
164
|
+
- spec/lib/seofy/configuration_spec.rb
|
165
|
+
- spec/lib/seofy/seofy_spec.rb
|
166
|
+
- spec/lib/seofy/task_runner_spec.rb
|
167
|
+
- spec/models.rb
|
168
|
+
- spec/models_migration.rb
|
169
|
+
- spec/spec_helper.rb
|
170
|
+
has_rdoc: true
|
171
|
+
homepage: ""
|
172
|
+
licenses: []
|
173
|
+
|
174
|
+
post_install_message:
|
175
|
+
rdoc_options: []
|
176
|
+
|
177
|
+
require_paths:
|
178
|
+
- lib
|
179
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
180
|
+
none: false
|
181
|
+
requirements:
|
182
|
+
- - ">="
|
183
|
+
- !ruby/object:Gem::Version
|
184
|
+
hash: 3
|
185
|
+
segments:
|
186
|
+
- 0
|
187
|
+
version: "0"
|
188
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
189
|
+
none: false
|
190
|
+
requirements:
|
191
|
+
- - ">="
|
192
|
+
- !ruby/object:Gem::Version
|
193
|
+
hash: 3
|
194
|
+
segments:
|
195
|
+
- 0
|
196
|
+
version: "0"
|
197
|
+
requirements: []
|
198
|
+
|
199
|
+
rubyforge_project: seofy
|
200
|
+
rubygems_version: 1.6.2
|
201
|
+
signing_key:
|
202
|
+
specification_version: 3
|
203
|
+
summary: A flexiable permalink plugin for Rails
|
204
|
+
test_files:
|
205
|
+
- spec/database.yml
|
206
|
+
- spec/integration/base36_spec.rb
|
207
|
+
- spec/integration/existing_column_spec.rb
|
208
|
+
- spec/lib/seofy/active_record_spec.rb
|
209
|
+
- spec/lib/seofy/adapters/.base_spec.rb.swo
|
210
|
+
- spec/lib/seofy/adapters/base36_spec.rb
|
211
|
+
- spec/lib/seofy/adapters/base_spec.rb
|
212
|
+
- spec/lib/seofy/adapters/exiting_column_spec.rb
|
213
|
+
- spec/lib/seofy/configuration_spec.rb
|
214
|
+
- spec/lib/seofy/seofy_spec.rb
|
215
|
+
- spec/lib/seofy/task_runner_spec.rb
|
216
|
+
- spec/models.rb
|
217
|
+
- spec/models_migration.rb
|
218
|
+
- spec/spec_helper.rb
|