acts-as-taggable-on 3.1.1 → 3.2.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.
Files changed (72) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -1
  3. data/.travis.yml +9 -7
  4. data/Appraisals +13 -8
  5. data/CHANGELOG.md +8 -0
  6. data/Gemfile +1 -2
  7. data/README.md +23 -13
  8. data/Rakefile +5 -17
  9. data/UPGRADING.md +6 -0
  10. data/acts-as-taggable-on.gemspec +13 -13
  11. data/db/migrate/1_acts_as_taggable_on_migration.rb +3 -3
  12. data/db/migrate/2_add_missing_unique_indices.rb +3 -5
  13. data/db/migrate/3_add_taggings_counter_cache_to_tags.rb +1 -1
  14. data/gemfiles/activerecord_3.2.gemfile +15 -0
  15. data/gemfiles/activerecord_4.0.gemfile +15 -0
  16. data/gemfiles/activerecord_4.1.gemfile +15 -0
  17. data/gemfiles/activerecord_edge.gemfile +16 -0
  18. data/lib/acts-as-taggable-on.rb +23 -21
  19. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +1 -4
  20. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +29 -20
  21. data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +11 -10
  22. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +98 -80
  23. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +5 -12
  24. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +7 -7
  25. data/lib/acts_as_taggable_on/engine.rb +0 -1
  26. data/lib/acts_as_taggable_on/tag.rb +24 -19
  27. data/lib/acts_as_taggable_on/tag_list.rb +95 -21
  28. data/lib/acts_as_taggable_on/taggable.rb +28 -30
  29. data/lib/acts_as_taggable_on/tagger.rb +30 -18
  30. data/lib/acts_as_taggable_on/tagging.rb +7 -8
  31. data/lib/acts_as_taggable_on/tags_helper.rb +1 -1
  32. data/lib/acts_as_taggable_on/utils.rb +25 -3
  33. data/lib/acts_as_taggable_on/version.rb +1 -1
  34. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +133 -138
  35. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +55 -58
  36. data/spec/acts_as_taggable_on/caching_spec.rb +34 -35
  37. data/spec/acts_as_taggable_on/related_spec.rb +59 -113
  38. data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +118 -95
  39. data/spec/acts_as_taggable_on/tag_list_spec.rb +89 -57
  40. data/spec/acts_as_taggable_on/tag_spec.rb +125 -114
  41. data/spec/acts_as_taggable_on/taggable_spec.rb +538 -352
  42. data/spec/acts_as_taggable_on/tagger_spec.rb +81 -78
  43. data/spec/acts_as_taggable_on/tagging_spec.rb +13 -14
  44. data/spec/acts_as_taggable_on/tags_helper_spec.rb +25 -25
  45. data/spec/acts_as_taggable_on/utils_spec.rb +9 -9
  46. data/spec/internal/app/models/altered_inheriting_taggable_model.rb +3 -0
  47. data/spec/internal/app/models/cached_model.rb +3 -0
  48. data/spec/internal/app/models/cached_model_with_array.rb +5 -0
  49. data/spec/internal/app/models/company.rb +15 -0
  50. data/spec/internal/app/models/inheriting_taggable_model.rb +2 -0
  51. data/spec/internal/app/models/market.rb +2 -0
  52. data/spec/{models.rb → internal/app/models/models.rb} +34 -2
  53. data/spec/internal/app/models/non_standard_id_taggable_model.rb +8 -0
  54. data/spec/internal/app/models/ordered_taggable_model.rb +4 -0
  55. data/spec/internal/app/models/other_cached_model.rb +3 -0
  56. data/spec/internal/app/models/other_taggable_model.rb +4 -0
  57. data/spec/internal/app/models/student.rb +2 -0
  58. data/spec/internal/app/models/taggable_model.rb +13 -0
  59. data/spec/internal/app/models/untaggable_model.rb +3 -0
  60. data/spec/internal/app/models/user.rb +3 -0
  61. data/spec/{database.yml.sample → internal/config/database.yml.sample} +2 -2
  62. data/spec/internal/db/schema.rb +97 -0
  63. data/spec/schema.rb +11 -0
  64. data/spec/spec_helper.rb +9 -62
  65. data/spec/support/array.rb +9 -0
  66. data/spec/support/database.rb +42 -0
  67. data/spec/support/database_cleaner.rb +17 -0
  68. metadata +101 -37
  69. data/gemfiles/rails_3.2.gemfile +0 -7
  70. data/gemfiles/rails_4.0.gemfile +0 -7
  71. data/gemfiles/rails_4.1.gemfile +0 -7
  72. data/gemfiles/rails_edge.gemfile +0 -7
@@ -9,201 +9,211 @@ end
9
9
 
10
10
  describe ActsAsTaggableOn::Tag do
11
11
  before(:each) do
12
- clean_database!
13
12
  @tag = ActsAsTaggableOn::Tag.new
14
- @user = TaggableModel.create(:name => "Pablo")
13
+ @user = TaggableModel.create(name: 'Pablo')
15
14
  end
16
15
 
17
- describe "named like any" do
18
- context "case insensitive collation and unique index on tag name" do
19
- if described_class.using_case_insensitive_collation?
16
+
17
+
18
+ describe 'named like any' do
19
+ context 'case insensitive collation and unique index on tag name' do
20
+ if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
20
21
  before(:each) do
21
- ActsAsTaggableOn::Tag.create(:name => "Awesome")
22
- ActsAsTaggableOn::Tag.create(:name => "epic")
22
+ ActsAsTaggableOn::Tag.create(name: 'Awesome')
23
+ ActsAsTaggableOn::Tag.create(name: 'epic')
23
24
  end
24
25
 
25
- it "should find both tags" do
26
- ActsAsTaggableOn::Tag.named_like_any(["awesome", "epic"]).should have(2).items
26
+ it 'should find both tags' do
27
+ expect(ActsAsTaggableOn::Tag.named_like_any(%w(awesome epic)).count).to eq(2)
27
28
  end
28
29
  end
29
30
  end
30
31
 
31
- context "case insensitive collation without indexes or case sensitive collation with indexes" do
32
- if described_class.using_case_insensitive_collation?
32
+ context 'case insensitive collation without indexes or case sensitive collation with indexes' do
33
+ if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
33
34
  include_context 'without unique index'
34
35
  end
35
36
 
36
37
  before(:each) do
37
- ActsAsTaggableOn::Tag.create(:name => "Awesome")
38
- ActsAsTaggableOn::Tag.create(:name => "awesome")
39
- ActsAsTaggableOn::Tag.create(:name => "epic")
38
+ ActsAsTaggableOn::Tag.create(name: 'Awesome')
39
+ ActsAsTaggableOn::Tag.create(name: 'awesome')
40
+ ActsAsTaggableOn::Tag.create(name: 'epic')
40
41
  end
41
42
 
42
- it "should find both tags" do
43
- ActsAsTaggableOn::Tag.named_like_any(["awesome", "epic"]).should have(3).items
43
+ it 'should find both tags' do
44
+ expect(ActsAsTaggableOn::Tag.named_like_any(%w(awesome epic)).count).to eq(3)
44
45
  end
45
46
  end
46
47
  end
47
48
 
48
- describe "find or create by name" do
49
+ describe 'find or create by name' do
49
50
  before(:each) do
50
- @tag.name = "awesome"
51
+ @tag.name = 'awesome'
51
52
  @tag.save
52
53
  end
53
54
 
54
- it "should find by name" do
55
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("awesome").should == @tag
55
+ it 'should find by name' do
56
+ expect(ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('awesome')).to eq(@tag)
56
57
  end
57
58
 
58
- it "should find by name case insensitive" do
59
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("AWESOME").should == @tag
59
+ it 'should find by name case insensitive' do
60
+ expect(ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('AWESOME')).to eq(@tag)
60
61
  end
61
62
 
62
- it "should create by name" do
63
- lambda {
64
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("epic")
65
- }.should change(ActsAsTaggableOn::Tag, :count).by(1)
63
+ it 'should create by name' do
64
+ expect(-> {
65
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('epic')
66
+ }).to change(ActsAsTaggableOn::Tag, :count).by(1)
66
67
  end
67
68
  end
68
69
 
69
- unless ActsAsTaggableOn::Tag.using_sqlite?
70
- describe "find or create by unicode name" do
70
+ unless ActsAsTaggableOn::Utils.using_sqlite?
71
+ describe 'find or create by unicode name' do
71
72
  before(:each) do
72
- @tag.name = "привет"
73
+ @tag.name = 'привет'
73
74
  @tag.save
74
75
  end
75
76
 
76
- it "should find by name" do
77
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("привет").should == @tag
77
+ it 'should find by name' do
78
+ expect(ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('привет')).to eq(@tag)
79
+ end
80
+
81
+ it 'should find by name case insensitive' do
82
+ expect(ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('ПРИВЕТ')).to eq(@tag)
78
83
  end
79
84
 
80
- it "should find by name case insensitive" do
81
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("ПРИВЕТ").should == @tag
85
+ if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
86
+ it 'should find by name accent insensitive' do
87
+ @tag.name = 'inupiat'
88
+ @tag.save
89
+ expect(ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('Iñupiat')).to eq(@tag)
90
+ end
82
91
  end
83
92
  end
84
93
  end
85
94
 
86
- describe "find or create all by any name" do
95
+ describe 'find or create all by any name' do
87
96
  before(:each) do
88
- @tag.name = "awesome"
97
+ @tag.name = 'awesome'
89
98
  @tag.save
90
99
  end
91
100
 
92
- it "should find by name" do
93
- ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("awesome").should == [@tag]
101
+ it 'should find by name' do
102
+ expect(ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name('awesome')).to eq([@tag])
94
103
  end
95
104
 
96
- it "should find by name case insensitive" do
97
- ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("AWESOME").should == [@tag]
105
+ it 'should find by name case insensitive' do
106
+ expect(ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name('AWESOME')).to eq([@tag])
98
107
  end
99
108
 
100
- context "case sensitive" do
101
- if described_class.using_case_insensitive_collation?
109
+ context 'case sensitive' do
110
+ if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
102
111
  include_context 'without unique index'
103
112
  end
104
113
 
105
- it "should find by name case sensitive" do
114
+ it 'should find by name case sensitive' do
106
115
  ActsAsTaggableOn.strict_case_match = true
107
116
  expect {
108
- ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("AWESOME")
117
+ ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name('AWESOME')
109
118
  }.to change(ActsAsTaggableOn::Tag, :count).by(1)
110
119
  end
111
120
  end
112
121
 
113
- it "should create by name" do
122
+ it 'should create by name' do
114
123
  expect {
115
- ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("epic")
124
+ ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name('epic')
116
125
  }.to change(ActsAsTaggableOn::Tag, :count).by(1)
117
126
  end
118
127
 
119
- context "case sensitive" do
120
- if described_class.using_case_insensitive_collation?
128
+ context 'case sensitive' do
129
+ if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
121
130
  include_context 'without unique index'
122
131
  end
123
132
 
124
- it "should find or create by name case sensitive" do
133
+ it 'should find or create by name case sensitive' do
125
134
  ActsAsTaggableOn.strict_case_match = true
126
135
  expect {
127
- ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("AWESOME", 'awesome').map(&:name).should == ["AWESOME", "awesome"]
136
+ expect(ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name('AWESOME', 'awesome').map(&:name)).to eq(%w(AWESOME awesome))
128
137
  }.to change(ActsAsTaggableOn::Tag, :count).by(1)
129
138
  end
130
139
  end
131
140
 
132
- it "should find or create by name" do
141
+ it 'should find or create by name' do
133
142
  expect {
134
- ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("awesome", "epic").map(&:name).should == ["awesome", "epic"]
143
+ expect(ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name('awesome', 'epic').map(&:name)).to eq(%w(awesome epic))
135
144
  }.to change(ActsAsTaggableOn::Tag, :count).by(1)
136
145
  end
137
146
 
138
- it "should return an empty array if no tags are specified" do
139
- ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name([]).should == []
147
+ it 'should return an empty array if no tags are specified' do
148
+ expect(ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name([])).to be_empty
140
149
  end
141
150
  end
142
151
 
143
- it "should require a name" do
152
+ it 'should require a name' do
144
153
  @tag.valid?
154
+ #TODO, we should find another way to check this
155
+ expect(@tag.errors[:name]).to eq(["can't be blank"])
145
156
 
146
- @tag.errors[:name].should == ["can't be blank"]
147
-
148
- @tag.name = "something"
157
+ @tag.name = 'something'
149
158
  @tag.valid?
150
159
 
151
- @tag.errors[:name].should == []
160
+ expect(@tag.errors[:name]).to be_empty
152
161
  end
153
162
 
154
- it "should limit the name length to 255 or less characters" do
155
- @tag.name = "fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxranr"
163
+ it 'should limit the name length to 255 or less characters' do
164
+ @tag.name = 'fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxranr'
156
165
  @tag.valid?
157
- @tag.errors[:name].should == ["is too long (maximum is 255 characters)"]
166
+ #TODO, we should find another way to check this
167
+ expect(@tag.errors[:name]).to eq(['is too long (maximum is 255 characters)'])
158
168
 
159
- @tag.name = "fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxran"
169
+ @tag.name = 'fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxran'
160
170
  @tag.valid?
161
- @tag.errors[:name].should == []
171
+ expect(@tag.errors[:name]).to be_empty
162
172
  end
163
173
 
164
- it "should equal a tag with the same name" do
165
- @tag.name = "awesome"
166
- new_tag = ActsAsTaggableOn::Tag.new(:name => "awesome")
167
- new_tag.should == @tag
174
+ it 'should equal a tag with the same name' do
175
+ @tag.name = 'awesome'
176
+ new_tag = ActsAsTaggableOn::Tag.new(name: 'awesome')
177
+ expect(new_tag).to eq(@tag)
168
178
  end
169
179
 
170
- it "should return its name when to_s is called" do
171
- @tag.name = "cool"
172
- @tag.to_s.should == "cool"
180
+ it 'should return its name when to_s is called' do
181
+ @tag.name = 'cool'
182
+ expect(@tag.to_s).to eq('cool')
173
183
  end
174
184
 
175
- it "have named_scope named(something)" do
176
- @tag.name = "cool"
185
+ it 'have named_scope named(something)' do
186
+ @tag.name = 'cool'
177
187
  @tag.save!
178
- ActsAsTaggableOn::Tag.named('cool').should include(@tag)
188
+ expect(ActsAsTaggableOn::Tag.named('cool')).to include(@tag)
179
189
  end
180
190
 
181
- it "have named_scope named_like(something)" do
182
- @tag.name = "cool"
191
+ it 'have named_scope named_like(something)' do
192
+ @tag.name = 'cool'
183
193
  @tag.save!
184
- @another_tag = ActsAsTaggableOn::Tag.create!(:name => "coolip")
185
- ActsAsTaggableOn::Tag.named_like('cool').should include(@tag, @another_tag)
194
+ @another_tag = ActsAsTaggableOn::Tag.create!(name: 'coolip')
195
+ expect(ActsAsTaggableOn::Tag.named_like('cool')).to include(@tag, @another_tag)
186
196
  end
187
197
 
188
- describe "escape wildcard symbols in like requests" do
198
+ describe 'escape wildcard symbols in like requests' do
189
199
  before(:each) do
190
- @tag.name = "cool"
200
+ @tag.name = 'cool'
191
201
  @tag.save
192
- @another_tag = ActsAsTaggableOn::Tag.create!(:name => "coo%")
193
- @another_tag2 = ActsAsTaggableOn::Tag.create!(:name => "coolish")
202
+ @another_tag = ActsAsTaggableOn::Tag.create!(name: 'coo%')
203
+ @another_tag2 = ActsAsTaggableOn::Tag.create!(name: 'coolish')
194
204
  end
195
205
 
196
206
  it "return escaped result when '%' char present in tag" do
197
- ActsAsTaggableOn::Tag.named_like('coo%').should_not include(@tag)
198
- ActsAsTaggableOn::Tag.named_like('coo%').should include(@another_tag)
207
+ expect(ActsAsTaggableOn::Tag.named_like('coo%')).to_not include(@tag)
208
+ expect(ActsAsTaggableOn::Tag.named_like('coo%')).to include(@another_tag)
199
209
  end
200
210
 
201
211
  end
202
212
 
203
- describe "when using strict_case_match" do
213
+ describe 'when using strict_case_match' do
204
214
  before do
205
215
  ActsAsTaggableOn.strict_case_match = true
206
- @tag.name = "awesome"
216
+ @tag.name = 'awesome'
207
217
  @tag.save!
208
218
  end
209
219
 
@@ -211,71 +221,72 @@ describe ActsAsTaggableOn::Tag do
211
221
  ActsAsTaggableOn.strict_case_match = false
212
222
  end
213
223
 
214
- it "should find by name" do
215
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("awesome").should == @tag
224
+ it 'should find by name' do
225
+ expect(ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('awesome')).to eq(@tag)
216
226
  end
217
227
 
218
- context "case sensitive" do
219
- if described_class.using_case_insensitive_collation?
228
+ context 'case sensitive' do
229
+ if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
220
230
  include_context 'without unique index'
221
231
  end
222
232
 
223
- it "should find by name case sensitively" do
233
+ it 'should find by name case sensitively' do
224
234
  expect {
225
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("AWESOME")
235
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name('AWESOME')
226
236
  }.to change(ActsAsTaggableOn::Tag, :count)
227
237
 
228
- ActsAsTaggableOn::Tag.last.name.should == "AWESOME"
238
+ expect(ActsAsTaggableOn::Tag.last.name).to eq('AWESOME')
229
239
  end
230
240
  end
231
241
 
232
- context "case sensitive" do
233
- if described_class.using_case_insensitive_collation?
242
+ context 'case sensitive' do
243
+ if ActsAsTaggableOn::Utils.using_case_insensitive_collation?
234
244
  include_context 'without unique index'
235
245
  end
236
246
 
237
- it "should have a named_scope named(something) that matches exactly" do
238
- uppercase_tag = ActsAsTaggableOn::Tag.create(:name => "Cool")
239
- @tag.name = "cool"
247
+ it 'should have a named_scope named(something) that matches exactly' do
248
+ uppercase_tag = ActsAsTaggableOn::Tag.create(name: 'Cool')
249
+ @tag.name = 'cool'
240
250
  @tag.save!
241
251
 
242
- ActsAsTaggableOn::Tag.named('cool').should include(@tag)
243
- ActsAsTaggableOn::Tag.named('cool').should_not include(uppercase_tag)
252
+ expect(ActsAsTaggableOn::Tag.named('cool')).to include(@tag)
253
+ expect(ActsAsTaggableOn::Tag.named('cool')).to_not include(uppercase_tag)
244
254
  end
245
255
  end
246
256
 
247
- it "should not change enconding" do
257
+ it 'should not change enconding' do
248
258
  name = "\u3042"
249
259
  original_encoding = name.encoding
250
- ActsAsTaggableOn::Tag.find_or_create_with_like_by_name(name)
251
- name.encoding.should == original_encoding
260
+ record = ActsAsTaggableOn::Tag.find_or_create_with_like_by_name(name)
261
+ record.reload
262
+ expect(record.name.encoding).to eq(original_encoding)
252
263
  end
253
264
  end
254
265
 
255
- describe "name uniqeness validation" do
256
- let(:duplicate_tag) { ActsAsTaggableOn::Tag.new(:name => 'ror') }
266
+ describe 'name uniqeness validation' do
267
+ let(:duplicate_tag) { ActsAsTaggableOn::Tag.new(name: 'ror') }
257
268
 
258
- before { ActsAsTaggableOn::Tag.create(:name => 'ror') }
269
+ before { ActsAsTaggableOn::Tag.create(name: 'ror') }
259
270
 
260
271
  context "when don't need unique names" do
261
272
  include_context 'without unique index'
262
- it "should not run uniqueness validation" do
263
- duplicate_tag.stub(:validates_name_uniqueness?).and_return(false)
273
+ it 'should not run uniqueness validation' do
274
+ allow(duplicate_tag).to receive(:validates_name_uniqueness?) { false }
264
275
  duplicate_tag.save
265
- duplicate_tag.should be_persisted
276
+ expect(duplicate_tag).to be_persisted
266
277
  end
267
278
  end
268
279
 
269
- context "when do need unique names" do
270
- it "should run uniqueness validation" do
271
- duplicate_tag.should_not be_valid
280
+ context 'when do need unique names' do
281
+ it 'should run uniqueness validation' do
282
+ expect(duplicate_tag).to_not be_valid
272
283
  end
273
284
 
274
- it "add error to name" do
285
+ it 'add error to name' do
275
286
  duplicate_tag.save
276
287
 
277
- duplicate_tag.should have(1).errors
278
- duplicate_tag.errors.messages[:name].should include('has already been taken')
288
+ expect(duplicate_tag.errors.size).to eq(1)
289
+ expect(duplicate_tag.errors.messages[:name]).to include('has already been taken')
279
290
  end
280
291
  end
281
292
  end
@@ -1,622 +1,738 @@
1
1
  # encoding: utf-8
2
2
  require 'spec_helper'
3
3
 
4
- describe "Taggable To Preserve Order" do
4
+ describe 'Taggable To Preserve Order' do
5
5
  before(:each) do
6
- clean_database!
7
- @taggable = OrderedTaggableModel.new(:name => "Bob Jones")
6
+ @taggable = OrderedTaggableModel.new(name: 'Bob Jones')
8
7
  end
9
8
 
10
- it "should have tag types" do
11
- [:tags, :colours].each do |type|
12
- OrderedTaggableModel.tag_types.should include type
13
- end
14
-
15
- @taggable.tag_types.should == OrderedTaggableModel.tag_types
16
- end
17
9
 
18
- it "should have tag associations" do
10
+ it 'should have tag associations' do
19
11
  [:tags, :colours].each do |type|
20
- @taggable.respond_to?(type).should be_true
21
- @taggable.respond_to?("#{type.to_s.singularize}_taggings").should be_true
12
+ expect(@taggable.respond_to?(type)).to be_truthy
13
+ expect(@taggable.respond_to?("#{type.to_s.singularize}_taggings")).to be_truthy
22
14
  end
23
15
  end
24
16
 
25
- # it "should have tag associations ordered by id" do
26
- # [:tags, :colours].each do |type|
27
- # OrderedTaggableModel.reflect_on_association(type).options[:order].should include('id')
28
- # OrderedTaggableModel.reflect_on_association("#{type.to_s.singularize}_taggings".to_sym).options[:order].should include('id')
29
- # end
30
- # end
31
-
32
- it "should have tag methods" do
17
+ it 'should have tag methods' do
33
18
  [:tags, :colours].each do |type|
34
- @taggable.respond_to?("#{type.to_s.singularize}_list").should be_true
35
- @taggable.respond_to?("#{type.to_s.singularize}_list=").should be_true
36
- @taggable.respond_to?("all_#{type.to_s}_list").should be_true
19
+ expect(@taggable.respond_to?("#{type.to_s.singularize}_list")).to be_truthy
20
+ expect(@taggable.respond_to?("#{type.to_s.singularize}_list=")).to be_truthy
21
+ expect(@taggable.respond_to?("all_#{type}_list")).to be_truthy
37
22
  end
38
23
  end
39
24
 
40
- it "should return tag list in the order the tags were created" do
25
+ it 'should return tag list in the order the tags were created' do
41
26
  # create
42
- @taggable.tag_list = "rails, ruby, css"
43
- @taggable.instance_variable_get("@tag_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
27
+ @taggable.tag_list = 'rails, ruby, css'
28
+ expect(@taggable.instance_variable_get('@tag_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
44
29
 
45
- lambda {
30
+ expect(-> {
46
31
  @taggable.save
47
- }.should change(ActsAsTaggableOn::Tag, :count).by(3)
32
+ }).to change(ActsAsTaggableOn::Tag, :count).by(3)
48
33
 
49
34
  @taggable.reload
50
- @taggable.tag_list.should == %w(rails ruby css)
35
+ expect(@taggable.tag_list).to eq(%w(rails ruby css))
51
36
 
52
37
  # update
53
- @taggable.tag_list = "pow, ruby, rails"
38
+ @taggable.tag_list = 'pow, ruby, rails'
54
39
  @taggable.save
55
40
 
56
41
  @taggable.reload
57
- @taggable.tag_list.should == %w(pow ruby rails)
42
+ expect(@taggable.tag_list).to eq(%w(pow ruby rails))
58
43
 
59
44
  # update with no change
60
- @taggable.tag_list = "pow, ruby, rails"
45
+ @taggable.tag_list = 'pow, ruby, rails'
61
46
  @taggable.save
62
47
 
63
48
  @taggable.reload
64
- @taggable.tag_list.should == %w(pow ruby rails)
49
+ expect(@taggable.tag_list).to eq(%w(pow ruby rails))
65
50
 
66
51
  # update to clear tags
67
- @taggable.tag_list = ""
52
+ @taggable.tag_list = ''
68
53
  @taggable.save
69
54
 
70
55
  @taggable.reload
71
- @taggable.tag_list.should == []
56
+ expect(@taggable.tag_list).to be_empty
72
57
  end
73
58
 
74
- it "should return tag objects in the order the tags were created" do
59
+ it 'should return tag objects in the order the tags were created' do
75
60
  # create
76
- @taggable.tag_list = "pow, ruby, rails"
77
- @taggable.instance_variable_get("@tag_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
61
+ @taggable.tag_list = 'pow, ruby, rails'
62
+ expect(@taggable.instance_variable_get('@tag_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
78
63
 
79
- lambda {
64
+ expect(-> {
80
65
  @taggable.save
81
- }.should change(ActsAsTaggableOn::Tag, :count).by(3)
66
+ }).to change(ActsAsTaggableOn::Tag, :count).by(3)
82
67
 
83
68
  @taggable.reload
84
- @taggable.tags.map{|t| t.name}.should == %w(pow ruby rails)
69
+ expect(@taggable.tags.map { |t| t.name }).to eq(%w(pow ruby rails))
85
70
 
86
71
  # update
87
- @taggable.tag_list = "rails, ruby, css, pow"
72
+ @taggable.tag_list = 'rails, ruby, css, pow'
88
73
  @taggable.save
89
74
 
90
75
  @taggable.reload
91
- @taggable.tags.map{|t| t.name}.should == %w(rails ruby css pow)
76
+ expect(@taggable.tags.map { |t| t.name }).to eq(%w(rails ruby css pow))
92
77
  end
93
78
 
94
- it "should return tag objects in tagging id order" do
79
+ it 'should return tag objects in tagging id order' do
95
80
  # create
96
- @taggable.tag_list = "pow, ruby, rails"
81
+ @taggable.tag_list = 'pow, ruby, rails'
97
82
  @taggable.save
98
83
 
99
84
  @taggable.reload
100
- ids = @taggable.tags.map{|t| t.taggings.first.id}
101
- ids.should == ids.sort
85
+ ids = @taggable.tags.map { |t| t.taggings.first.id }
86
+ expect(ids).to eq(ids.sort)
102
87
 
103
88
  # update
104
- @taggable.tag_list = "rails, ruby, css, pow"
89
+ @taggable.tag_list = 'rails, ruby, css, pow'
105
90
  @taggable.save
106
91
 
107
92
  @taggable.reload
108
- ids = @taggable.tags.map{|t| t.taggings.first.id}
109
- ids.should == ids.sort
93
+ ids = @taggable.tags.map { |t| t.taggings.first.id }
94
+ expect(ids).to eq(ids.sort)
110
95
  end
111
96
  end
112
97
 
113
- describe "Taggable" do
98
+ describe 'Taggable' do
114
99
  before(:each) do
115
- clean_database!
116
- @taggable = TaggableModel.new(:name => "Bob Jones")
117
- @taggables = [@taggable, TaggableModel.new(:name => "John Doe")]
100
+ @taggable = TaggableModel.new(name: 'Bob Jones')
101
+ @taggables = [@taggable, TaggableModel.new(name: 'John Doe')]
118
102
  end
119
103
 
120
- it "should have tag types" do
104
+ it 'should have tag types' do
121
105
  [:tags, :languages, :skills, :needs, :offerings].each do |type|
122
- TaggableModel.tag_types.should include type
106
+ expect(TaggableModel.tag_types).to include type
123
107
  end
124
108
 
125
- @taggable.tag_types.should == TaggableModel.tag_types
109
+ expect(@taggable.tag_types).to eq(TaggableModel.tag_types)
126
110
  end
127
111
 
128
- it "should have tag_counts_on" do
129
- TaggableModel.tag_counts_on(:tags).should be_empty
112
+ it 'should have tag_counts_on' do
113
+ expect(TaggableModel.tag_counts_on(:tags)).to be_empty
130
114
 
131
- @taggable.tag_list = ["awesome", "epic"]
115
+ @taggable.tag_list = %w(awesome epic)
132
116
  @taggable.save
133
117
 
134
- TaggableModel.tag_counts_on(:tags).length.should == 2
135
- @taggable.tag_counts_on(:tags).length.should == 2
118
+ expect(TaggableModel.tag_counts_on(:tags).length).to eq(2)
119
+ expect(@taggable.tag_counts_on(:tags).length).to eq(2)
136
120
  end
137
121
 
138
- it "should have tags_on" do
139
- TaggableModel.tags_on(:tags).should be_empty
122
+ it 'should have tags_on' do
123
+ expect(TaggableModel.tags_on(:tags)).to be_empty
140
124
 
141
- @taggable.tag_list = ["awesome", "epic"]
125
+ @taggable.tag_list = %w(awesome epic)
142
126
  @taggable.save
143
127
 
144
- TaggableModel.tags_on(:tags).length.should == 2
145
- @taggable.tags_on(:tags).length.should == 2
128
+ expect(TaggableModel.tags_on(:tags).length).to eq(2)
129
+ expect(@taggable.tags_on(:tags).length).to eq(2)
146
130
  end
147
131
 
148
- it "should return [] right after create" do
149
- blank_taggable = TaggableModel.new(:name => "Bob Jones")
150
- blank_taggable.tag_list.should == []
132
+ it 'should return [] right after create' do
133
+ blank_taggable = TaggableModel.new(name: 'Bob Jones')
134
+ expect(blank_taggable.tag_list).to be_empty
151
135
  end
152
136
 
153
- it "should be able to create tags" do
154
- @taggable.skill_list = "ruby, rails, css"
155
- @taggable.instance_variable_get("@skill_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
137
+ it 'should be able to create tags' do
138
+ @taggable.skill_list = 'ruby, rails, css'
139
+ expect(@taggable.instance_variable_get('@skill_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
156
140
 
157
- lambda {
141
+ expect(-> {
158
142
  @taggable.save
159
- }.should change(ActsAsTaggableOn::Tag, :count).by(3)
143
+ }).to change(ActsAsTaggableOn::Tag, :count).by(3)
160
144
 
161
145
  @taggable.reload
162
- @taggable.skill_list.sort.should == %w(ruby rails css).sort
146
+ expect(@taggable.skill_list.sort).to eq(%w(ruby rails css).sort)
163
147
  end
164
148
 
165
- it "should be able to create tags through the tag list directly" do
166
- @taggable.tag_list_on(:test).add("hello")
167
- @taggable.tag_list_cache_on(:test).should_not be_empty
168
- @taggable.tag_list_on(:test).should == ["hello"]
149
+ it 'should be able to create tags through the tag list directly' do
150
+ @taggable.tag_list_on(:test).add('hello')
151
+ expect(@taggable.tag_list_cache_on(:test)).to_not be_empty
152
+ expect(@taggable.tag_list_on(:test)).to eq(['hello'])
169
153
 
170
154
  @taggable.save
171
155
  @taggable.save_tags
172
156
 
173
157
  @taggable.reload
174
- @taggable.tag_list_on(:test).should == ["hello"]
158
+ expect(@taggable.tag_list_on(:test)).to eq(['hello'])
175
159
  end
176
160
 
177
- it "should differentiate between contexts" do
178
- @taggable.skill_list = "ruby, rails, css"
179
- @taggable.tag_list = "ruby, bob, charlie"
161
+ it 'should differentiate between contexts' do
162
+ @taggable.skill_list = 'ruby, rails, css'
163
+ @taggable.tag_list = 'ruby, bob, charlie'
180
164
  @taggable.save
181
165
  @taggable.reload
182
- @taggable.skill_list.should include("ruby")
183
- @taggable.skill_list.should_not include("bob")
166
+ expect(@taggable.skill_list).to include('ruby')
167
+ expect(@taggable.skill_list).to_not include('bob')
184
168
  end
185
169
 
186
- it "should be able to remove tags through list alone" do
187
- @taggable.skill_list = "ruby, rails, css"
170
+ it 'should be able to remove tags through list alone' do
171
+ @taggable.skill_list = 'ruby, rails, css'
188
172
  @taggable.save
189
173
  @taggable.reload
190
- @taggable.should have(3).skills
191
- @taggable.skill_list = "ruby, rails"
174
+ expect(@taggable.skills.count).to eq(3)
175
+ @taggable.skill_list = 'ruby, rails'
192
176
  @taggable.save
193
177
  @taggable.reload
194
- @taggable.should have(2).skills
178
+ expect(@taggable.skills.count).to eq(2)
195
179
  end
196
180
 
197
- it "should be able to select taggables by subset of tags using ActiveRelation methods" do
198
- @taggables[0].tag_list = "bob"
199
- @taggables[1].tag_list = "charlie"
200
- @taggables[0].skill_list = "ruby"
201
- @taggables[1].skill_list = "css"
202
- @taggables.each{|taggable| taggable.save}
181
+ it 'should be able to select taggables by subset of tags using ActiveRelation methods' do
182
+ @taggables[0].tag_list = 'bob'
183
+ @taggables[1].tag_list = 'charlie'
184
+ @taggables[0].skill_list = 'ruby'
185
+ @taggables[1].skill_list = 'css'
186
+ @taggables.each { |taggable| taggable.save }
203
187
 
204
- @found_taggables_by_tag = TaggableModel.joins(:tags).where(:tags => {:name => ["bob"]})
205
- @found_taggables_by_skill = TaggableModel.joins(:skills).where(:tags => {:name => ["ruby"]})
188
+ @found_taggables_by_tag = TaggableModel.joins(:tags).where(tags: {name: ['bob']})
189
+ @found_taggables_by_skill = TaggableModel.joins(:skills).where(tags: {name: ['ruby']})
206
190
 
207
- @found_taggables_by_tag.should include @taggables[0]
208
- @found_taggables_by_tag.should_not include @taggables[1]
209
- @found_taggables_by_skill.should include @taggables[0]
210
- @found_taggables_by_skill.should_not include @taggables[1]
191
+ expect(@found_taggables_by_tag).to include @taggables[0]
192
+ expect(@found_taggables_by_tag).to_not include @taggables[1]
193
+ expect(@found_taggables_by_skill).to include @taggables[0]
194
+ expect(@found_taggables_by_skill).to_not include @taggables[1]
211
195
  end
212
196
 
213
- it "should be able to find by tag" do
214
- @taggable.skill_list = "ruby, rails, css"
197
+ it 'should be able to find by tag' do
198
+ @taggable.skill_list = 'ruby, rails, css'
215
199
  @taggable.save
216
200
 
217
- TaggableModel.tagged_with("ruby").first.should == @taggable
201
+ expect(TaggableModel.tagged_with('ruby').first).to eq(@taggable)
218
202
  end
219
203
 
220
- it "should be able to get a count with find by tag when using a group by" do
221
- @taggable.skill_list = "ruby"
204
+ it 'should be able to get a count with find by tag when using a group by' do
205
+ @taggable.skill_list = 'ruby'
222
206
  @taggable.save
223
207
 
224
- expect(TaggableModel.tagged_with("ruby").group(:created_at).count.count).to eq(1)
208
+ expect(TaggableModel.tagged_with('ruby').group(:created_at).count.count).to eq(1)
225
209
  end
226
210
 
227
- it "should be able to find by tag with context" do
228
- @taggable.skill_list = "ruby, rails, css"
229
- @taggable.tag_list = "bob, charlie"
211
+ it "shouldn't generate a query with DISTINCT by default" do
212
+ @taggable.skill_list = 'ruby, rails, css'
230
213
  @taggable.save
231
214
 
232
- TaggableModel.tagged_with("ruby").first.should == @taggable
233
- TaggableModel.tagged_with("ruby, css").first.should == @taggable
234
- TaggableModel.tagged_with("bob", :on => :skills).first.should_not == @taggable
235
- TaggableModel.tagged_with("bob", :on => :tags).first.should == @taggable
215
+ expect(TaggableModel.tagged_with('ruby').to_sql).to_not match /DISTINCT/
236
216
  end
237
217
 
238
- it "should not care about case" do
239
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby")
240
- frank = TaggableModel.create(:name => "Frank", :tag_list => "Ruby")
218
+ it 'should be able to find by tag with context' do
219
+ @taggable.skill_list = 'ruby, rails, css'
220
+ @taggable.tag_list = 'bob, charlie'
221
+ @taggable.save
241
222
 
242
- ActsAsTaggableOn::Tag.all.size.should == 1
243
- TaggableModel.tagged_with("ruby").to_a.should == TaggableModel.tagged_with("Ruby").to_a
223
+ expect(TaggableModel.tagged_with('ruby').first).to eq(@taggable)
224
+ expect(TaggableModel.tagged_with('ruby, css').first).to eq(@taggable)
225
+ expect(TaggableModel.tagged_with('bob', on: :skills).first).to_not eq(@taggable)
226
+ expect(TaggableModel.tagged_with('bob', on: :tags).first).to eq(@taggable)
244
227
  end
245
228
 
246
- unless ActsAsTaggableOn::Tag.using_sqlite?
247
- it "should not care about case for unicode names" do
229
+ it 'should not care about case' do
230
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby')
231
+ TaggableModel.create(name: 'Frank', tag_list: 'Ruby')
232
+
233
+ expect(ActsAsTaggableOn::Tag.all.size).to eq(1)
234
+ expect(TaggableModel.tagged_with('ruby').to_a).to eq(TaggableModel.tagged_with('Ruby').to_a)
235
+ end
236
+
237
+ it 'should be able to find by tags with other joins in the query' do
238
+ @taggable.skill_list = 'ruby, rails, css'
239
+ @taggable.tag_list = 'bob, charlie'
240
+ @taggable.save
241
+
242
+ expect(TaggableModel.group(:created_at).tagged_with(['bob', 'css'], :any => true).first).to eq(@taggable)
243
+
244
+ bob = TaggableModel.create(:name => 'Bob', :tag_list => 'ruby, rails, css')
245
+ frank = TaggableModel.create(:name => 'Frank', :tag_list => 'ruby, rails')
246
+ charlie = TaggableModel.create(:name => 'Charlie', :skill_list => 'ruby, java')
247
+
248
+ # Test for explicit distinct in select
249
+ bob.untaggable_models.create!
250
+ frank.untaggable_models.create!
251
+ charlie.untaggable_models.create!
252
+
253
+ expect(TaggableModel.select('distinct(taggable_models.id), taggable_models.*').joins(:untaggable_models).tagged_with(['css', 'java'], :any => true).to_a.sort).to eq([bob, charlie].sort)
254
+
255
+ expect(TaggableModel.select('distinct(taggable_models.id), taggable_models.*').joins(:untaggable_models).tagged_with(['rails', 'ruby'], :any => false).to_a.sort).to eq([bob, frank].sort)
256
+ end
257
+
258
+ unless ActsAsTaggableOn::Utils.using_sqlite?
259
+ it 'should not care about case for unicode names' do
248
260
  ActsAsTaggableOn.strict_case_match = false
249
-
250
- anya = TaggableModel.create(:name => "Anya", :tag_list => "ПРИВЕТ")
251
- igor = TaggableModel.create(:name => "Igor", :tag_list => "привет")
252
- katia = TaggableModel.create(:name => "Katia", :tag_list => "ПРИВЕТ")
261
+ TaggableModel.create(name: 'Anya', tag_list: 'ПРИВЕТ')
262
+ TaggableModel.create(name: 'Igor', tag_list: 'привет')
263
+ TaggableModel.create(name: 'Katia', tag_list: 'ПРИВЕТ')
253
264
 
254
- ActsAsTaggableOn::Tag.all.size.should == 1
255
- TaggableModel.tagged_with("привет").to_a.should == TaggableModel.tagged_with("ПРИВЕТ").to_a
265
+ expect(ActsAsTaggableOn::Tag.all.size).to eq(1)
266
+ expect(TaggableModel.tagged_with('привет').to_a).to eq(TaggableModel.tagged_with('ПРИВЕТ').to_a)
256
267
  end
257
268
  end
258
269
 
259
- it "should be able to create and find tags in languages without capitalization" do
270
+ context 'should be able to create and find tags in languages without capitalization :' do
260
271
  ActsAsTaggableOn.strict_case_match = false
261
- chihiro = TaggableModel.create(:name => "Chihiro", :tag_list => "日本の")
262
- salim = TaggableModel.create(:name => "Salim", :tag_list => "עברית")
263
- ieie = TaggableModel.create(:name => "Ieie", :tag_list => "中国的")
264
- yasser = TaggableModel.create(:name => "Yasser", :tag_list => "العربية")
265
- emo = TaggableModel.create(:name => "Emo", :tag_list => "✏")
266
-
267
- TaggableModel.tagged_with("日本の").to_a.size.should == 1
268
- TaggableModel.tagged_with("עברית").to_a.size.should == 1
269
- TaggableModel.tagged_with("中国的").to_a.size.should == 1
270
- TaggableModel.tagged_with("العربية").to_a.size.should == 1
271
- TaggableModel.tagged_with("✏").to_a.size.should == 1
272
- end
272
+ {
273
+ japanese: {name: 'Chihiro', tag_list: '日本の'},
274
+ hebrew: {name: 'Salim', tag_list: 'עברית'},
275
+ chinese: {name: 'Ieie', tag_list: '中国的'},
276
+ arabic: {name: 'Yasser', tag_list: 'العربية'},
277
+ emo: {name: 'Emo', tag_list: '✏'}
278
+ }.each do |language, values|
279
+
280
+ it language do
281
+ TaggableModel.create(values)
282
+ expect(TaggableModel.tagged_with(values[:tag_list]).count).to eq(1)
283
+ end
284
+ end
285
+ end
273
286
 
274
- it "should be able to get tag counts on model as a whole" do
275
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
276
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
277
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
278
- TaggableModel.tag_counts.should_not be_empty
279
- TaggableModel.skill_counts.should_not be_empty
287
+ it 'should be able to get tag counts on model as a whole' do
288
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
289
+ TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
290
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
291
+ expect(TaggableModel.tag_counts).to_not be_empty
292
+ expect(TaggableModel.skill_counts).to_not be_empty
280
293
  end
281
294
 
282
- it "should be able to get all tag counts on model as whole" do
283
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
284
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
285
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
295
+ it 'should be able to get all tag counts on model as whole' do
296
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
297
+ TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
298
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
286
299
 
287
- TaggableModel.all_tag_counts.should_not be_empty
288
- TaggableModel.all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
300
+ expect(TaggableModel.all_tag_counts).to_not be_empty
301
+ expect(TaggableModel.all_tag_counts(order: 'tags.id').first.count).to eq(3) # ruby
289
302
  end
290
303
 
291
- it "should be able to get all tags on model as whole" do
292
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
293
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
294
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
304
+ it 'should be able to get all tags on model as whole' do
305
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
306
+ TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
307
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
295
308
 
296
- TaggableModel.all_tags.should_not be_empty
297
- TaggableModel.all_tags(:order => 'tags.id').first.name.should == "ruby"
309
+ expect(TaggableModel.all_tags).to_not be_empty
310
+ expect(TaggableModel.all_tags(order: 'tags.id').first.name).to eq('ruby')
298
311
  end
299
312
 
300
- it "should be able to use named scopes to chain tag finds by any tags by context" do
301
- bob = TaggableModel.create(:name => "Bob", :need_list => "rails", :offering_list => "c++")
302
- frank = TaggableModel.create(:name => "Frank", :need_list => "css", :offering_list => "css")
303
- steve = TaggableModel.create(:name => 'Steve', :need_list => "c++", :offering_list => "java")
313
+ it 'should be able to use named scopes to chain tag finds by any tags by context' do
314
+ bob = TaggableModel.create(name: 'Bob', need_list: 'rails', offering_list: 'c++')
315
+ TaggableModel.create(name: 'Frank', need_list: 'css', offering_list: 'css')
316
+ TaggableModel.create(name: 'Steve', need_list: 'c++', offering_list: 'java')
304
317
 
305
318
  # Let's only find those who need rails or css and are offering c++ or java
306
- TaggableModel.tagged_with(['rails, css'], :on => :needs, :any => true).tagged_with(['c++', 'java'], :on => :offerings, :any => true).to_a.should == [bob]
319
+ expect(TaggableModel.tagged_with(['rails, css'], on: :needs, any: true).tagged_with(['c++', 'java'], on: :offerings, any: true).to_a).to eq([bob])
307
320
  end
308
321
 
309
- it "should not return read-only records" do
310
- TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
311
- TaggableModel.tagged_with("ruby").first.should_not be_readonly
322
+ it 'should not return read-only records' do
323
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
324
+ expect(TaggableModel.tagged_with('ruby').first).to_not be_readonly
312
325
  end
313
326
 
314
- it "should be able to get scoped tag counts" do
315
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
316
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
317
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
327
+ it 'should be able to get scoped tag counts' do
328
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
329
+ TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
330
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
318
331
 
319
- TaggableModel.tagged_with("ruby").tag_counts(:order => 'tags.id').first.count.should == 2 # ruby
320
- TaggableModel.tagged_with("ruby").skill_counts.first.count.should == 1 # ruby
332
+ expect(TaggableModel.tagged_with('ruby').tag_counts(order: 'tags.id').first.count).to eq(2) # ruby
333
+ expect(TaggableModel.tagged_with('ruby').skill_counts.first.count).to eq(1) # ruby
321
334
  end
322
335
 
323
- it "should be able to get all scoped tag counts" do
324
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
325
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
326
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
336
+ it 'should be able to get all scoped tag counts' do
337
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
338
+ TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
339
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
327
340
 
328
- TaggableModel.tagged_with("ruby").all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
341
+ expect(TaggableModel.tagged_with('ruby').all_tag_counts(order: 'tags.id').first.count).to eq(3) # ruby
329
342
  end
330
343
 
331
- it "should be able to get all scoped tags" do
332
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
333
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
334
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
344
+ it 'should be able to get all scoped tags' do
345
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
346
+ TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
347
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby')
335
348
 
336
- TaggableModel.tagged_with("ruby").all_tags(:order => 'tags.id').first.name.should == "ruby"
349
+ expect(TaggableModel.tagged_with('ruby').all_tags(order: 'tags.id').first.name).to eq('ruby')
337
350
  end
338
351
 
339
352
  it 'should only return tag counts for the available scope' do
340
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
341
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
342
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby, java")
353
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
354
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
355
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby, java')
343
356
 
344
- TaggableModel.tagged_with('rails').all_tag_counts.should have(3).items
345
- TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }.should be_false
357
+ expect(TaggableModel.tagged_with('rails').all_tag_counts.size).to eq(3)
358
+ expect(TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }).to be_falsy
346
359
 
347
360
  # Test specific join syntaxes:
348
361
  frank.untaggable_models.create!
349
- TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tag_counts.should have(2).items
350
- TaggableModel.tagged_with('rails').joins(:untaggable_models => :taggable_model).all_tag_counts.should have(2).items
351
- TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tag_counts.should have(2).items
362
+ expect(TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tag_counts.size).to eq(2)
363
+ expect(TaggableModel.tagged_with('rails').joins(untaggable_models: :taggable_model).all_tag_counts.size).to eq(2)
364
+ expect(TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tag_counts.size).to eq(2)
352
365
  end
353
366
 
354
367
  it 'should only return tags for the available scope' do
355
- bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
356
- frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
357
- charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby, java")
368
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'ruby, rails')
369
+ TaggableModel.create(name: 'Bob', tag_list: 'ruby, rails, css')
370
+ TaggableModel.create(name: 'Charlie', skill_list: 'ruby, java')
358
371
 
359
- TaggableModel.tagged_with('rails').all_tags.should have(3).items
360
- TaggableModel.tagged_with('rails').all_tags.any? { |tag| tag.name == 'java' }.should be_false
372
+ expect(TaggableModel.tagged_with('rails').all_tags.count).to eq(3)
373
+ expect(TaggableModel.tagged_with('rails').all_tags.any? { |tag| tag.name == 'java' }).to be_falsy
361
374
 
362
375
  # Test specific join syntaxes:
363
376
  frank.untaggable_models.create!
364
- TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tags.should have(2).items
365
- TaggableModel.tagged_with('rails').joins({ :untaggable_models => :taggable_model }).all_tags.should have(2).items
366
- TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tags.should have(2).items
377
+ expect(TaggableModel.tagged_with('rails').joins(:untaggable_models).all_tags.size).to eq(2)
378
+ expect(TaggableModel.tagged_with('rails').joins(untaggable_models: :taggable_model).all_tags.size).to eq(2)
379
+ expect(TaggableModel.tagged_with('rails').joins([:untaggable_models]).all_tags.size).to eq(2)
367
380
  end
368
381
 
369
- it "should be able to set a custom tag context list" do
370
- bob = TaggableModel.create(:name => "Bob")
371
- bob.set_tag_list_on(:rotors, "spinning, jumping")
372
- bob.tag_list_on(:rotors).should == ["spinning","jumping"]
382
+ it 'should be able to set a custom tag context list' do
383
+ bob = TaggableModel.create(name: 'Bob')
384
+ bob.set_tag_list_on(:rotors, 'spinning, jumping')
385
+ expect(bob.tag_list_on(:rotors)).to eq(%w(spinning jumping))
373
386
  bob.save
374
387
  bob.reload
375
- bob.tags_on(:rotors).should_not be_empty
388
+ expect(bob.tags_on(:rotors)).to_not be_empty
376
389
  end
377
390
 
378
- it "should be able to find tagged" do
379
- bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
380
- frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
381
- steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
391
+ it 'should be able to find tagged' do
392
+ bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
393
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
394
+ steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, ruby')
382
395
 
383
- TaggableModel.tagged_with("ruby", :order => 'taggable_models.name').to_a.should == [bob, frank, steve]
384
- TaggableModel.tagged_with("ruby, rails", :order => 'taggable_models.name').to_a.should == [bob, frank]
385
- TaggableModel.tagged_with(["ruby", "rails"], :order => 'taggable_models.name').to_a.should == [bob, frank]
396
+ expect(TaggableModel.tagged_with('ruby', order: 'taggable_models.name').to_a).to eq([bob, frank, steve])
397
+ expect(TaggableModel.tagged_with('ruby, rails', order: 'taggable_models.name').to_a).to eq([bob, frank])
398
+ expect(TaggableModel.tagged_with(%w(ruby rails), order: 'taggable_models.name').to_a).to eq([bob, frank])
386
399
  end
387
400
 
388
- it "should be able to find tagged with quotation marks" do
389
- bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive, 'I love the ,comma,'")
390
- TaggableModel.tagged_with("'I love the ,comma,'").should include(bob)
401
+ it 'should be able to find tagged with quotation marks' do
402
+ bob = TaggableModel.create(name: 'Bob', tag_list: "fitter, happier, more productive, 'I love the ,comma,'")
403
+ expect(TaggableModel.tagged_with("'I love the ,comma,'")).to include(bob)
391
404
  end
392
405
 
393
- it "should be able to find tagged with invalid tags" do
394
- bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive")
395
- TaggableModel.tagged_with("sad, happier").should_not include(bob)
406
+ it 'should be able to find tagged with invalid tags' do
407
+ bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive')
408
+ expect(TaggableModel.tagged_with('sad, happier')).to_not include(bob)
396
409
  end
397
410
 
398
- it "should be able to find tagged with any tag" do
399
- bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
400
- frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
401
- steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
411
+ it 'should be able to find tagged with any tag' do
412
+ bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
413
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
414
+ steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, ruby')
402
415
 
403
- TaggableModel.tagged_with(["ruby", "java"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank, steve]
404
- TaggableModel.tagged_with(["c++", "fitter"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, steve]
405
- TaggableModel.tagged_with(["depressed", "css"], :order => 'taggable_models.name', :any => true).to_a.should == [bob, frank]
416
+ expect(TaggableModel.tagged_with(%w(ruby java), order: 'taggable_models.name', any: true).to_a).to eq([bob, frank, steve])
417
+ expect(TaggableModel.tagged_with(%w(c++ fitter), order: 'taggable_models.name', any: true).to_a).to eq([bob, steve])
418
+ expect(TaggableModel.tagged_with(%w(depressed css), order: 'taggable_models.name', any: true).to_a).to eq([bob, frank])
406
419
  end
407
420
 
408
- it "should be able to order by number of matching tags when matching any" do
409
- bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
410
- frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
411
- steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
421
+ it 'should be able to order by number of matching tags when matching any' do
422
+ bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
423
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
424
+ steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, ruby')
412
425
 
413
- TaggableModel.tagged_with(["ruby", "java"], :any => true, :order_by_matching_tag_count => true, :order => 'taggable_models.name').to_a.should == [steve, bob, frank]
414
- TaggableModel.tagged_with(["c++", "fitter"], :any => true, :order_by_matching_tag_count => true, :order => 'taggable_models.name').to_a.should == [steve, bob]
415
- TaggableModel.tagged_with(["depressed", "css"], :any => true, :order_by_matching_tag_count => true, :order => 'taggable_models.name').to_a.should == [frank, bob]
416
- TaggableModel.tagged_with(["fitter", "happier", "more productive", "c++", "java", "ruby"], :any => true, :order_by_matching_tag_count => true, :order => 'taggable_models.name').to_a.should == [steve, bob, frank]
417
- TaggableModel.tagged_with(["c++", "java", "ruby", "fitter"], :any => true, :order_by_matching_tag_count => true, :order => 'taggable_models.name').to_a.should == [steve, bob, frank]
426
+ expect(TaggableModel.tagged_with(%w(ruby java), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob, frank])
427
+ expect(TaggableModel.tagged_with(%w(c++ fitter), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob])
428
+ expect(TaggableModel.tagged_with(%w(depressed css), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([frank, bob])
429
+ expect(TaggableModel.tagged_with(['fitter', 'happier', 'more productive', 'c++', 'java', 'ruby'], any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob, frank])
430
+ expect(TaggableModel.tagged_with(%w(c++ java ruby fitter), any: true, order_by_matching_tag_count: true, order: 'taggable_models.name').to_a).to eq([steve, bob, frank])
418
431
  end
419
432
 
420
- context "wild: true" do
421
- it "should use params as wildcards" do
422
- bob = TaggableModel.create(:name => "Bob", :tag_list => "bob, tricia")
423
- frank = TaggableModel.create(:name => "Frank", :tag_list => "bobby, jim")
424
- steve = TaggableModel.create(:name => "Steve", :tag_list => "john, patricia")
425
- jim = TaggableModel.create(:name => "Jim", :tag_list => "jim, steve")
426
-
433
+ context 'wild: true' do
434
+ it 'should use params as wildcards' do
435
+ bob = TaggableModel.create(name: 'Bob', tag_list: 'bob, tricia')
436
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'bobby, jim')
437
+ steve = TaggableModel.create(name: 'Steve', tag_list: 'john, patricia')
438
+ jim = TaggableModel.create(name: 'Jim', tag_list: 'jim, steve')
427
439
 
428
- TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :any => true).to_a.sort_by{|o| o.id}.should == [bob, frank, steve]
429
- TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :exclude => true).to_a.should == [jim]
440
+ expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, any: true).to_a.sort_by { |o| o.id }).to eq([bob, frank, steve])
441
+ expect(TaggableModel.tagged_with(%w(bob tricia), wild: true, exclude: true).to_a).to eq([jim])
430
442
  end
431
443
  end
432
444
 
433
- it "should be able to find tagged on a custom tag context" do
434
- bob = TaggableModel.create(:name => "Bob")
435
- bob.set_tag_list_on(:rotors, "spinning, jumping")
436
- bob.tag_list_on(:rotors).should == ["spinning","jumping"]
445
+ it 'should be able to find tagged on a custom tag context' do
446
+ bob = TaggableModel.create(name: 'Bob')
447
+ bob.set_tag_list_on(:rotors, 'spinning, jumping')
448
+ expect(bob.tag_list_on(:rotors)).to eq(%w(spinning jumping))
437
449
  bob.save
438
450
 
439
- TaggableModel.tagged_with("spinning", :on => :rotors).to_a.should == [bob]
451
+ expect(TaggableModel.tagged_with('spinning', on: :rotors).to_a).to eq([bob])
440
452
  end
441
453
 
442
- it "should be able to use named scopes to chain tag finds" do
443
- bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
444
- frank = TaggableModel.create(:name => "Frank", :tag_list => "weaker, depressed, inefficient", :skill_list => "ruby, rails, css")
445
- steve = TaggableModel.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, python')
454
+ it 'should be able to use named scopes to chain tag finds' do
455
+ bob = TaggableModel.create(name: 'Bob', tag_list: 'fitter, happier, more productive', skill_list: 'ruby, rails, css')
456
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'weaker, depressed, inefficient', skill_list: 'ruby, rails, css')
457
+ steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier, more productive', skill_list: 'c++, java, python')
446
458
 
447
459
  # Let's only find those productive Rails developers
448
- TaggableModel.tagged_with('rails', :on => :skills, :order => 'taggable_models.name').to_a.should == [bob, frank]
449
- TaggableModel.tagged_with('happier', :on => :tags, :order => 'taggable_models.name').to_a.should == [bob, steve]
450
- TaggableModel.tagged_with('rails', :on => :skills).tagged_with('happier', :on => :tags).to_a.should == [bob]
451
- TaggableModel.tagged_with('rails').tagged_with('happier', :on => :tags).to_a.should == [bob]
460
+ expect(TaggableModel.tagged_with('rails', on: :skills, order: 'taggable_models.name').to_a).to eq([bob, frank])
461
+ expect(TaggableModel.tagged_with('happier', on: :tags, order: 'taggable_models.name').to_a).to eq([bob, steve])
462
+ expect(TaggableModel.tagged_with('rails', on: :skills).tagged_with('happier', on: :tags).to_a).to eq([bob])
463
+ expect(TaggableModel.tagged_with('rails').tagged_with('happier', on: :tags).to_a).to eq([bob])
452
464
  end
453
465
 
454
- it "should be able to find tagged with only the matching tags" do
455
- bob = TaggableModel.create(:name => "Bob", :tag_list => "lazy, happier")
456
- frank = TaggableModel.create(:name => "Frank", :tag_list => "fitter, happier, inefficient")
457
- steve = TaggableModel.create(:name => 'Steve', :tag_list => "fitter, happier")
466
+ it 'should be able to find tagged with only the matching tags' do
467
+ TaggableModel.create(name: 'Bob', tag_list: 'lazy, happier')
468
+ TaggableModel.create(name: 'Frank', tag_list: 'fitter, happier, inefficient')
469
+ steve = TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier')
458
470
 
459
- TaggableModel.tagged_with("fitter, happier", :match_all => true).to_a.should == [steve]
471
+ expect(TaggableModel.tagged_with('fitter, happier', match_all: true).to_a).to eq([steve])
460
472
  end
461
473
 
462
- it "should be able to find tagged with only the matching tags for a context" do
463
- bob = TaggableModel.create(:name => "Bob", :tag_list => "lazy, happier", :skill_list => "ruby, rails, css")
464
- frank = TaggableModel.create(:name => "Frank", :tag_list => "fitter, happier, inefficient", :skill_list => "css")
465
- steve = TaggableModel.create(:name => 'Steve', :tag_list => "fitter, happier", :skill_list => "ruby, rails, css")
474
+ it 'should be able to find tagged with only the matching tags for a context' do
475
+ TaggableModel.create(name: 'Bob', tag_list: 'lazy, happier', skill_list: 'ruby, rails, css')
476
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'fitter, happier, inefficient', skill_list: 'css')
477
+ TaggableModel.create(name: 'Steve', tag_list: 'fitter, happier', skill_list: 'ruby, rails, css')
466
478
 
467
- TaggableModel.tagged_with("css", :on => :skills, :match_all => true).to_a.should == [frank]
479
+ expect(TaggableModel.tagged_with('css', on: :skills, match_all: true).to_a).to eq([frank])
468
480
  end
469
481
 
470
- it "should be able to find tagged with some excluded tags" do
471
- bob = TaggableModel.create(:name => "Bob", :tag_list => "happier, lazy")
472
- frank = TaggableModel.create(:name => "Frank", :tag_list => "happier")
473
- steve = TaggableModel.create(:name => 'Steve', :tag_list => "happier")
482
+ it 'should be able to find tagged with some excluded tags' do
483
+ TaggableModel.create(name: 'Bob', tag_list: 'happier, lazy')
484
+ frank = TaggableModel.create(name: 'Frank', tag_list: 'happier')
485
+ steve = TaggableModel.create(name: 'Steve', tag_list: 'happier')
474
486
 
475
- TaggableModel.tagged_with("lazy", :exclude => true).to_a.should == [frank, steve]
487
+ expect(TaggableModel.tagged_with('lazy', exclude: true)).to include(frank, steve)
488
+ expect(TaggableModel.tagged_with('lazy', exclude: true).size).to eq(2)
476
489
  end
477
490
 
478
- it "should return an empty scope for empty tags" do
479
- TaggableModel.tagged_with('').should == []
480
- TaggableModel.tagged_with(' ').should == []
481
- TaggableModel.tagged_with(nil).should == []
482
- TaggableModel.tagged_with([]).should == []
491
+ it 'should return an empty scope for empty tags' do
492
+ ['', ' ', nil, []].each do |tag|
493
+ expect(TaggableModel.tagged_with(tag)).to be_empty
494
+ end
483
495
  end
484
496
 
485
- it "should not create duplicate taggings" do
486
- bob = TaggableModel.create(:name => "Bob")
487
- lambda {
488
- bob.tag_list << "happier"
489
- bob.tag_list << "happier"
490
- bob.save
491
- }.should change(ActsAsTaggableOn::Tagging, :count).by(1)
497
+ context 'Duplicates' do
498
+ context 'should not create duplicate taggings' do
499
+ let(:bob) { TaggableModel.create(name: 'Bob') }
500
+ context 'case sensitive' do
501
+ it '#add' do
502
+ expect(lambda {
503
+ bob.tag_list.add 'happier'
504
+ bob.tag_list.add 'happier'
505
+ bob.tag_list.add 'happier', 'rich', 'funny'
506
+ bob.save
507
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(3)
508
+ end
509
+ it '#<<' do
510
+ expect(lambda {
511
+ bob.tag_list << 'social'
512
+ bob.tag_list << 'social'
513
+ bob.tag_list << 'social' << 'wow'
514
+ bob.save
515
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(2)
516
+
517
+ end
518
+
519
+ it 'unicode' do
520
+
521
+ expect(lambda {
522
+ bob.tag_list.add 'ПРИВЕТ'
523
+ bob.tag_list.add 'ПРИВЕТ'
524
+ bob.tag_list.add 'ПРИВЕТ', 'ПРИВЕТ'
525
+ bob.save
526
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(1)
527
+
528
+ end
529
+
530
+ it '#=' do
531
+ expect(lambda {
532
+ bob.tag_list = ['Happy', 'Happy']
533
+ bob.save
534
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(1)
535
+ end
536
+ end
537
+ context 'case insensitive' do
538
+ before(:all) { ActsAsTaggableOn.force_lowercase = true }
539
+ after(:all) { ActsAsTaggableOn.force_lowercase = false }
540
+
541
+ it '#<<' do
542
+ expect(lambda {
543
+ bob.tag_list << 'Alone'
544
+ bob.tag_list << 'AloNe'
545
+ bob.tag_list << 'ALONE' << 'In The dark'
546
+ bob.save
547
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(2)
548
+
549
+ end
550
+
551
+ it '#add' do
552
+ expect(lambda {
553
+ bob.tag_list.add 'forever'
554
+ bob.tag_list.add 'ForEver'
555
+ bob.tag_list.add 'FOREVER', 'ALONE'
556
+ bob.save
557
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(2)
558
+ end
559
+
560
+ it 'unicode' do
561
+
562
+ expect(lambda {
563
+ bob.tag_list.add 'ПРИВЕТ'
564
+ bob.tag_list.add 'привет', 'Привет'
565
+ bob.save
566
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(1)
567
+
568
+ end
569
+
570
+ it '#=' do
571
+ expect(lambda {
572
+ bob.tag_list = ['Happy', 'HAPPY']
573
+ bob.save
574
+ }).to change(ActsAsTaggableOn::Tagging, :count).by(1)
575
+ end
576
+
577
+
578
+ end
579
+
580
+
581
+ end
582
+
583
+ if ActsAsTaggableOn::Utils.supports_concurrency?
584
+ xit 'should not duplicate tags added on different threads' do
585
+ #TODO, try with more threads and fix deadlock
586
+ thread_count = 4
587
+ barrier = Barrier.new thread_count
588
+
589
+ expect {
590
+ thread_count.times.map do |idx|
591
+ Thread.start do
592
+ connor = TaggableModel.first_or_create(name: 'Connor')
593
+ connor.tag_list = 'There, can, be, only, one'
594
+ barrier.wait
595
+ begin
596
+ connor.save
597
+ rescue ActsAsTaggableOn::DuplicateTagError
598
+ # second save should succeed
599
+ connor.save
600
+ end
601
+ end
602
+ end.map(&:join)
603
+ }.to change(ActsAsTaggableOn::Tag, :count).by(5)
604
+ end
605
+ end
492
606
  end
493
607
 
494
- describe "Associations" do
608
+ describe 'Associations' do
495
609
  before(:each) do
496
- @taggable = TaggableModel.create(:tag_list => "awesome, epic")
610
+ @taggable = TaggableModel.create(tag_list: 'awesome, epic')
497
611
  end
498
612
 
499
- it "should not remove tags when creating associated objects" do
613
+ it 'should not remove tags when creating associated objects' do
500
614
  @taggable.untaggable_models.create!
501
615
  @taggable.reload
502
- @taggable.tag_list.should have(2).items
616
+ expect(@taggable.tag_list.size).to eq(2)
503
617
  end
504
618
  end
505
619
 
506
- describe "grouped_column_names_for method" do
507
- it "should return all column names joined for Tag GROUP clause" do
508
- @taggable.grouped_column_names_for(ActsAsTaggableOn::Tag).should == "tags.id, tags.name, tags.taggings_count"
620
+ describe 'grouped_column_names_for method' do
621
+ it 'should return all column names joined for Tag GROUP clause' do
622
+ # NOTE: type column supports an STI Tag subclass in the test suite, though
623
+ # isn't included by default in the migration generator
624
+ expect(@taggable.grouped_column_names_for(ActsAsTaggableOn::Tag)).
625
+ to eq('tags.id, tags.name, tags.taggings_count, tags.type')
509
626
  end
510
627
 
511
- it "should return all column names joined for TaggableModel GROUP clause" do
512
- @taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.id, taggable_models.name, taggable_models.type"
628
+ it 'should return all column names joined for TaggableModel GROUP clause' do
629
+ expect(@taggable.grouped_column_names_for(TaggableModel)).to eq('taggable_models.id, taggable_models.name, taggable_models.type')
513
630
  end
514
631
 
515
- it "should return all column names joined for NonStandardIdTaggableModel GROUP clause" do
516
- @taggable.grouped_column_names_for(TaggableModel).should == "taggable_models.#{TaggableModel.primary_key}, taggable_models.name, taggable_models.type"
632
+ it 'should return all column names joined for NonStandardIdTaggableModel GROUP clause' do
633
+ expect(@taggable.grouped_column_names_for(TaggableModel)).to eq("taggable_models.#{TaggableModel.primary_key}, taggable_models.name, taggable_models.type")
517
634
  end
518
635
  end
519
636
 
520
- describe "NonStandardIdTaggable" do
637
+ describe 'NonStandardIdTaggable' do
521
638
  before(:each) do
522
- clean_database!
523
- @taggable = NonStandardIdTaggableModel.new(:name => "Bob Jones")
524
- @taggables = [@taggable, NonStandardIdTaggableModel.new(:name => "John Doe")]
639
+ @taggable = NonStandardIdTaggableModel.new(name: 'Bob Jones')
640
+ @taggables = [@taggable, NonStandardIdTaggableModel.new(name: 'John Doe')]
525
641
  end
526
642
 
527
- it "should have tag types" do
643
+ it 'should have tag types' do
528
644
  [:tags, :languages, :skills, :needs, :offerings].each do |type|
529
- NonStandardIdTaggableModel.tag_types.should include type
645
+ expect(NonStandardIdTaggableModel.tag_types).to include type
530
646
  end
531
647
 
532
- @taggable.tag_types.should == NonStandardIdTaggableModel.tag_types
648
+ expect(@taggable.tag_types).to eq(NonStandardIdTaggableModel.tag_types)
533
649
  end
534
650
 
535
- it "should have tag_counts_on" do
536
- NonStandardIdTaggableModel.tag_counts_on(:tags).should be_empty
651
+ it 'should have tag_counts_on' do
652
+ expect(NonStandardIdTaggableModel.tag_counts_on(:tags)).to be_empty
537
653
 
538
- @taggable.tag_list = ["awesome", "epic"]
654
+ @taggable.tag_list = %w(awesome epic)
539
655
  @taggable.save
540
656
 
541
- NonStandardIdTaggableModel.tag_counts_on(:tags).length.should == 2
542
- @taggable.tag_counts_on(:tags).length.should == 2
657
+ expect(NonStandardIdTaggableModel.tag_counts_on(:tags).length).to eq(2)
658
+ expect(@taggable.tag_counts_on(:tags).length).to eq(2)
543
659
  end
544
660
 
545
- it "should have tags_on" do
546
- NonStandardIdTaggableModel.tags_on(:tags).should be_empty
661
+ it 'should have tags_on' do
662
+ expect(NonStandardIdTaggableModel.tags_on(:tags)).to be_empty
547
663
 
548
- @taggable.tag_list = ["awesome", "epic"]
664
+ @taggable.tag_list = %w(awesome epic)
549
665
  @taggable.save
550
666
 
551
- NonStandardIdTaggableModel.tags_on(:tags).length.should == 2
552
- @taggable.tags_on(:tags).length.should == 2
667
+ expect(NonStandardIdTaggableModel.tags_on(:tags).length).to eq(2)
668
+ expect(@taggable.tags_on(:tags).length).to eq(2)
553
669
  end
554
670
 
555
- it "should be able to create tags" do
556
- @taggable.skill_list = "ruby, rails, css"
557
- @taggable.instance_variable_get("@skill_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
671
+ it 'should be able to create tags' do
672
+ @taggable.skill_list = 'ruby, rails, css'
673
+ expect(@taggable.instance_variable_get('@skill_list').instance_of?(ActsAsTaggableOn::TagList)).to be_truthy
558
674
 
559
- lambda {
675
+ expect(-> {
560
676
  @taggable.save
561
- }.should change(ActsAsTaggableOn::Tag, :count).by(3)
677
+ }).to change(ActsAsTaggableOn::Tag, :count).by(3)
562
678
 
563
679
  @taggable.reload
564
- @taggable.skill_list.sort.should == %w(ruby rails css).sort
680
+ expect(@taggable.skill_list.sort).to eq(%w(ruby rails css).sort)
565
681
  end
566
682
 
567
- it "should be able to create tags through the tag list directly" do
568
- @taggable.tag_list_on(:test).add("hello")
569
- @taggable.tag_list_cache_on(:test).should_not be_empty
570
- @taggable.tag_list_on(:test).should == ["hello"]
683
+ it 'should be able to create tags through the tag list directly' do
684
+ @taggable.tag_list_on(:test).add('hello')
685
+ expect(@taggable.tag_list_cache_on(:test)).to_not be_empty
686
+ expect(@taggable.tag_list_on(:test)).to eq(['hello'])
571
687
 
572
688
  @taggable.save
573
689
  @taggable.save_tags
574
690
 
575
691
  @taggable.reload
576
- @taggable.tag_list_on(:test).should == ["hello"]
692
+ expect(@taggable.tag_list_on(:test)).to eq(['hello'])
577
693
  end
578
694
  end
579
695
 
580
- describe "Dirty Objects" do
581
- context "with un-contexted tags" do
696
+ describe 'Dirty Objects' do
697
+ context 'with un-contexted tags' do
582
698
  before(:each) do
583
- @taggable = TaggableModel.create(:tag_list => "awesome, epic")
699
+ @taggable = TaggableModel.create(tag_list: 'awesome, epic')
584
700
  end
585
701
 
586
- context "when tag_list changed" do
702
+ context 'when tag_list changed' do
587
703
  before(:each) do
588
- @taggable.changes.should == {}
704
+ expect(@taggable.changes).to be_empty
589
705
  @taggable.tag_list = 'one'
590
706
  end
591
707
 
592
708
  it 'should show changes of dirty object' do
593
- @taggable.changes.should == {"tag_list"=>["awesome, epic", ["one"]]}
709
+ expect(@taggable.changes).to eq({'tag_list' => ['awesome, epic', ['one']]})
594
710
  end
595
711
 
596
712
  it 'flags tag_list as changed' do
597
- @taggable.tag_list_changed?.should be_true
713
+ expect(@taggable.tag_list_changed?).to be_truthy
598
714
  end
599
715
 
600
716
  it 'preserves original value' do
601
- @taggable.tag_list_was.should == "awesome, epic"
717
+ expect(@taggable.tag_list_was).to eq('awesome, epic')
602
718
  end
603
719
 
604
720
  it 'shows what the change was' do
605
- @taggable.tag_list_change.should == ["awesome, epic", ["one"]]
721
+ expect(@taggable.tag_list_change).to eq(['awesome, epic', ['one']])
606
722
  end
607
723
  end
608
724
 
609
725
  context 'when tag_list is the same' do
610
726
  before(:each) do
611
- @taggable.tag_list = "awesome, epic"
727
+ @taggable.tag_list = 'awesome, epic'
612
728
  end
613
729
 
614
730
  it 'is not flagged as changed' do
615
- @taggable.tag_list_changed?.should be_false
731
+ expect(@taggable.tag_list_changed?).to be_falsy
616
732
  end
617
733
 
618
734
  it 'does not show any changes to the taggable item' do
619
- @taggable.changes.should == {}
735
+ expect(@taggable.changes).to be_empty
620
736
  end
621
737
 
622
738
  context "and using a delimiter different from a ','" do
@@ -630,64 +746,134 @@ describe "Taggable" do
630
746
  end
631
747
 
632
748
  it 'does not show any changes to the taggable item when using array assignments' do
633
- @taggable.tag_list = ["awesome", "epic"]
634
- @taggable.changes.should == {}
749
+ @taggable.tag_list = %w(awesome epic)
750
+ expect(@taggable.changes).to be_empty
635
751
  end
636
752
  end
637
753
  end
638
754
  end
639
755
 
640
- context "with context tags" do
756
+ context 'with context tags' do
641
757
  before(:each) do
642
- @taggable = TaggableModel.create(:language_list => "awesome, epic")
758
+ @taggable = TaggableModel.create('language_list' => 'awesome, epic')
643
759
  end
644
760
 
645
- context "when language_list changed" do
761
+ context 'when language_list changed' do
646
762
  before(:each) do
647
- @taggable.changes.should == {}
763
+ expect(@taggable.changes).to be_empty
648
764
  @taggable.language_list = 'one'
649
765
  end
650
766
 
651
767
  it 'should show changes of dirty object' do
652
- @taggable.changes.should == {"language_list"=>["awesome, epic", ["one"]]}
768
+ expect(@taggable.changes).to eq({'language_list' => ['awesome, epic', ['one']]})
653
769
  end
654
770
 
655
771
  it 'flags language_list as changed' do
656
- @taggable.language_list_changed?.should be_true
772
+ expect(@taggable.language_list_changed?).to be_truthy
657
773
  end
658
774
 
659
775
  it 'preserves original value' do
660
- @taggable.language_list_was.should == "awesome, epic"
776
+ expect(@taggable.language_list_was).to eq('awesome, epic')
661
777
  end
662
778
 
663
779
  it 'shows what the change was' do
664
- @taggable.language_list_change.should == ["awesome, epic", ["one"]]
780
+ expect(@taggable.language_list_change).to eq(['awesome, epic', ['one']])
665
781
  end
666
782
 
667
783
  it 'shows what the changes were' do
668
- @taggable.language_list_changes.should == ["awesome, epic", ["one"]]
784
+ expect(@taggable.language_list_changes).to eq(['awesome, epic', ['one']])
669
785
  end
670
786
  end
671
787
 
672
788
  context 'when language_list is the same' do
673
789
  before(:each) do
674
- @taggable.language_list = "awesome, epic"
790
+ @taggable.language_list = 'awesome, epic'
675
791
  end
676
792
 
677
793
  it 'is not flagged as changed' do
678
- @taggable.language_list_changed?.should be_false
794
+ expect(@taggable.language_list_changed?).to be_falsy
679
795
  end
680
796
 
681
797
  it 'does not show any changes to the taggable item' do
682
- @taggable.changes.should == {}
798
+ expect(@taggable.changes).to be_empty
799
+ end
800
+ end
801
+ end
802
+ end
803
+
804
+ describe 'Autogenerated methods' do
805
+ it 'should be overridable' do
806
+ expect(TaggableModel.create(tag_list: 'woo').tag_list_submethod_called).to be_truthy
807
+ end
808
+ end
809
+
810
+ # See https://github.com/mbleigh/acts-as-taggable-on/pull/457 for details
811
+ context 'tag_counts and aggreating scopes, compatability with MySQL ' do
812
+ before(:each) do
813
+ TaggableModel.new(:name => 'Barb Jones').tap { |t| t.tag_list = %w(awesome fun) }.save
814
+ TaggableModel.new(:name => 'John Doe').tap { |t| t.tag_list = %w(cool fun hella) }.save
815
+ TaggableModel.new(:name => 'Jo Doe').tap { |t| t.tag_list = %w(curious young naive sharp) }.save
816
+
817
+ TaggableModel.all.each { |t| t.save }
818
+ end
819
+
820
+ context 'Model.limit(x).tag_counts.sum(:tags_count)' do
821
+ it 'should not break on Mysql' do
822
+ # Activerecord 3.2 return a string
823
+ expect(TaggableModel.limit(2).tag_counts.sum('tags_count').to_i).to eq(5)
824
+ end
825
+ end
826
+
827
+ context 'regression prevention, just making sure these esoteric queries still work' do
828
+ context 'Model.tag_counts.limit(x)' do
829
+ it 'should limit the tag objects (not very useful, of course)' do
830
+ array_of_tag_counts = TaggableModel.tag_counts.limit(2)
831
+ expect(array_of_tag_counts.count).to eq(2)
832
+ end
833
+ end
834
+
835
+ context 'Model.tag_counts.sum(:tags_count)' do
836
+ it 'should limit the total tags used' do
837
+ expect(TaggableModel.tag_counts.sum(:tags_count).to_i).to eq(9)
838
+ end
839
+ end
840
+
841
+ context 'Model.tag_counts.limit(2).sum(:tags_count)' do
842
+ it 'limit should have no effect; this is just a sanity check' do
843
+ expect(TaggableModel.tag_counts.limit(2).sum(:tags_count).to_i).to eq(9)
683
844
  end
684
845
  end
685
846
  end
686
847
  end
848
+ end
849
+
850
+
851
+ if ActsAsTaggableOn::Utils.using_postgresql?
852
+ describe 'Taggable model with json columns' do
853
+ before(:each) do
854
+ @taggable = TaggableModelWithJson.new(:name => 'Bob Jones')
855
+ @taggables = [@taggable, TaggableModelWithJson.new(:name => 'John Doe')]
856
+ end
857
+
858
+ it 'should be able to find by tag with context' do
859
+ @taggable.skill_list = 'ruby, rails, css'
860
+ @taggable.tag_list = 'bob, charlie'
861
+ @taggable.save
862
+
863
+ expect(TaggableModelWithJson.tagged_with('ruby').first).to eq(@taggable)
864
+ expect(TaggableModelWithJson.tagged_with('ruby, css').first).to eq(@taggable)
865
+ expect(TaggableModelWithJson.tagged_with('bob', :on => :skills).first).to_not eq(@taggable)
866
+ expect(TaggableModelWithJson.tagged_with('bob', :on => :tags).first).to eq(@taggable)
867
+ end
868
+
869
+ it 'should be able to find tagged with any tag' do
870
+ bob = TaggableModelWithJson.create(:name => 'Bob', :tag_list => 'fitter, happier, more productive', :skill_list => 'ruby, rails, css')
871
+ frank = TaggableModelWithJson.create(:name => 'Frank', :tag_list => 'weaker, depressed, inefficient', :skill_list => 'ruby, rails, css')
872
+ steve = TaggableModelWithJson.create(:name => 'Steve', :tag_list => 'fitter, happier, more productive', :skill_list => 'c++, java, ruby')
687
873
 
688
- describe "Autogenerated methods" do
689
- it "should be overridable" do
690
- TaggableModel.create(:tag_list=>'woo').tag_list_submethod_called.should be_true
874
+ expect(TaggableModelWithJson.tagged_with(%w(ruby java), :order => 'taggable_model_with_jsons.name', :any => true).to_a).to eq([bob, frank, steve])
875
+ expect(TaggableModelWithJson.tagged_with(%w(c++ fitter), :order => 'taggable_model_with_jsons.name', :any => true).to_a).to eq([bob, steve])
876
+ expect(TaggableModelWithJson.tagged_with(%w(depressed css), :order => 'taggable_model_with_jsons.name', :any => true).to_a).to eq([bob, frank])
691
877
  end
692
878
  end
693
879
  end