vidibus-permalink 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.
@@ -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
+