vidibus-permalink 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,223 @@
1
+ require "spec_helper"
2
+
3
+ describe "Permalink" do
4
+ let(:asset) {Asset.create!(:label => "Something")}
5
+ let(:category) {Category.create!(:label => "Else")}
6
+ let(:this) {Permalink.create!(:value => "Hey Joe!", :linkable => asset)}
7
+ let(:another) {Permalink.create!(:value => "Something", :linkable => asset)}
8
+
9
+ def create_permalink(options = {})
10
+ options[:value] ||= "Super Trouper"
11
+ options[:linkable] ||= asset
12
+ Permalink.create!(options)
13
+ end
14
+
15
+ def stub_stopwords(list)
16
+ I18n.backend.store_translations :en, :vidibus => {:stopwords => list}
17
+ end
18
+
19
+ describe "validation" do
20
+ it "should pass with valid attributes" do
21
+ this.should be_valid
22
+ end
23
+
24
+ it "should fail without a value" do
25
+ this.value = nil
26
+ this.should be_invalid
27
+ end
28
+
29
+ it "should fail without an UUID given on linkable" do
30
+ asset.uuid = nil
31
+ expect {this.linkable}.to raise_error(Permalink::UuidRequiredError)
32
+ end
33
+
34
+ it "should fail if linkable_uuid is invalid" do
35
+ this.linkable_uuid = "something"
36
+ this.should be_invalid
37
+ end
38
+
39
+ it "should fail if linkable_uuid is missing" do
40
+ this.linkable_class = nil
41
+ this.should be_invalid
42
+ end
43
+ end
44
+
45
+ describe "deleting" do
46
+ let(:last) {Permalink.create!(:value => "Buh!", :linkable => asset)}
47
+
48
+ before do
49
+ stub_time!("04.11.2010")
50
+ this
51
+ stub_time!("05.11.2010")
52
+ another
53
+ end
54
+
55
+ it "should not affect other permalinks of the same linkable unless the deleted permalink was the current one" do
56
+ this.reload.destroy.should be_true
57
+ another.reload.current?.should be_true
58
+ end
59
+
60
+ it "should set the lastly updated permalink as current if the deleted permalink was the current one" do
61
+ last.destroy.should be_true
62
+ another.reload.current?.should be_true
63
+ end
64
+
65
+ it "should not affect other permalinks but the last one if the deleted permalink was the current one" do
66
+ last.destroy.should be_true
67
+ this.reload.current?.should be_false
68
+ end
69
+ end
70
+
71
+ describe "#linkable=" do
72
+ let(:this) { Permalink.new }
73
+
74
+ it "should set linkable_uuid" do
75
+ this.linkable = asset
76
+ this.linkable_uuid.should eql(asset.uuid)
77
+ end
78
+
79
+ it "should set linkable_class" do
80
+ this.linkable = asset
81
+ this.linkable_class.should eql("Asset")
82
+ end
83
+ end
84
+
85
+ describe "#linkable" do
86
+ before {this.instance_variable_set("@linkable", nil)}
87
+
88
+ it "should fetch the linkable object" do
89
+ this.linkable.should eql(asset)
90
+ end
91
+
92
+ it "should return nil if no linkable_class has been set" do
93
+ this.linkable_class = nil
94
+ this.linkable.should be_nil
95
+ end
96
+
97
+ it "should return nil if no linkable_uuid has been set" do
98
+ this.linkable_uuid = nil
99
+ this.linkable.should be_nil
100
+ end
101
+ end
102
+
103
+ describe "#value" do
104
+ it "should be sanitized when set" do
105
+ this.value = "Hey Joe!"
106
+ this.value.should eql("hey-joe")
107
+ end
108
+
109
+ context "with stop words" do
110
+ before {stub_stopwords(%w[its a])}
111
+
112
+ it "should be cleaned from stop words before validation" do
113
+ this.value = "It's a beautiful day."
114
+ this.value.should eql("beautiful-day")
115
+ end
116
+
117
+ it "should not be cleaned from stop words if the resulting value would be empty" do
118
+ this.value = "It's a..."
119
+ this.value.should eql("it-s-a")
120
+ end
121
+
122
+ it "should not be cleaned from stop words if the resulting value already exists" do
123
+ Permalink.create!(:value => "It's a beautiful day.", :linkable => asset)
124
+ this = Permalink.new(:value => "It's a beautiful day.")
125
+ this.value.should eql("it-s-a-beautiful-day")
126
+ end
127
+ end
128
+
129
+ describe "incrementation" do
130
+ it "should be performed unless value is unique" do
131
+ this.value = another.value
132
+ this.save.should be_true
133
+ this.value.should_not eql(another.value)
134
+ end
135
+
136
+ it "should not be performed unless value did change" do
137
+ this.update_attributes(:value => "It's a beautiful day.")
138
+ dont_allow(this).increment
139
+ this.value = "It's a beautiful day."
140
+ end
141
+
142
+ it "should append 2 as first number" do
143
+ first = create_permalink
144
+ create_permalink.value.should eql("super-trouper-2")
145
+ end
146
+
147
+ it "should append 3 if 2 is already taken" do
148
+ create_permalink
149
+ create_permalink
150
+ create_permalink.value.should eql("super-trouper-3")
151
+ end
152
+
153
+ it "should append 2 if 3 is taken but 2 has been deleted" do
154
+ create_permalink
155
+ second = create_permalink
156
+ create_permalink
157
+ second.reload.destroy
158
+ create_permalink.value.should eql("super-trouper-2")
159
+ end
160
+ end
161
+ end
162
+
163
+ describe "#current?" do
164
+ it "should return true after creation" do
165
+ this.current?.should be_true
166
+ end
167
+
168
+ it "should return true after update" do
169
+ another
170
+ this.save
171
+ this.reload.current?.should be_true
172
+ end
173
+
174
+ it "should return false on all other permalinks of the assigned linkable" do
175
+ first = create_permalink
176
+ second = create_permalink
177
+ third = create_permalink
178
+ first.reload.current?.should be_false
179
+ second.reload.current?.should be_false
180
+ third.reload.current?.should be_true
181
+ end
182
+
183
+ it "should not affect permalinks of other linkables" do
184
+ this
185
+ another = Permalink.create!(:value => "Buh!", :linkable => category)
186
+ another.current?.should be_true
187
+ this.reload.current?.should be_true
188
+ end
189
+ end
190
+
191
+ describe "#current" do
192
+ before {this; another}
193
+
194
+ it "should return self for the current permalink" do
195
+ another.reload.current.should eql(another)
196
+ end
197
+
198
+ it "should return the current permalink of the given linkable" do
199
+ this.reload.current.should eql(another)
200
+ end
201
+ end
202
+
203
+ describe ".for_value" do
204
+ it "should return finder conditions to retreive permalinks for the given value" do
205
+ this; another
206
+ Permalink.for_value("Hey Joe!").to_a.should have(1).permalink
207
+ end
208
+ end
209
+
210
+ describe ".for_linkable" do
211
+ it "should return finder conditions to retreive permalinks for the given object" do
212
+ this
213
+ Permalink.create!(:value => "Buh!", :linkable => category)
214
+ Permalink.for_linkable(asset).to_a.should have(1).permalink
215
+ end
216
+ end
217
+
218
+ describe ".dispatch" do
219
+ it "should return a Vidibus::Permalink::Dispatcher object" do
220
+ Permalink.dispatch("/something").should be_a(Vidibus::Permalink::Dispatcher)
221
+ end
222
+ end
223
+ end
@@ -0,0 +1,41 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
2
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", "lib"))
3
+
4
+ require "rubygems"
5
+ require "rspec"
6
+ require "rr"
7
+ require "mongoid"
8
+ require "active_support/core_ext"
9
+ require "vidibus-core_extensions"
10
+ require "vidibus-uuid"
11
+ require "vidibus-words"
12
+
13
+ require "models"
14
+ require "vidibus-permalink"
15
+ require "app/models/permalink"
16
+
17
+ Mongoid.configure do |config|
18
+ name = "vidibus-permalink_test"
19
+ host = "localhost"
20
+ config.master = Mongo::Connection.new.db(name)
21
+ config.logger = nil
22
+ end
23
+
24
+ RSpec.configure do |config|
25
+ config.mock_with :rr
26
+ config.before(:each) do
27
+ Mongoid.master.collections.select {|c| c.name !~ /system/}.each(&:drop)
28
+ end
29
+ end
30
+
31
+ I18n.load_path += Dir[File.join('config', 'locales', '**', '*.{rb,yml}')]
32
+
33
+ # Helper for stubbing time. Define String to be set as Time.now.
34
+ # Usage:
35
+ # stub_time!('01.01.2010 14:00')
36
+ # stub_time!(2.days.ago)
37
+ def stub_time!(string = nil)
38
+ now = string ? Time.parse(string.to_s) : Time.now
39
+ stub(Time).now { now }
40
+ now
41
+ end
@@ -0,0 +1,122 @@
1
+ require "spec_helper"
2
+
3
+ describe "Vidibus::Permalink::Dispatcher" do
4
+ describe "Dispatcher" do
5
+
6
+ let(:category) {Category.create!}
7
+ let(:asset) {Asset.create!}
8
+ let(:category_permalink) {Permalink.create!(:value => "Something", :linkable => category)}
9
+ let(:asset_permalink) {Permalink.create!(:value => "Pretty", :linkable => asset)}
10
+ let(:this) {Vidibus::Permalink::Dispatcher.new("/something/pretty")}
11
+
12
+ describe "initializing" do
13
+ it "should require a path" do
14
+ expect {Vidibus::Permalink::Dispatcher.new}.to raise_error(ArgumentError)
15
+ end
16
+
17
+ it "should require an absolute request path" do
18
+ expect {Vidibus::Permalink::Dispatcher.new("something/pretty")}.
19
+ to raise_error(Vidibus::Permalink::Dispatcher::PathError)
20
+ end
21
+
22
+ it "should accept an absolute request path" do
23
+ this.should be_a(Vidibus::Permalink::Dispatcher)
24
+ end
25
+ end
26
+
27
+ describe "#path" do
28
+ it "should return the given request path" do
29
+ this.path.should eql("/something/pretty")
30
+ end
31
+ end
32
+
33
+ describe "#parts" do
34
+ it "should contain the parts of the given path" do
35
+ this.parts.should eql(%w[something pretty])
36
+ end
37
+ end
38
+
39
+ describe "#objects" do
40
+ before do
41
+ category_permalink
42
+ asset_permalink
43
+ end
44
+
45
+ it "should contain all permalinks of given path" do
46
+ this.objects.should eql([category_permalink, asset_permalink])
47
+ end
48
+
49
+ it "should reflect the order of the parts in request path" do
50
+ this = Vidibus::Permalink::Dispatcher.new("/pretty/something")
51
+ this.objects.should eql([asset_permalink, category_permalink])
52
+ end
53
+
54
+ it "should contain empty records for unresolvable parts of the path" do
55
+ this = Vidibus::Permalink::Dispatcher.new("/some/pretty")
56
+ this.objects.should eql([nil, asset_permalink])
57
+ end
58
+
59
+ it "should not contain more than one permalink per linkable" do
60
+ Permalink.create!(:value => "New", :linkable => asset)
61
+ this = Vidibus::Permalink::Dispatcher.new("/pretty/new")
62
+ this.objects.should eql([asset_permalink, nil])
63
+ end
64
+ end
65
+
66
+ describe "found?" do
67
+ before do
68
+ category_permalink
69
+ asset_permalink
70
+ end
71
+
72
+ it "should return true if all parts of the request path could be resolved" do
73
+ this.found?.should be_true
74
+ end
75
+
76
+ it "should return false if any part of the request path could not be resolved" do
77
+ this = Vidibus::Permalink::Dispatcher.new("/some/pretty")
78
+ this.found?.should be_false
79
+ end
80
+ end
81
+
82
+ describe "#redirect?" do
83
+ before do
84
+ category_permalink
85
+ asset_permalink
86
+ Permalink.create!(:value => "New", :linkable => asset)
87
+ end
88
+
89
+ it "should return true if any part of the path is not current" do
90
+ this.redirect?.should be_true
91
+ end
92
+
93
+ it "should return false if all parts of the request path are current" do
94
+ this = Vidibus::Permalink::Dispatcher.new("/something/new")
95
+ this.redirect?.should be_false
96
+ end
97
+
98
+ it "should return nil if path could not be resolved" do
99
+ this = Vidibus::Permalink::Dispatcher.new("/something/ugly")
100
+ this.redirect?.should be_nil
101
+ end
102
+ end
103
+
104
+ describe "#redirect_path" do
105
+ before do
106
+ category_permalink
107
+ asset_permalink
108
+ Permalink.create!(:value => "New", :linkable => asset)
109
+ end
110
+
111
+ it "should return the current request path" do
112
+ this = Vidibus::Permalink::Dispatcher.new("/something/pretty")
113
+ this.redirect_path.should eql("/something/new")
114
+ end
115
+
116
+ it "should return nil if redirecting is not necessary" do
117
+ this = Vidibus::Permalink::Dispatcher.new("/something/new")
118
+ this.redirect_path.should be_nil
119
+ end
120
+ end
121
+ end
122
+ end
@@ -0,0 +1,147 @@
1
+ require "spec_helper"
2
+
3
+ class Model
4
+ include Mongoid::Document
5
+ include Vidibus::Uuid::Mongoid
6
+ include Vidibus::Permalink::Mongoid
7
+ field :name
8
+ permalink :name
9
+ end
10
+
11
+ class Appointment
12
+ include Mongoid::Document
13
+ include Vidibus::Uuid::Mongoid
14
+ include Vidibus::Permalink::Mongoid
15
+ field :reason
16
+ field :location
17
+ permalink :reason, :location
18
+ end
19
+
20
+ class Car
21
+ include Mongoid::Document
22
+ include Vidibus::Uuid::Mongoid
23
+ include Vidibus::Permalink::Mongoid
24
+ field :make
25
+ end
26
+
27
+ describe "Vidibus::Permalink::Mongoid" do
28
+
29
+ let(:john) {Model.new(:name => "John Malkovich")}
30
+ let(:appointment) {Appointment.create(:location => "Bistro", :reason => "Lunch")}
31
+
32
+ describe "permalink" do
33
+ it "should set permalink attribute before validation" do
34
+ john.valid?
35
+ john.permalink.should eql("john-malkovich")
36
+ end
37
+
38
+ it "should persist the permalink" do
39
+ john.save
40
+ john = Model.first
41
+ john.permalink.should eql("john-malkovich")
42
+ end
43
+
44
+ it "should create a permalink object from given attribute after creation" do
45
+ john.save
46
+ permalink = Permalink.first
47
+ permalink.value.should eql("john-malkovich")
48
+ end
49
+
50
+ it "should not store a new permalink object unless attribute value did change" do
51
+ john.save
52
+ john.save
53
+ Permalink.all.to_a.should have(1).object
54
+ end
55
+
56
+ it "should store a new permalink if attributes change" do
57
+ john.save
58
+ john.update_attributes(:name => "Inkognito")
59
+ john.reload.permalink.should eql("inkognito")
60
+ end
61
+
62
+ it "should store a new permalink object if permalink changes" do
63
+ john.save
64
+ john.update_attributes(:name => "Inkognito")
65
+ permalinks = Permalink.all.to_a
66
+ permalinks.should have(2).permalinks
67
+ permalinks.last.value.should eql("inkognito")
68
+ permalinks.last.should be_current
69
+ end
70
+
71
+ it "should should set a former permalink object as current if possible" do
72
+ john.save
73
+ john.update_attributes(:name => "Inkognito")
74
+ john.update_attributes(:name => "John Malkovich")
75
+ permalinks = Permalink.all.to_a
76
+ permalinks.should have(2).objects
77
+ permalinks.first.should be_current
78
+ end
79
+
80
+ it "should accept multiple attributes" do
81
+ appointment.permalink.should eql("lunch-bistro")
82
+ end
83
+
84
+ it "should be updatable" do
85
+ appointment.update_attributes(:reason => "Drinking")
86
+ appointment.permalink.should eql("drinking-bistro")
87
+ end
88
+
89
+ it "should raise an error unless permalink attributes have been defined" do
90
+ expect {Car.create(:make => "Porsche")}.to raise_error(Car::PermalinkConfigurationError)
91
+ end
92
+ end
93
+
94
+ describe "destroying" do
95
+ it "should trigger deleting of all permalink objects with linkable" do
96
+ appointment.destroy
97
+ Permalink.all.to_a.should have(:no).permalinks
98
+ end
99
+
100
+ it "should not delete permalink objects of other linkables" do
101
+ john.save
102
+ appointment.destroy
103
+ Permalink.all.to_a.should have(1).permalink
104
+ end
105
+ end
106
+
107
+ describe "#permalink" do
108
+ it "should trigger an error if blank" do
109
+ model = Model.new(:permalink => "")
110
+ model.should be_invalid
111
+ model.errors[:permalink].should have(1).error
112
+ end
113
+ end
114
+
115
+ describe "#permalink_object" do
116
+ it "should return the current permalink object" do
117
+ appointment.update_attributes(:reason => "Drinking")
118
+ permalink = appointment.permalink_object
119
+ permalink.should be_a(Permalink)
120
+ permalink.value.should eql(appointment.permalink)
121
+ permalink.should be_current
122
+ end
123
+
124
+ it "should return the permalink object assigned recently" do
125
+ appointment.reason = "Drinking"
126
+ appointment.valid?
127
+ appointment.permalink_object.should be_a_new_record
128
+ end
129
+ end
130
+
131
+ describe "#permalink_objects" do
132
+ it "should return all permalink objects ordered by time of update" do
133
+ stub_time!("04.11.2010")
134
+ appointment.update_attributes(:reason => "Drinking")
135
+ stub_time!("05.11.2010")
136
+ appointment.update_attributes(:reason => "Lunch")
137
+ permalinks = appointment.permalink_objects
138
+ permalinks[0].value.should eql("drinking-bistro")
139
+ permalinks[1].value.should eql("lunch-bistro")
140
+ end
141
+
142
+ it "should only return permalink objects assigned to the current linkable" do
143
+ john.save
144
+ appointment.permalink_objects.to_a.should have(1).permalink
145
+ end
146
+ end
147
+ end
@@ -0,0 +1,80 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{vidibus-permalink}
8
+ s.version = "0.0.1"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Andre Pankratz"]
12
+ s.date = %q{2010-11-16}
13
+ s.description = %q{Allows changeable permalinks (good for SEO).}
14
+ s.email = %q{andre@vidibus.com}
15
+ s.extra_rdoc_files = [
16
+ "LICENSE",
17
+ "README.rdoc"
18
+ ]
19
+ s.files = [
20
+ ".bundle/config",
21
+ ".document",
22
+ ".gitignore",
23
+ ".rspec",
24
+ "Gemfile",
25
+ "Gemfile.lock",
26
+ "LICENSE",
27
+ "README.rdoc",
28
+ "Rakefile",
29
+ "VERSION",
30
+ "app/models/permalink.rb",
31
+ "lib/vidibus-permalink.rb",
32
+ "lib/vidibus/permalink.rb",
33
+ "lib/vidibus/permalink/dispatcher.rb",
34
+ "lib/vidibus/permalink/mongoid.rb",
35
+ "spec/models.rb",
36
+ "spec/permalink_spec.rb",
37
+ "spec/spec_helper.rb",
38
+ "spec/vidibus/permalink/dispatcher_spec.rb",
39
+ "spec/vidibus/permalink/mongoid_spec.rb",
40
+ "vidibus-permalink.gemspec"
41
+ ]
42
+ s.homepage = %q{http://github.com/vidibus/vidibus-permalink}
43
+ s.rdoc_options = ["--charset=UTF-8"]
44
+ s.require_paths = ["lib"]
45
+ s.rubygems_version = %q{1.3.7}
46
+ s.summary = %q{Permalink handling}
47
+ s.test_files = [
48
+ "spec/models.rb",
49
+ "spec/permalink_spec.rb",
50
+ "spec/spec_helper.rb",
51
+ "spec/vidibus/permalink/dispatcher_spec.rb",
52
+ "spec/vidibus/permalink/mongoid_spec.rb"
53
+ ]
54
+
55
+ if s.respond_to? :specification_version then
56
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
57
+ s.specification_version = 3
58
+
59
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
60
+ s.add_runtime_dependency(%q<rails>, ["~> 3.0.0"])
61
+ s.add_runtime_dependency(%q<mongoid>, ["~> 2.0.0.beta.20"])
62
+ s.add_runtime_dependency(%q<vidibus-core_extensions>, [">= 0"])
63
+ s.add_runtime_dependency(%q<vidibus-uuid>, [">= 0"])
64
+ s.add_runtime_dependency(%q<vidibus-words>, [">= 0"])
65
+ else
66
+ s.add_dependency(%q<rails>, ["~> 3.0.0"])
67
+ s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.20"])
68
+ s.add_dependency(%q<vidibus-core_extensions>, [">= 0"])
69
+ s.add_dependency(%q<vidibus-uuid>, [">= 0"])
70
+ s.add_dependency(%q<vidibus-words>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<rails>, ["~> 3.0.0"])
74
+ s.add_dependency(%q<mongoid>, ["~> 2.0.0.beta.20"])
75
+ s.add_dependency(%q<vidibus-core_extensions>, [">= 0"])
76
+ s.add_dependency(%q<vidibus-uuid>, [">= 0"])
77
+ s.add_dependency(%q<vidibus-words>, [">= 0"])
78
+ end
79
+ end
80
+