acts-as-taggable-on 1.0.13 → 2.0.0

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.
Files changed (40) hide show
  1. data/CHANGELOG +5 -2
  2. data/Gemfile +6 -0
  3. data/README.rdoc +61 -31
  4. data/Rakefile +46 -16
  5. data/VERSION +1 -1
  6. data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +7 -0
  7. data/generators/acts_as_taggable_on_migration/templates/migration.rb +29 -0
  8. data/lib/acts-as-taggable-on.rb +30 -7
  9. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +53 -0
  10. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +98 -0
  11. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +237 -0
  12. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +101 -0
  13. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +64 -0
  14. data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +43 -373
  15. data/lib/acts_as_taggable_on/acts_as_tagger.rb +58 -43
  16. data/lib/acts_as_taggable_on/compatibility/Gemfile +6 -0
  17. data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +17 -0
  18. data/lib/acts_as_taggable_on/tag.rb +47 -8
  19. data/lib/acts_as_taggable_on/tag_list.rb +45 -45
  20. data/lib/acts_as_taggable_on/tagging.rb +17 -2
  21. data/lib/acts_as_taggable_on/tags_helper.rb +8 -2
  22. data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +31 -0
  23. data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +28 -0
  24. data/rails/init.rb +1 -7
  25. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +98 -53
  26. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +46 -4
  27. data/spec/acts_as_taggable_on/tag_list_spec.rb +18 -0
  28. data/spec/acts_as_taggable_on/tag_spec.rb +66 -13
  29. data/spec/acts_as_taggable_on/taggable_spec.rb +142 -70
  30. data/spec/acts_as_taggable_on/tagger_spec.rb +73 -5
  31. data/spec/acts_as_taggable_on/tagging_spec.rb +18 -3
  32. data/spec/acts_as_taggable_on/tags_helper_spec.rb +1 -3
  33. data/spec/bm.rb +52 -0
  34. data/spec/models.rb +30 -0
  35. data/spec/schema.rb +13 -2
  36. data/spec/spec.opts +1 -2
  37. data/spec/spec_helper.rb +39 -34
  38. metadata +28 -8
  39. data/lib/acts_as_taggable_on/group_helper.rb +0 -12
  40. data/spec/acts_as_taggable_on/group_helper_spec.rb +0 -18
@@ -2,25 +2,36 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
3
  describe Tag do
4
4
  before(:each) do
5
+ clean_database!
5
6
  @tag = Tag.new
6
- @user = TaggableModel.create(:name => "Pablo")
7
- Tag.delete_all
7
+ @user = TaggableModel.create(:name => "Pablo")
8
8
  end
9
-
9
+
10
+ describe "named like any" do
11
+ before(:each) do
12
+ Tag.create(:name => "awesome")
13
+ Tag.create(:name => "epic")
14
+ end
15
+
16
+ it "should find both tags" do
17
+ Tag.named_like_any(["awesome", "epic"]).should have(2).items
18
+ end
19
+ end
20
+
10
21
  describe "find or create by name" do
11
22
  before(:each) do
12
23
  @tag.name = "awesome"
13
24
  @tag.save
14
25
  end
15
-
26
+
16
27
  it "should find by name" do
17
28
  Tag.find_or_create_with_like_by_name("awesome").should == @tag
18
29
  end
19
-
30
+
20
31
  it "should find by name case insensitive" do
21
32
  Tag.find_or_create_with_like_by_name("AWESOME").should == @tag
22
33
  end
23
-
34
+
24
35
  it "should create by name" do
25
36
  lambda {
26
37
  Tag.find_or_create_with_like_by_name("epic")
@@ -28,35 +39,77 @@ describe Tag do
28
39
  end
29
40
  end
30
41
 
42
+ describe "find or create all by any name" do
43
+ before(:each) do
44
+ @tag.name = "awesome"
45
+ @tag.save
46
+ end
47
+
48
+ it "should find by name" do
49
+ Tag.find_or_create_all_with_like_by_name("awesome").should == [@tag]
50
+ end
51
+
52
+ it "should find by name case insensitive" do
53
+ Tag.find_or_create_all_with_like_by_name("AWESOME").should == [@tag]
54
+ end
55
+
56
+ it "should create by name" do
57
+ lambda {
58
+ Tag.find_or_create_all_with_like_by_name("epic")
59
+ }.should change(Tag, :count).by(1)
60
+ end
61
+
62
+ it "should find or create by name" do
63
+ lambda {
64
+ Tag.find_or_create_all_with_like_by_name("awesome", "epic").map(&:name).should == ["awesome", "epic"]
65
+ }.should change(Tag, :count).by(1)
66
+ end
67
+
68
+ it "should return an empty array if no tags are specified" do
69
+ Tag.find_or_create_all_with_like_by_name([]).should == []
70
+ end
71
+ end
72
+
31
73
  it "should require a name" do
32
74
  @tag.valid?
33
- @tag.errors.on(:name).should == "can't be blank"
75
+
76
+ if ActiveRecord::VERSION::MAJOR >= 3
77
+ @tag.errors[:name].should == ["can't be blank"]
78
+ else
79
+ @tag.errors[:name].should == "can't be blank"
80
+ end
81
+
34
82
  @tag.name = "something"
35
83
  @tag.valid?
36
- @tag.errors.on(:name).should be_nil
84
+
85
+ if ActiveRecord::VERSION::MAJOR >= 3
86
+ @tag.errors[:name].should == []
87
+ else
88
+ @tag.errors[:name].should be_nil
89
+ end
37
90
  end
38
-
91
+
39
92
  it "should equal a tag with the same name" do
40
93
  @tag.name = "awesome"
41
94
  new_tag = Tag.new(:name => "awesome")
42
95
  new_tag.should == @tag
43
96
  end
44
-
97
+
45
98
  it "should return its name when to_s is called" do
46
99
  @tag.name = "cool"
47
100
  @tag.to_s.should == "cool"
48
101
  end
49
-
102
+
50
103
  it "have named_scope named(something)" do
51
104
  @tag.name = "cool"
52
105
  @tag.save!
53
106
  Tag.named('cool').should include(@tag)
54
107
  end
55
-
108
+
56
109
  it "have named_scope named_like(something)" do
57
110
  @tag.name = "cool"
58
111
  @tag.save!
59
112
  @another_tag = Tag.create!(:name => "coolip")
60
113
  Tag.named_like('cool').should include(@tag, @another_tag)
61
114
  end
62
- end
115
+ end
@@ -2,49 +2,61 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
3
  describe "Taggable" do
4
4
  before(:each) do
5
- [TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
5
+ clean_database!
6
6
  @taggable = TaggableModel.new(:name => "Bob Jones")
7
7
  end
8
8
 
9
9
  it "should have tag types" do
10
- TaggableModel.tag_types.should == [:tags, :languages, :skills, :needs, :offerings]
10
+ [:tags, :languages, :skills, :needs, :offerings].each do |type|
11
+ TaggableModel.tag_types.should include type
12
+ end
13
+
11
14
  @taggable.tag_types.should == TaggableModel.tag_types
12
15
  end
13
16
 
14
17
  it "should have tag_counts_on" do
15
- TaggableModel.tag_counts_on(:tags).should be_empty
16
-
18
+ TaggableModel.tag_counts_on(:tags).all.should be_empty
19
+
17
20
  @taggable.tag_list = ["awesome", "epic"]
18
21
  @taggable.save
19
22
 
20
- TaggableModel.tag_counts_on(:tags).count.should == 2
21
- @taggable.tag_counts_on(:tags).count.should == 2
23
+ TaggableModel.tag_counts_on(:tags).length.should == 2
24
+ @taggable.tag_counts_on(:tags).length.should == 2
22
25
  end
23
-
26
+
24
27
  it "should be able to create tags" do
25
28
  @taggable.skill_list = "ruby, rails, css"
26
29
  @taggable.instance_variable_get("@skill_list").instance_of?(TagList).should be_true
27
- @taggable.save
28
30
 
29
- Tag.find(:all).size.should == 3
31
+ lambda {
32
+ @taggable.save
33
+ }.should change(Tag, :count).by(3)
34
+
35
+ @taggable.reload
36
+ @taggable.skill_list.sort.should == %w(ruby rails css).sort
30
37
  end
31
-
38
+
32
39
  it "should be able to create tags through the tag list directly" do
33
40
  @taggable.tag_list_on(:test).add("hello")
34
- @taggable.save
41
+ @taggable.tag_list_cache_on(:test).should_not be_empty
42
+ @taggable.tag_list_on(:test).should == ["hello"]
43
+
44
+ @taggable.save
45
+ @taggable.save_tags
46
+
35
47
  @taggable.reload
36
48
  @taggable.tag_list_on(:test).should == ["hello"]
37
49
  end
38
-
50
+
39
51
  it "should differentiate between contexts" do
40
52
  @taggable.skill_list = "ruby, rails, css"
41
53
  @taggable.tag_list = "ruby, bob, charlie"
42
54
  @taggable.save
43
55
  @taggable.reload
44
- @taggable.skill_list.include?("ruby").should be_true
45
- @taggable.skill_list.include?("bob").should be_false
56
+ @taggable.skill_list.should include("ruby")
57
+ @taggable.skill_list.should_not include("bob")
46
58
  end
47
-
59
+
48
60
  it "should be able to remove tags through list alone" do
49
61
  @taggable.skill_list = "ruby, rails, css"
50
62
  @taggable.save
@@ -55,74 +67,83 @@ describe "Taggable" do
55
67
  @taggable.reload
56
68
  @taggable.should have(2).skills
57
69
  end
58
-
70
+
59
71
  it "should be able to find by tag" do
60
72
  @taggable.skill_list = "ruby, rails, css"
61
73
  @taggable.save
62
- TaggableModel.find_tagged_with("ruby").first.should == @taggable
74
+
75
+ TaggableModel.tagged_with("ruby").first.should == @taggable
63
76
  end
64
-
77
+
65
78
  it "should be able to find by tag with context" do
66
79
  @taggable.skill_list = "ruby, rails, css"
67
80
  @taggable.tag_list = "bob, charlie"
68
81
  @taggable.save
69
- TaggableModel.find_tagged_with("ruby").first.should == @taggable
70
- TaggableModel.find_tagged_with("bob", :on => :skills).first.should_not == @taggable
71
- TaggableModel.find_tagged_with("bob", :on => :tags).first.should == @taggable
72
- end
73
-
74
- it "should be able to use the tagged_with named scope" do
75
- @taggable.skill_list = "ruby, rails, css"
76
- @taggable.tag_list = "bob, charlie"
77
- @taggable.save
78
-
82
+
79
83
  TaggableModel.tagged_with("ruby").first.should == @taggable
84
+ TaggableModel.tagged_with("ruby, css").first.should == @taggable
80
85
  TaggableModel.tagged_with("bob", :on => :skills).first.should_not == @taggable
81
86
  TaggableModel.tagged_with("bob", :on => :tags).first.should == @taggable
82
87
  end
83
-
88
+
84
89
  it "should not care about case" do
85
90
  bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby")
86
91
  frank = TaggableModel.create(:name => "Frank", :tag_list => "Ruby")
87
-
92
+
88
93
  Tag.find(:all).size.should == 1
89
- TaggableModel.find_tagged_with("ruby").should == TaggableModel.find_tagged_with("Ruby")
94
+ TaggableModel.tagged_with("ruby").to_a.should == TaggableModel.tagged_with("Ruby").to_a
90
95
  end
91
-
96
+
92
97
  it "should be able to get tag counts on model as a whole" do
93
98
  bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
94
99
  frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
95
100
  charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
96
- TaggableModel.tag_counts.should_not be_empty
97
- TaggableModel.skill_counts.should_not be_empty
101
+ TaggableModel.tag_counts.all.should_not be_empty
102
+ TaggableModel.skill_counts.all.should_not be_empty
98
103
  end
99
-
104
+
100
105
  it "should be able to get all tag counts on model as whole" do
101
106
  bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
102
107
  frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
103
108
  charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
104
-
105
- TaggableModel.all_tag_counts.should_not be_empty
109
+
110
+ TaggableModel.all_tag_counts.all.should_not be_empty
106
111
  TaggableModel.all_tag_counts.first.count.should == 3 # ruby
107
112
  end
108
-
113
+
114
+ if ActiveRecord::VERSION::MAJOR >= 3
115
+ it "should not return read-only records" do
116
+ TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
117
+ TaggableModel.tagged_with("ruby").first.should_not be_readonly
118
+ end
119
+ else
120
+ xit "should not return read-only records" do
121
+ # apparantly, there is no way to set readonly to false in a scope if joins are made
122
+ end
123
+
124
+ it "should be possible to return writable records" do
125
+ TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
126
+ TaggableModel.tagged_with("ruby").first(:readonly => false).should_not be_readonly
127
+ end
128
+ end
129
+
109
130
  it "should be able to get scoped tag counts" do
110
131
  bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
111
132
  frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
112
133
  charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
113
-
134
+
114
135
  TaggableModel.tagged_with("ruby").tag_counts.first.count.should == 2 # ruby
115
136
  TaggableModel.tagged_with("ruby").skill_counts.first.count.should == 1 # ruby
116
137
  end
117
-
138
+
118
139
  it "should be able to get all scoped tag counts" do
119
140
  bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
120
141
  frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
121
142
  charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
122
-
143
+
123
144
  TaggableModel.tagged_with("ruby").all_tag_counts.first.count.should == 3 # ruby
124
145
  end
125
-
146
+
126
147
  it "should be able to set a custom tag context list" do
127
148
  bob = TaggableModel.create(:name => "Bob")
128
149
  bob.set_tag_list_on(:rotors, "spinning, jumping")
@@ -131,89 +152,140 @@ describe "Taggable" do
131
152
  bob.reload
132
153
  bob.tags_on(:rotors).should_not be_empty
133
154
  end
134
-
155
+
135
156
  it "should be able to find tagged" do
136
157
  bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
137
158
  frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
138
159
  steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
139
-
140
- TaggableModel.find_tagged_with("ruby", :order => 'taggable_models.name').should == [bob, frank, steve]
141
- TaggableModel.find_tagged_with("ruby, rails", :order => 'taggable_models.name').should == [bob, frank]
142
- TaggableModel.find_tagged_with(["ruby", "rails"], :order => 'taggable_models.name').should == [bob, frank]
160
+
161
+ TaggableModel.tagged_with("ruby", :order => 'taggable_models.name').to_a.should == [bob, frank, steve]
162
+ TaggableModel.tagged_with("ruby, rails", :order => 'taggable_models.name').to_a.should == [bob, frank]
163
+ TaggableModel.tagged_with(["ruby", "rails"], :order => 'taggable_models.name').to_a.should == [bob, frank]
143
164
  end
144
-
165
+
166
+ it "should be able to find tagged with any tag" do
167
+ bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
168
+ frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
169
+ steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
170
+
171
+ TaggableModel.tagged_with(["ruby", "java"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank, steve]
172
+ TaggableModel.tagged_with(["c++", "fitter"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, steve]
173
+ TaggableModel.tagged_with(["depressed", "css"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank]
174
+ end
175
+
145
176
  it "should be able to find tagged on a custom tag context" do
146
177
  bob = TaggableModel.create(:name => "Bob")
147
178
  bob.set_tag_list_on(:rotors, "spinning, jumping")
148
179
  bob.tag_list_on(:rotors).should == ["spinning","jumping"]
149
180
  bob.save
150
- TaggableModel.find_tagged_with("spinning", :on => :rotors).should == [bob]
181
+
182
+ TaggableModel.tagged_with("spinning", :on => :rotors).to_a.should == [bob]
151
183
  end
152
184
 
153
185
  it "should be able to use named scopes to chain tag finds" do
154
186
  bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
155
187
  frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
156
188
  steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, python')
157
-
189
+
158
190
  # Let's only find those productive Rails developers
159
- TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').should == [bob, frank]
160
- TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').should == [bob, steve]
161
- TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).should == [bob]
162
- TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).should == [bob]
191
+ TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').to_a.should == [bob, frank]
192
+ TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').to_a.should == [bob, steve]
193
+ TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).to_a.should == [bob]
194
+ TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).to_a.should == [bob]
163
195
  end
164
-
196
+
165
197
  it "should be able to find tagged with only the matching tags" do
166
198
  bob = TaggableModel.create(:name => "Bob", :tag_list => "lazy, happier")
167
199
  frank = TaggableModel.create(:name => "Frank", :tag_list => "fitter, happier, inefficient")
168
200
  steve = TaggableModel.create(:name => 'Steve', :tag_list => "fitter, happier")
169
-
170
- TaggableModel.find_tagged_with("fitter, happier", :match_all => true).should == [steve]
201
+
202
+ TaggableModel.tagged_with("fitter, happier", :match_all => true).to_a.should == [steve]
171
203
  end
172
-
204
+
173
205
  it "should be able to find tagged with some excluded tags" do
174
206
  bob = TaggableModel.create(:name => "Bob", :tag_list => "happier, lazy")
175
207
  frank = TaggableModel.create(:name => "Frank", :tag_list => "happier")
176
208
  steve = TaggableModel.create(:name => 'Steve', :tag_list => "happier")
209
+
210
+ TaggableModel.tagged_with("lazy", :exclude => true).to_a.should == [frank, steve]
211
+ end
212
+
213
+ it "should not create duplicate taggings" do
214
+ bob = TaggableModel.create(:name => "Bob")
215
+ lambda {
216
+ bob.tag_list << "happier"
217
+ bob.tag_list << "happier"
218
+ bob.save
219
+ }.should change(Tagging, :count).by(1)
220
+ end
221
+
222
+ describe "Associations" do
223
+ before(:each) do
224
+ @taggable = TaggableModel.create(:tag_list => "awesome, epic")
225
+ end
177
226
 
178
- TaggableModel.find_tagged_with("lazy", :exclude => true).should == [frank, steve]
227
+ it "should not remove tags when creating associated objects" do
228
+ @taggable.untaggable_models.create!
229
+ @taggable.reload
230
+ @taggable.tag_list.should have(2).items
231
+ end
179
232
  end
180
-
233
+
234
+ describe "grouped_column_names_for method" do
235
+ it "should return all column names joined for Tag GROUP clause" do
236
+ @taggable.grouped_column_names_for(Tag).should == "tags.id, tags.name"
237
+ end
238
+
239
+ it "should return all column names joined for TaggableModel GROUP clause" do
240
+ @taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.id, taggable_models.name, taggable_models.type"
241
+ end
242
+ end
243
+
181
244
  describe "Single Table Inheritance" do
182
245
  before do
183
- [TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
184
246
  @taggable = TaggableModel.new(:name => "taggable")
185
247
  @inherited_same = InheritingTaggableModel.new(:name => "inherited same")
186
248
  @inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
187
249
  end
188
-
250
+
189
251
  it "should be able to save tags for inherited models" do
190
252
  @inherited_same.tag_list = "bob, kelso"
191
253
  @inherited_same.save
192
- InheritingTaggableModel.find_tagged_with("bob").first.should == @inherited_same
254
+ InheritingTaggableModel.tagged_with("bob").first.should == @inherited_same
193
255
  end
194
-
256
+
195
257
  it "should find STI tagged models on the superclass" do
196
258
  @inherited_same.tag_list = "bob, kelso"
197
259
  @inherited_same.save
198
- TaggableModel.find_tagged_with("bob").first.should == @inherited_same
260
+ TaggableModel.tagged_with("bob").first.should == @inherited_same
199
261
  end
200
-
262
+
201
263
  it "should be able to add on contexts only to some subclasses" do
202
264
  @inherited_different.part_list = "fork, spoon"
203
265
  @inherited_different.save
204
- InheritingTaggableModel.find_tagged_with("fork", :on => :parts).should be_empty
205
- AlteredInheritingTaggableModel.find_tagged_with("fork", :on => :parts).first.should == @inherited_different
266
+ InheritingTaggableModel.tagged_with("fork", :on => :parts).should be_empty
267
+ AlteredInheritingTaggableModel.tagged_with("fork", :on => :parts).first.should == @inherited_different
206
268
  end
207
-
269
+
208
270
  it "should have different tag_counts_on for inherited models" do
209
271
  @inherited_same.tag_list = "bob, kelso"
210
272
  @inherited_same.save!
211
273
  @inherited_different.tag_list = "fork, spoon"
212
274
  @inherited_different.save!
213
-
275
+
214
276
  InheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso)
215
277
  AlteredInheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(fork spoon)
216
278
  TaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso fork spoon)
217
279
  end
280
+
281
+ it 'should store same tag without validation conflict' do
282
+ @taggable.tag_list = 'one'
283
+ @taggable.save!
284
+
285
+ @inherited_same.tag_list = 'one'
286
+ @inherited_same.save!
287
+
288
+ @inherited_same.update_attributes! :name => 'foo'
289
+ end
218
290
  end
219
291
  end
@@ -2,21 +2,89 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
3
  describe "Tagger" do
4
4
  before(:each) do
5
- [TaggableModel, Tag, Tagging, TaggableUser].each(&:delete_all)
6
- @user = TaggableUser.new
7
- @taggable = TaggableModel.new(:name => "Bob Jones")
5
+ clean_database!
6
+ @user = TaggableUser.create
7
+ @taggable = TaggableModel.create(:name => "Bob Jones")
8
8
  end
9
-
9
+
10
10
  it "should have taggings" do
11
11
  @user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
12
12
  @user.owned_taggings.size == 2
13
13
  end
14
-
14
+
15
15
  it "should have tags" do
16
16
  @user.tag(@taggable, :with=>'ruby,scheme', :on=>:tags)
17
17
  @user.owned_tags.size == 2
18
18
  end
19
19
 
20
+ it "should not overlap tags from different taggers" do
21
+ @user2 = TaggableUser.new
22
+ lambda{
23
+ @user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
24
+ @user2.tag(@taggable, :with => 'java, python, lisp, ruby', :on => :tags)
25
+ }.should change(Tagging, :count).by(6)
26
+
27
+ [@user, @user2, @taggable].each(&:reload)
28
+
29
+ @user.owned_tags.map(&:name).sort.should == %w(ruby scheme).sort
30
+ @user2.owned_tags.map(&:name).sort.should == %w(java python lisp ruby).sort
31
+
32
+ @taggable.tags_from(@user).sort.should == %w(ruby scheme).sort
33
+ @taggable.tags_from(@user2).sort.should == %w(java lisp python ruby).sort
34
+
35
+ @taggable.all_tags_list.sort.should == %w(ruby scheme java python lisp).sort
36
+ @taggable.all_tags_on(:tags).size.should == 5
37
+ end
38
+
39
+ it "should not lose tags from different taggers" do
40
+ @user2 = TaggableUser.create
41
+ @user2.tag(@taggable, :with => 'java, python, lisp, ruby', :on => :tags)
42
+ @user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
43
+
44
+ lambda {
45
+ @user2.tag(@taggable, :with => 'java, python, lisp', :on => :tags)
46
+ }.should change(Tagging, :count).by(-1)
47
+
48
+ [@user, @user2, @taggable].each(&:reload)
49
+
50
+ @taggable.tags_from(@user).sort.should == %w(ruby scheme).sort
51
+ @taggable.tags_from(@user2).sort.should == %w(java python lisp).sort
52
+
53
+ @taggable.all_tags_list.sort.should == %w(ruby scheme java python lisp).sort
54
+ @taggable.all_tags_on(:tags).length.should == 5
55
+ end
56
+
57
+ it "should not lose tags" do
58
+ @user2 = TaggableUser.create
59
+
60
+ @user.tag(@taggable, :with => 'awesome', :on => :tags)
61
+ @user2.tag(@taggable, :with => 'awesome, epic', :on => :tags)
62
+
63
+ lambda {
64
+ @user2.tag(@taggable, :with => 'epic', :on => :tags)
65
+ }.should change(Tagging, :count).by(-1)
66
+
67
+ @taggable.reload
68
+ @taggable.all_tags_list.should include('awesome')
69
+ @taggable.all_tags_list.should include('epic')
70
+ end
71
+
72
+ it "should not lose tags" do
73
+ @taggable.update_attributes(:tag_list => 'ruby')
74
+ @user.tag(@taggable, :with => 'ruby, scheme', :on => :tags)
75
+
76
+ [@taggable, @user].each(&:reload)
77
+ @taggable.tag_list.should == %w(ruby)
78
+ @taggable.all_tags_list.sort.should == %w(ruby scheme).sort
79
+
80
+ lambda {
81
+ @taggable.update_attributes(:tag_list => "")
82
+ }.should change(Tagging, :count).by(-1)
83
+
84
+ @taggable.tag_list.should == []
85
+ @taggable.all_tags_list.sort.should == %w(ruby scheme).sort
86
+ end
87
+
20
88
  it "is tagger" do
21
89
  @user.is_tagger?.should(be_true)
22
90
  end
@@ -2,15 +2,30 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
3
  describe Tagging do
4
4
  before(:each) do
5
+ clean_database!
5
6
  @tagging = Tagging.new
6
7
  end
7
-
8
+
8
9
  it "should not be valid with a invalid tag" do
9
10
  @tagging.taggable = TaggableModel.create(:name => "Bob Jones")
10
11
  @tagging.tag = Tag.new(:name => "")
11
12
  @tagging.context = "tags"
12
13
 
13
14
  @tagging.should_not be_valid
14
- @tagging.errors.on(:tag_id).should == "can't be blank"
15
+
16
+ if ActiveRecord::VERSION::MAJOR >= 3
17
+ @tagging.errors[:tag_id].should == ["can't be blank"]
18
+ else
19
+ @tagging.errors[:tag_id].should == "can't be blank"
20
+ end
21
+ end
22
+
23
+ it "should not create duplicate taggings" do
24
+ @taggable = TaggableModel.create(:name => "Bob Jones")
25
+ @tag = Tag.create(:name => "awesome")
26
+
27
+ lambda {
28
+ 2.times { Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags') }
29
+ }.should change(Tagging, :count).by(1)
15
30
  end
16
- end
31
+ end
@@ -2,7 +2,7 @@ require File.dirname(__FILE__) + '/../spec_helper'
2
2
 
3
3
  describe TagsHelper do
4
4
  before(:each) do
5
- [TaggableModel, Tag, Tagging].each(&:delete_all)
5
+ clean_database!
6
6
 
7
7
  @bob = TaggableModel.create(:name => "Bob Jones", :language_list => "ruby, php")
8
8
  @tom = TaggableModel.create(:name => "Tom Marley", :language_list => "ruby, java")
@@ -11,8 +11,6 @@ describe TagsHelper do
11
11
  @helper = class Helper
12
12
  include TagsHelper
13
13
  end.new
14
-
15
-
16
14
  end
17
15
 
18
16
  it "should yield the proper css classes" do