seofy 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|