acts-as-taggable-on 3.1.1 → 3.2.1

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