make_taggable 0.6.5 → 0.7.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (127) hide show
  1. checksums.yaml +4 -4
  2. data/.dummyrc +17 -0
  3. data/.github/workflows/ci.yml +115 -22
  4. data/.github/workflows/standard-ci.yml +27 -0
  5. data/.gitignore +4 -0
  6. data/Appraisals +4 -0
  7. data/CONTRIBUTING.md +5 -31
  8. data/README.md +62 -37
  9. data/Rakefile +3 -0
  10. data/UPGRADING.md +1 -1
  11. data/gemfiles/rails_6_1.gemfile +9 -0
  12. data/lib/make_taggable.rb +4 -4
  13. data/lib/make_taggable/tag.rb +1 -1
  14. data/lib/make_taggable/version.rb +1 -2
  15. data/lib/tasks/setup_test_db.rake +8 -0
  16. data/make_taggable.gemspec +29 -15
  17. metadata +110 -253
  18. data/.standard.yml +0 -18
  19. data/.standard_todo.yml +0 -5
  20. data/.travis.yml +0 -36
  21. data/LICENSE.txt +0 -21
  22. data/spec/dummy/README.md +0 -24
  23. data/spec/dummy/Rakefile +0 -6
  24. data/spec/dummy/app/assets/config/manifest.js +0 -2
  25. data/spec/dummy/app/channels/application_cable/channel.rb +0 -4
  26. data/spec/dummy/app/channels/application_cable/connection.rb +0 -4
  27. data/spec/dummy/app/controllers/application_controller.rb +0 -2
  28. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  29. data/spec/dummy/app/jobs/application_job.rb +0 -7
  30. data/spec/dummy/app/mailers/application_mailer.rb +0 -4
  31. data/spec/dummy/app/models/altered_inheriting_taggable_model.rb +0 -5
  32. data/spec/dummy/app/models/application_record.rb +0 -3
  33. data/spec/dummy/app/models/cached_model.rb +0 -3
  34. data/spec/dummy/app/models/cached_model_with_array.rb +0 -11
  35. data/spec/dummy/app/models/columns_override_model.rb +0 -5
  36. data/spec/dummy/app/models/company.rb +0 -15
  37. data/spec/dummy/app/models/concerns/.keep +0 -0
  38. data/spec/dummy/app/models/inheriting_taggable_model.rb +0 -4
  39. data/spec/dummy/app/models/market.rb +0 -2
  40. data/spec/dummy/app/models/non_standard_id_taggable_model.rb +0 -8
  41. data/spec/dummy/app/models/ordered_taggable_model.rb +0 -4
  42. data/spec/dummy/app/models/other_cached_model.rb +0 -3
  43. data/spec/dummy/app/models/other_taggable_model.rb +0 -4
  44. data/spec/dummy/app/models/student.rb +0 -4
  45. data/spec/dummy/app/models/taggable_model.rb +0 -14
  46. data/spec/dummy/app/models/untaggable_model.rb +0 -3
  47. data/spec/dummy/app/models/user.rb +0 -3
  48. data/spec/dummy/app/views/layouts/mailer.html.erb +0 -13
  49. data/spec/dummy/app/views/layouts/mailer.text.erb +0 -1
  50. data/spec/dummy/bin/rails +0 -4
  51. data/spec/dummy/bin/rake +0 -4
  52. data/spec/dummy/bin/setup +0 -33
  53. data/spec/dummy/config.ru +0 -5
  54. data/spec/dummy/config/application.rb +0 -19
  55. data/spec/dummy/config/boot.rb +0 -5
  56. data/spec/dummy/config/cable.yml +0 -10
  57. data/spec/dummy/config/credentials.yml.enc +0 -1
  58. data/spec/dummy/config/database.yml +0 -25
  59. data/spec/dummy/config/environment.rb +0 -5
  60. data/spec/dummy/config/environments/development.rb +0 -52
  61. data/spec/dummy/config/environments/production.rb +0 -105
  62. data/spec/dummy/config/environments/test.rb +0 -49
  63. data/spec/dummy/config/initializers/application_controller_renderer.rb +0 -8
  64. data/spec/dummy/config/initializers/backtrace_silencers.rb +0 -7
  65. data/spec/dummy/config/initializers/cors.rb +0 -16
  66. data/spec/dummy/config/initializers/filter_parameter_logging.rb +0 -4
  67. data/spec/dummy/config/initializers/inflections.rb +0 -16
  68. data/spec/dummy/config/initializers/mime_types.rb +0 -4
  69. data/spec/dummy/config/initializers/wrap_parameters.rb +0 -14
  70. data/spec/dummy/config/locales/en.yml +0 -33
  71. data/spec/dummy/config/master.key +0 -1
  72. data/spec/dummy/config/puma.rb +0 -38
  73. data/spec/dummy/config/routes.rb +0 -3
  74. data/spec/dummy/config/spring.rb +0 -6
  75. data/spec/dummy/config/storage.yml +0 -34
  76. data/spec/dummy/db/migrate/20201119220853_create_taggable_models.rb +0 -8
  77. data/spec/dummy/db/migrate/20201119221037_create_columns_override_models.rb +0 -9
  78. data/spec/dummy/db/migrate/20201119221121_create_non_standard_id_taggable_models.rb +0 -8
  79. data/spec/dummy/db/migrate/20201119221228_create_untaggable_models.rb +0 -8
  80. data/spec/dummy/db/migrate/20201119221247_create_cached_models.rb +0 -9
  81. data/spec/dummy/db/migrate/20201119221314_create_other_cached_models.rb +0 -11
  82. data/spec/dummy/db/migrate/20201119221343_create_companies.rb +0 -7
  83. data/spec/dummy/db/migrate/20201119221416_create_users.rb +0 -7
  84. data/spec/dummy/db/migrate/20201119221434_create_other_taggable_models.rb +0 -8
  85. data/spec/dummy/db/migrate/20201119221507_create_ordered_taggable_models.rb +0 -8
  86. data/spec/dummy/db/migrate/20201119221530_create_cache_methods_injected_models.rb +0 -7
  87. data/spec/dummy/db/migrate/20201119221629_create_other_cached_with_array_models.rb +0 -11
  88. data/spec/dummy/db/migrate/20201119221746_create_taggable_model_with_jsons.rb +0 -9
  89. data/spec/dummy/db/migrate/20201121222007_create_make_taggable_tags.make_taggable_engine.rb +0 -11
  90. data/spec/dummy/db/migrate/20201121222008_create_make_taggable_taggings.make_taggable_engine.rb +0 -13
  91. data/spec/dummy/db/migrate/20201121222009_change_tag_name_collation_mysql.make_taggable_engine.rb +0 -8
  92. data/spec/dummy/db/migrate/20201121222010_add_index_to_tags.make_taggable_engine.rb +0 -6
  93. data/spec/dummy/db/migrate/20201121222011_add_index_to_taggings.make_taggable_engine.rb +0 -13
  94. data/spec/dummy/db/schema.rb +0 -117
  95. data/spec/dummy/db/seeds.rb +0 -7
  96. data/spec/dummy/lib/tasks/.keep +0 -0
  97. data/spec/dummy/log/.keep +0 -0
  98. data/spec/dummy/public/robots.txt +0 -1
  99. data/spec/dummy/storage/.keep +0 -0
  100. data/spec/dummy/test/channels/application_cable/connection_test.rb +0 -11
  101. data/spec/dummy/test/controllers/.keep +0 -0
  102. data/spec/dummy/test/fixtures/.keep +0 -0
  103. data/spec/dummy/test/fixtures/files/.keep +0 -0
  104. data/spec/dummy/test/integration/.keep +0 -0
  105. data/spec/dummy/test/mailers/.keep +0 -0
  106. data/spec/dummy/test/models/.keep +0 -0
  107. data/spec/dummy/test/test_helper.rb +0 -13
  108. data/spec/dummy/vendor/.keep +0 -0
  109. data/spec/make_taggable/acts_as_tagger_spec.rb +0 -112
  110. data/spec/make_taggable/caching_spec.rb +0 -123
  111. data/spec/make_taggable/default_parser_spec.rb +0 -45
  112. data/spec/make_taggable/dirty_spec.rb +0 -140
  113. data/spec/make_taggable/generic_parser_spec.rb +0 -13
  114. data/spec/make_taggable/make_taggable_spec.rb +0 -260
  115. data/spec/make_taggable/related_spec.rb +0 -93
  116. data/spec/make_taggable/single_table_inheritance_spec.rb +0 -220
  117. data/spec/make_taggable/tag_list_spec.rb +0 -169
  118. data/spec/make_taggable/tag_spec.rb +0 -297
  119. data/spec/make_taggable/taggable_spec.rb +0 -804
  120. data/spec/make_taggable/tagger_spec.rb +0 -149
  121. data/spec/make_taggable/tagging_spec.rb +0 -115
  122. data/spec/make_taggable/tags_helper_spec.rb +0 -43
  123. data/spec/make_taggable/utils_spec.rb +0 -22
  124. data/spec/make_taggable_spec.rb +0 -5
  125. data/spec/spec_helper.rb +0 -18
  126. data/spec/support/array.rb +0 -9
  127. data/spec/support/helpers.rb +0 -31
@@ -1,297 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe MakeTaggable::Tag do
4
- before(:each) do
5
- @tag = MakeTaggable::Tag.new
6
- @user = TaggableModel.create(name: "Pablo")
7
- end
8
-
9
- describe "named like any" do
10
- context "case insensitive collation and unique index on tag name", if: using_case_insensitive_collation? do
11
- before(:each) do
12
- MakeTaggable::Tag.create(name: "Awesome")
13
- MakeTaggable::Tag.create(name: "epic")
14
- end
15
-
16
- it "should find both tags" do
17
- expect(MakeTaggable::Tag.named_like_any(%w[awesome epic]).count).to eq(2)
18
- end
19
- end
20
-
21
- context "case insensitive collation without indexes or case sensitive collation with indexes" do
22
- before(:each) do
23
- MakeTaggable::Tag.create(name: "Awesome")
24
- MakeTaggable::Tag.create(name: "awesome")
25
- MakeTaggable::Tag.create(name: "epic")
26
- end
27
-
28
- it "should find both tags" do
29
- expect(MakeTaggable::Tag.named_like_any(%w[awesome epic]).count).to eq(3)
30
- end
31
- end
32
- end
33
-
34
- describe "named any" do
35
- context "with some special characters combinations", if: using_mysql? do
36
- it "should not raise an invalid encoding exception" do
37
- expect { MakeTaggable::Tag.named_any(["holä", "hol'ä"]) }.not_to raise_error
38
- end
39
- end
40
- end
41
-
42
- describe "for context" do
43
- before(:each) do
44
- @user.skill_list.add("ruby")
45
- @user.save
46
- end
47
-
48
- it "should return tags that have been used in the given context" do
49
- expect(MakeTaggable::Tag.for_context("skills").pluck(:name)).to include("ruby")
50
- end
51
-
52
- it "should not return tags that have been used in other contexts" do
53
- expect(MakeTaggable::Tag.for_context("needs").pluck(:name)).to_not include("ruby")
54
- end
55
- end
56
-
57
- describe "find or create by name" do
58
- before(:each) do
59
- @tag.name = "awesome"
60
- @tag.save
61
- end
62
-
63
- it "should find by name" do
64
- expect(MakeTaggable::Tag.find_or_create_with_like_by_name("awesome")).to eq(@tag)
65
- end
66
-
67
- it "should find by name case insensitive" do
68
- expect(MakeTaggable::Tag.find_or_create_with_like_by_name("AWESOME")).to eq(@tag)
69
- end
70
-
71
- it "should create by name" do
72
- expect(-> {
73
- MakeTaggable::Tag.find_or_create_with_like_by_name("epic")
74
- }).to change(MakeTaggable::Tag, :count).by(1)
75
- end
76
- end
77
-
78
- describe "find or create by unicode name", unless: using_sqlite? do
79
- before(:each) do
80
- @tag.name = "привет"
81
- @tag.save
82
- end
83
-
84
- it "should find by name" do
85
- expect(MakeTaggable::Tag.find_or_create_with_like_by_name("привет")).to eq(@tag)
86
- end
87
-
88
- it "should find by name case insensitive" do
89
- expect(MakeTaggable::Tag.find_or_create_with_like_by_name("ПРИВЕТ")).to eq(@tag)
90
- end
91
-
92
- it "should find by name accent insensitive", if: using_case_insensitive_collation? do
93
- @tag.name = "inupiat"
94
- @tag.save
95
- expect(MakeTaggable::Tag.find_or_create_with_like_by_name("Iñupiat")).to eq(@tag)
96
- end
97
- end
98
-
99
- describe "find or create all by any name" do
100
- before(:each) do
101
- @tag.name = "awesome"
102
- @tag.save
103
- end
104
-
105
- it "should find by name" do
106
- expect(MakeTaggable::Tag.find_or_create_all_with_like_by_name("awesome")).to eq([@tag])
107
- end
108
-
109
- it "should find by name case insensitive" do
110
- expect(MakeTaggable::Tag.find_or_create_all_with_like_by_name("AWESOME")).to eq([@tag])
111
- end
112
-
113
- context "case sensitive" do
114
- it "should find by name case sensitive" do
115
- MakeTaggable.strict_case_match = true
116
- expect {
117
- MakeTaggable::Tag.find_or_create_all_with_like_by_name("AWESOME")
118
- }.to change(MakeTaggable::Tag, :count).by(1)
119
- end
120
- end
121
-
122
- it "should create by name" do
123
- expect {
124
- MakeTaggable::Tag.find_or_create_all_with_like_by_name("epic")
125
- }.to change(MakeTaggable::Tag, :count).by(1)
126
- end
127
-
128
- context "case sensitive" do
129
- it "should find or create by name case sensitive" do
130
- MakeTaggable.strict_case_match = true
131
- expect {
132
- expect(MakeTaggable::Tag.find_or_create_all_with_like_by_name("AWESOME", "awesome").map(&:name)).to eq(%w[AWESOME awesome])
133
- }.to change(MakeTaggable::Tag, :count).by(1)
134
- end
135
- end
136
-
137
- it "should find or create by name" do
138
- expect {
139
- expect(MakeTaggable::Tag.find_or_create_all_with_like_by_name("awesome", "epic").map(&:name)).to eq(%w[awesome epic])
140
- }.to change(MakeTaggable::Tag, :count).by(1)
141
- end
142
-
143
- it "should return an empty array if no tags are specified" do
144
- expect(MakeTaggable::Tag.find_or_create_all_with_like_by_name([])).to be_empty
145
- end
146
- end
147
-
148
- it "should require a name" do
149
- @tag.valid?
150
- # TODO, we should find another way to check this
151
- expect(@tag.errors[:name]).to eq(["can't be blank"])
152
-
153
- @tag.name = "something"
154
- @tag.valid?
155
-
156
- expect(@tag.errors[:name]).to be_empty
157
- end
158
-
159
- it "should limit the name length to 255 or less characters" do
160
- @tag.name = "fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxranr"
161
- @tag.valid?
162
- # TODO, we should find another way to check this
163
- expect(@tag.errors[:name]).to eq(["is too long (maximum is 255 characters)"])
164
-
165
- @tag.name = "fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxran"
166
- @tag.valid?
167
- expect(@tag.errors[:name]).to be_empty
168
- end
169
-
170
- it "should equal a tag with the same name" do
171
- @tag.name = "awesome"
172
- new_tag = MakeTaggable::Tag.new(name: "awesome")
173
- expect(new_tag).to eq(@tag)
174
- end
175
-
176
- it "should return its name when to_s is called" do
177
- @tag.name = "cool"
178
- expect(@tag.to_s).to eq("cool")
179
- end
180
-
181
- it "have named_scope named(something)" do
182
- @tag.name = "cool"
183
- @tag.save!
184
- expect(MakeTaggable::Tag.named("cool")).to include(@tag)
185
- end
186
-
187
- it "have named_scope named_like(something)" do
188
- @tag.name = "cool"
189
- @tag.save!
190
- @another_tag = MakeTaggable::Tag.create!(name: "coolip")
191
- expect(MakeTaggable::Tag.named_like("cool")).to include(@tag, @another_tag)
192
- end
193
-
194
- describe "escape wildcard symbols in like requests" do
195
- before(:each) do
196
- @tag.name = "cool"
197
- @tag.save
198
- @another_tag = MakeTaggable::Tag.create!(name: "coo%")
199
- @another_tag2 = MakeTaggable::Tag.create!(name: "coolish")
200
- end
201
-
202
- it "return escaped result when '%' char present in tag" do
203
- expect(MakeTaggable::Tag.named_like("coo%")).to_not include(@tag)
204
- expect(MakeTaggable::Tag.named_like("coo%")).to include(@another_tag)
205
- end
206
- end
207
-
208
- describe "when using strict_case_match" do
209
- before do
210
- MakeTaggable.strict_case_match = true
211
- @tag.name = "awesome"
212
- @tag.save!
213
- end
214
-
215
- after do
216
- MakeTaggable.strict_case_match = false
217
- end
218
-
219
- it "should find by name" do
220
- expect(MakeTaggable::Tag.find_or_create_with_like_by_name("awesome")).to eq(@tag)
221
- end
222
-
223
- context "case sensitive" do
224
- it "should find by name case sensitively" do
225
- expect {
226
- MakeTaggable::Tag.find_or_create_with_like_by_name("AWESOME")
227
- }.to change(MakeTaggable::Tag, :count)
228
-
229
- expect(MakeTaggable::Tag.last.name).to eq("AWESOME")
230
- end
231
- end
232
-
233
- context "case sensitive" do
234
- it "should have a named_scope named(something) that matches exactly" do
235
- uppercase_tag = MakeTaggable::Tag.create(name: "Cool")
236
- @tag.name = "cool"
237
- @tag.save!
238
-
239
- expect(MakeTaggable::Tag.named("cool")).to include(@tag)
240
- expect(MakeTaggable::Tag.named("cool")).to_not include(uppercase_tag)
241
- end
242
- end
243
-
244
- it "should not change encoding" do
245
- name = "\u3042"
246
- original_encoding = name.encoding
247
- record = MakeTaggable::Tag.find_or_create_with_like_by_name(name)
248
- record.reload
249
- expect(record.name.encoding).to eq(original_encoding)
250
- end
251
-
252
- context "named any with some special characters combinations", if: using_mysql? do
253
- it "should not raise an invalid encoding exception" do
254
- expect { MakeTaggable::Tag.named_any(["holä", "hol'ä"]) }.not_to raise_error
255
- end
256
- end
257
- end
258
-
259
- describe "name uniqeness validation" do
260
- let(:duplicate_tag) { MakeTaggable::Tag.new(name: "ror") }
261
-
262
- before { MakeTaggable::Tag.create(name: "ror") }
263
-
264
- context "when do need unique names" do
265
- it "should run uniqueness validation" do
266
- expect(duplicate_tag).to_not be_valid
267
- end
268
-
269
- it "add error to name" do
270
- duplicate_tag.save
271
-
272
- expect(duplicate_tag.errors.size).to eq(1)
273
- expect(duplicate_tag.errors.messages[:name]).to include("has already been taken")
274
- end
275
- end
276
- end
277
-
278
- describe "popular tags" do
279
- before do
280
- %w[sports rails linux tennis golden_syrup].each_with_index do |t, i|
281
- tag = MakeTaggable::Tag.new(name: t)
282
- tag.taggings_count = i
283
- tag.save!
284
- end
285
- end
286
-
287
- it "should find the most popular tags" do
288
- expect(MakeTaggable::Tag.most_used(3).first.name).to eq("golden_syrup")
289
- expect(MakeTaggable::Tag.most_used(3).length).to eq(3)
290
- end
291
-
292
- it "should find the least popular tags" do
293
- expect(MakeTaggable::Tag.least_used(3).first.name).to eq("sports")
294
- expect(MakeTaggable::Tag.least_used(3).length).to eq(3)
295
- end
296
- end
297
- end
@@ -1,804 +0,0 @@
1
- require "spec_helper"
2
-
3
- describe "Taggable To Preserve Order" do
4
- before(:each) do
5
- @taggable = OrderedTaggableModel.new(name: "Bob Jones")
6
- end
7
-
8
- it "should have tag associations" do
9
- [:tags, :colours].each do |type|
10
- expect(@taggable.respond_to?(type)).to be_truthy
11
- expect(@taggable.respond_to?("#{type.to_s.singularize}_taggings")).to be_truthy
12
- end
13
- end
14
-
15
- it "should have tag methods" do
16
- [:tags, :colours].each do |type|
17
- expect(@taggable.respond_to?("#{type.to_s.singularize}_list")).to be_truthy
18
- expect(@taggable.respond_to?("#{type.to_s.singularize}_list=")).to be_truthy
19
- expect(@taggable.respond_to?("all_#{type}_list")).to be_truthy
20
- end
21
- end
22
-
23
- it "should return tag list in the order the tags were created" do
24
- # create
25
- @taggable.tag_list = "rails, ruby, css"
26
- expect(@taggable.instance_variable_get("@tag_list").instance_of?(MakeTaggable::TagList)).to be_truthy
27
-
28
- expect(-> {
29
- @taggable.save
30
- }).to change(MakeTaggable::Tag, :count).by(3)
31
-
32
- @taggable.reload
33
- expect(@taggable.tag_list).to eq(%w[rails ruby css])
34
-
35
- # update
36
- @taggable.tag_list = "pow, ruby, rails"
37
- @taggable.save
38
-
39
- @taggable.reload
40
- expect(@taggable.tag_list).to eq(%w[pow ruby rails])
41
-
42
- # update with no change
43
- @taggable.tag_list = "pow, ruby, rails"
44
- @taggable.save
45
-
46
- @taggable.reload
47
- expect(@taggable.tag_list).to eq(%w[pow ruby rails])
48
-
49
- # update to clear tags
50
- @taggable.tag_list = ""
51
- @taggable.save
52
-
53
- @taggable.reload
54
- expect(@taggable.tag_list).to be_empty
55
- end
56
-
57
- it "should return tag objects in the order the tags were created" do
58
- # create
59
- @taggable.tag_list = "pow, ruby, rails"
60
- expect(@taggable.instance_variable_get("@tag_list").instance_of?(MakeTaggable::TagList)).to be_truthy
61
-
62
- expect(-> {
63
- @taggable.save
64
- }).to change(MakeTaggable::Tag, :count).by(3)
65
-
66
- @taggable.reload
67
- expect(@taggable.tags.map { |t| t.name }).to eq(%w[pow ruby rails])
68
-
69
- # update
70
- @taggable.tag_list = "rails, ruby, css, pow"
71
- @taggable.save
72
-
73
- @taggable.reload
74
- expect(@taggable.tags.map { |t| t.name }).to eq(%w[rails ruby css pow])
75
- end
76
-
77
- it "should return tag objects in tagging id order" do
78
- # create
79
- @taggable.tag_list = "pow, ruby, rails"
80
- @taggable.save
81
-
82
- @taggable.reload
83
- ids = @taggable.tags.map { |t| t.taggings.first.id }
84
- expect(ids).to eq(ids.sort)
85
-
86
- # update
87
- @taggable.tag_list = "rails, ruby, css, pow"
88
- @taggable.save
89
-
90
- @taggable.reload
91
- ids = @taggable.tags.map { |t| t.taggings.first.id }
92
- expect(ids).to eq(ids.sort)
93
- end
94
- end
95
-
96
- describe "Taggable" do
97
- before(:each) do
98
- @taggable = TaggableModel.new(name: "Bob Jones")
99
- @taggables = [@taggable, TaggableModel.new(name: "John Doe")]
100
- end
101
-
102
- it "should have tag types" do
103
- [:tags, :languages, :skills, :needs, :offerings].each do |type|
104
- expect(TaggableModel.tag_types).to include type
105
- end
106
-
107
- expect(@taggable.tag_types).to eq(TaggableModel.tag_types)
108
- end
109
-
110
- it "should have tag_counts_on" do
111
- expect(TaggableModel.tag_counts_on(:tags)).to be_empty
112
-
113
- @taggable.tag_list = %w[awesome epic]
114
- @taggable.save
115
-
116
- expect(TaggableModel.tag_counts_on(:tags).length).to eq(2)
117
- expect(@taggable.tag_counts_on(:tags).length).to eq(2)
118
- end
119
-
120
- context "tag_counts on a collection" do
121
- context "a select clause is specified on the collection" do
122
- it "should return tag counts without raising an error" do
123
- expect(TaggableModel.tag_counts_on(:tags)).to be_empty
124
-
125
- @taggable.tag_list = %w[awesome epic]
126
- @taggable.save
127
-
128
- expect {
129
- expect(TaggableModel.select(:name).tag_counts_on(:tags).length).to eq(2)
130
- }.not_to raise_error
131
- end
132
- end
133
- end
134
-
135
- it "should have tags_on" do
136
- expect(TaggableModel.tags_on(:tags)).to be_empty
137
-
138
- @taggable.tag_list = %w[awesome epic]
139
- @taggable.save
140
-
141
- expect(TaggableModel.tags_on(:tags).length).to eq(2)
142
- expect(@taggable.tags_on(:tags).length).to eq(2)
143
- end
144
-
145
- it "should return [] right after create" do
146
- blank_taggable = TaggableModel.new(name: "Bob Jones")
147
- expect(blank_taggable.tag_list).to be_empty
148
- end
149
-
150
- it "should be able to create tags" do
151
- @taggable.skill_list = "ruby, rails, css"
152
- expect(@taggable.instance_variable_get("@skill_list").instance_of?(MakeTaggable::TagList)).to be_truthy
153
-
154
- expect(-> {
155
- @taggable.save
156
- }).to change(MakeTaggable::Tag, :count).by(3)
157
-
158
- @taggable.reload
159
- expect(@taggable.skill_list.sort).to eq(%w[ruby rails css].sort)
160
- end
161
-
162
- it "should be able to create tags through the tag list directly" do
163
- @taggable.tag_list_on(:test).add("hello")
164
- expect(@taggable.tag_list_cache_on(:test)).to_not be_empty
165
- expect(@taggable.tag_list_on(:test)).to eq(["hello"])
166
-
167
- @taggable.save
168
- @taggable.save_tags
169
-
170
- @taggable.reload
171
- expect(@taggable.tag_list_on(:test)).to eq(["hello"])
172
- end
173
-
174
- it "should differentiate between contexts" do
175
- @taggable.skill_list = "ruby, rails, css"
176
- @taggable.tag_list = "ruby, bob, charlie"
177
- @taggable.save
178
- @taggable.reload
179
- expect(@taggable.skill_list).to include("ruby")
180
- expect(@taggable.skill_list).to_not include("bob")
181
- end
182
-
183
- it "should be able to remove tags through list alone" do
184
- @taggable.skill_list = "ruby, rails, css"
185
- @taggable.save
186
- @taggable.reload
187
- expect(@taggable.skills.count).to eq(3)
188
- @taggable.skill_list = "ruby, rails"
189
- @taggable.save
190
- @taggable.reload
191
- expect(@taggable.skills.count).to eq(2)
192
- end
193
-
194
- it "should be able to select taggables by subset of tags using ActiveRelation methods" do
195
- @taggables[0].tag_list = "bob"
196
- @taggables[1].tag_list = "charlie"
197
- @taggables[0].skill_list = "ruby"
198
- @taggables[1].skill_list = "css"
199
- @taggables.each { |taggable| taggable.save }
200
-
201
- @found_taggables_by_tag = TaggableModel.joins(:tags).where(MakeTaggable.tags_table => {name: ["bob"]})
202
- @found_taggables_by_skill = TaggableModel.joins(:skills).where(MakeTaggable.tags_table => {name: ["ruby"]})
203
-
204
- expect(@found_taggables_by_tag).to include @taggables[0]
205
- expect(@found_taggables_by_tag).to_not include @taggables[1]
206
- expect(@found_taggables_by_skill).to include @taggables[0]
207
- expect(@found_taggables_by_skill).to_not include @taggables[1]
208
- end
209
-
210
- it "should be able to find by tag" do
211
- @taggable.skill_list = "ruby, rails, css"
212
- @taggable.save
213
-
214
- expect(TaggableModel.tagged_with("ruby").first).to eq(@taggable)
215
- end
216
-
217
- it "should be able to get a count with find by tag when using a group by" do
218
- @taggable.skill_list = "ruby"
219
- @taggable.save
220
-
221
- expect(TaggableModel.tagged_with("ruby").group(:created_at).count.count).to eq(1)
222
- end
223
-
224
- it "can be used as scope" do
225
- @taggable.skill_list = "ruby"
226
- @taggable.save
227
- untaggable_model = @taggable.untaggable_models.create!(name: "foobar")
228
- scope_tag = TaggableModel.tagged_with("ruby", any: "distinct", order: "taggable_models.name asc")
229
- expect(UntaggableModel.joins(:taggable_model).merge(scope_tag).except(:select)).to eq([untaggable_model])
230
- end
231
-
232
- it "shouldn't generate a query with DISTINCT by default" do
233
- @taggable.skill_list = "ruby, rails, css"
234
- @taggable.save
235
-
236
- expect(TaggableModel.tagged_with("ruby").to_sql).to_not match(/DISTINCT/)
237
- end
238
-
239
- it "should be able to find a tag using dates" do
240
- @taggable.skill_list = "ruby"
241
- @taggable.save
242
- today = Date.today.to_time.utc
243
- tomorrow = Date.tomorrow.to_time.utc
244
-
245
- expect(TaggableModel.tagged_with("ruby", start_at: today, end_at: tomorrow).count).to eq(1)
246
- end
247
-
248
- it "shouldn't be able to find a tag outside date range" do
249
- @taggable.skill_list = "ruby"
250
- @taggable.save
251
-
252
- expect(TaggableModel.tagged_with("ruby", start_at: Date.today - 2.days, end_at: Date.today - 1.day).count).to eq(0)
253
- end
254
-
255
- it "should be able to find by tag with context" do
256
- @taggable.skill_list = "ruby, rails, css, julia"
257
- @taggable.tag_list = "bob, charlie, julia"
258
- @taggable.save
259
-
260
- expect(TaggableModel.tagged_with("ruby").first).to eq(@taggable)
261
- expect(TaggableModel.tagged_with("ruby, css").first).to eq(@taggable)
262
- expect(TaggableModel.tagged_with("bob", on: :skills).first).to_not eq(@taggable)
263
- expect(TaggableModel.tagged_with("bob", on: :tags).first).to eq(@taggable)
264
- expect(TaggableModel.tagged_with("julia", on: :skills).size).to eq(1)
265
- expect(TaggableModel.tagged_with("julia", on: :tags).size).to eq(1)
266
- expect(TaggableModel.tagged_with("julia", on: nil).size).to eq(2)
267
- end
268
-
269
- it "should not care about case" do
270
- TaggableModel.create(name: "Bob", tag_list: "ruby")
271
- TaggableModel.create(name: "Frank", tag_list: "Ruby")
272
-
273
- expect(MakeTaggable::Tag.all.size).to eq(1)
274
- expect(TaggableModel.tagged_with("ruby").to_a).to eq(TaggableModel.tagged_with("Ruby").to_a)
275
- end
276
-
277
- it "should be able to find by tags with other joins in the query" do
278
- @taggable.skill_list = "ruby, rails, css"
279
- @taggable.tag_list = "bob, charlie"
280
- @taggable.save
281
-
282
- expect(TaggableModel.tagged_with(["bob", "css"], any: true).to_a).to eq([@taggable])
283
-
284
- bob = TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
285
- frank = TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
286
- charlie = TaggableModel.create(name: "Charlie", skill_list: "ruby, java")
287
-
288
- # Test for explicit distinct in select
289
- bob.untaggable_models.create!
290
- frank.untaggable_models.create!
291
- charlie.untaggable_models.create!
292
-
293
- 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)
294
-
295
- 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)
296
- end
297
-
298
- it "should not care about case for unicode names", unless: using_sqlite? do
299
- MakeTaggable.strict_case_match = false
300
- TaggableModel.create(name: "Anya", tag_list: "ПРИВЕТ")
301
- TaggableModel.create(name: "Igor", tag_list: "привет")
302
- TaggableModel.create(name: "Katia", tag_list: "ПРИВЕТ")
303
-
304
- expect(MakeTaggable::Tag.all.size).to eq(1)
305
- expect(TaggableModel.tagged_with("привет").to_a).to eq(TaggableModel.tagged_with("ПРИВЕТ").to_a)
306
- end
307
-
308
- context "should be able to create and find tags in languages without capitalization :" do
309
- MakeTaggable.strict_case_match = false
310
- {
311
- japanese: {name: "Chihiro", tag_list: "日本の"},
312
- hebrew: {name: "Salim", tag_list: "עברית"},
313
- chinese: {name: "Ieie", tag_list: "中国的"},
314
- arabic: {name: "Yasser", tag_list: "العربية"},
315
- emo: {name: "Emo", tag_list: "✏"}
316
- }.each do |language, values|
317
- it language do
318
- TaggableModel.create(values)
319
- expect(TaggableModel.tagged_with(values[:tag_list]).count).to eq(1)
320
- end
321
- end
322
- end
323
-
324
- it "should be able to get tag counts on model as a whole" do
325
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
326
- TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
327
- TaggableModel.create(name: "Charlie", skill_list: "ruby")
328
- expect(TaggableModel.tag_counts).to_not be_empty
329
- expect(TaggableModel.skill_counts).to_not be_empty
330
- end
331
-
332
- it "should be able to get all tag counts on model as whole" do
333
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
334
- TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
335
- TaggableModel.create(name: "Charlie", skill_list: "ruby")
336
-
337
- expect(TaggableModel.all_tag_counts).to_not be_empty
338
- expect(TaggableModel.all_tag_counts(order: "#{MakeTaggable.tags_table}.id").first.count).to eq(3) # ruby
339
- end
340
-
341
- it "should be able to get all tags on model as whole" do
342
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
343
- TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
344
- TaggableModel.create(name: "Charlie", skill_list: "ruby")
345
-
346
- expect(TaggableModel.all_tags).to_not be_empty
347
- expect(TaggableModel.all_tags(order: "#{MakeTaggable.tags_table}.id").first.name).to eq("ruby")
348
- end
349
-
350
- it "should be able to use named scopes to chain tag finds by any tags by context" do
351
- bob = TaggableModel.create(name: "Bob", need_list: "rails", offering_list: "c++")
352
- TaggableModel.create(name: "Frank", need_list: "css", offering_list: "css")
353
- TaggableModel.create(name: "Steve", need_list: "c++", offering_list: "java")
354
-
355
- # Let's only find those who need rails or css and are offering c++ or java
356
- expect(TaggableModel.tagged_with(["rails, css"], on: :needs, any: true).tagged_with(["c++", "java"], on: :offerings, any: true).to_a).to eq([bob])
357
- end
358
-
359
- it "should not return read-only records" do
360
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
361
- expect(TaggableModel.tagged_with("ruby").first).to_not be_readonly
362
- end
363
-
364
- it "should be able to get scoped tag counts" do
365
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
366
- TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
367
- TaggableModel.create(name: "Charlie", skill_list: "ruby")
368
-
369
- expect(TaggableModel.tagged_with("ruby").tag_counts(order: "#{MakeTaggable.tags_table}.id").first.count).to eq(2) # ruby
370
- expect(TaggableModel.tagged_with("ruby").skill_counts.first.count).to eq(1) # ruby
371
- end
372
-
373
- it "should be able to get all scoped tag counts" do
374
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
375
- TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
376
- TaggableModel.create(name: "Charlie", skill_list: "ruby")
377
-
378
- expect(TaggableModel.tagged_with("ruby").all_tag_counts(order: "#{MakeTaggable.tags_table}.id").first.count).to eq(3) # ruby
379
- end
380
-
381
- it "should be able to get all scoped tags" do
382
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
383
- TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
384
- TaggableModel.create(name: "Charlie", skill_list: "ruby")
385
-
386
- expect(TaggableModel.tagged_with("ruby").all_tags(order: "#{MakeTaggable.tags_table}.id").first.name).to eq("ruby")
387
- end
388
-
389
- it "should only return tag counts for the available scope" do
390
- frank = TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
391
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
392
- TaggableModel.create(name: "Charlie", skill_list: "ruby, java")
393
-
394
- expect(TaggableModel.tagged_with("rails").all_tag_counts.size).to eq(3)
395
- expect(TaggableModel.tagged_with("rails").all_tag_counts.any? { |tag| tag.name == "java" }).to be_falsy
396
-
397
- # Test specific join syntaxes:
398
- frank.untaggable_models.create!
399
- expect(TaggableModel.tagged_with("rails").joins(:untaggable_models).all_tag_counts.size).to eq(2)
400
- expect(TaggableModel.tagged_with("rails").joins([:untaggable_models]).all_tag_counts.size).to eq(2)
401
- end
402
-
403
- it "should only return tags for the available scope" do
404
- frank = TaggableModel.create(name: "Frank", tag_list: "ruby, rails")
405
- TaggableModel.create(name: "Bob", tag_list: "ruby, rails, css")
406
- TaggableModel.create(name: "Charlie", skill_list: "ruby, java")
407
-
408
- expect(TaggableModel.tagged_with("rails").all_tags.count).to eq(3)
409
- expect(TaggableModel.tagged_with("rails").all_tags.any? { |tag| tag.name == "java" }).to be_falsy
410
-
411
- # Test specific join syntaxes:
412
- frank.untaggable_models.create!
413
- expect(TaggableModel.tagged_with("rails").joins(:untaggable_models).all_tags.size).to eq(2)
414
- expect(TaggableModel.tagged_with("rails").joins([:untaggable_models]).all_tags.size).to eq(2)
415
- end
416
-
417
- it "should be able to set a custom tag context list" do
418
- bob = TaggableModel.create(name: "Bob")
419
- bob.set_tag_list_on(:rotors, "spinning, jumping")
420
- expect(bob.tag_list_on(:rotors)).to eq(%w[spinning jumping])
421
- bob.save
422
- bob.reload
423
- expect(bob.tags_on(:rotors)).to_not be_empty
424
- end
425
-
426
- it "should be able to find tagged" do
427
- bob = TaggableModel.create(name: "Bob", tag_list: "fitter, happier, more productive", skill_list: "ruby, rails, css")
428
- frank = TaggableModel.create(name: "Frank", tag_list: "weaker, depressed, inefficient", skill_list: "ruby, rails, css")
429
- steve = TaggableModel.create(name: "Steve", tag_list: "fitter, happier, more productive", skill_list: "c++, java, ruby")
430
-
431
- expect(TaggableModel.tagged_with("ruby", order: "taggable_models.name").to_a).to eq([bob, frank, steve])
432
- expect(TaggableModel.tagged_with("ruby, rails", order: "taggable_models.name").to_a).to eq([bob, frank])
433
- expect(TaggableModel.tagged_with(%w[ruby rails], order: "taggable_models.name").to_a).to eq([bob, frank])
434
- end
435
-
436
- it "should be able to find tagged with quotation marks" do
437
- bob = TaggableModel.create(name: "Bob", tag_list: "fitter, happier, more productive, 'I love the ,comma,'")
438
- expect(TaggableModel.tagged_with("'I love the ,comma,'")).to include(bob)
439
- end
440
-
441
- it "should be able to find tagged with invalid tags" do
442
- bob = TaggableModel.create(name: "Bob", tag_list: "fitter, happier, more productive")
443
- expect(TaggableModel.tagged_with("sad, happier")).to_not include(bob)
444
- end
445
-
446
- it "should be able to find tagged with any tag" do
447
- bob = TaggableModel.create(name: "Bob", tag_list: "fitter, happier, more productive", skill_list: "ruby, rails, css")
448
- frank = TaggableModel.create(name: "Frank", tag_list: "weaker, depressed, inefficient", skill_list: "ruby, rails, css")
449
- steve = TaggableModel.create(name: "Steve", tag_list: "fitter, happier, more productive", skill_list: "c++, java, ruby")
450
-
451
- expect(TaggableModel.tagged_with(%w[ruby java], order: "taggable_models.name", any: true).to_a).to eq([bob, frank, steve])
452
- expect(TaggableModel.tagged_with(%w[c++ fitter], order: "taggable_models.name", any: true).to_a).to eq([bob, steve])
453
- expect(TaggableModel.tagged_with(%w[depressed css], order: "taggable_models.name", any: true).to_a).to eq([bob, frank])
454
- end
455
-
456
- it "should be able to order by number of matching tags when matching any" do
457
- bob = TaggableModel.create(name: "Bob", tag_list: "fitter, happier, more productive", skill_list: "ruby, rails, css")
458
- frank = TaggableModel.create(name: "Frank", tag_list: "weaker, depressed, inefficient", skill_list: "ruby, rails, css")
459
- steve = TaggableModel.create(name: "Steve", tag_list: "fitter, happier, more productive", skill_list: "c++, java, ruby")
460
-
461
- 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])
462
- 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])
463
- 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])
464
- 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])
465
- 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])
466
- end
467
-
468
- context "wild: true" do
469
- it "should use params as wildcards" do
470
- bob = TaggableModel.create(name: "Bob", tag_list: "bob, tricia")
471
- frank = TaggableModel.create(name: "Frank", tag_list: "bobby, jim")
472
- steve = TaggableModel.create(name: "Steve", tag_list: "john, patricia")
473
- jim = TaggableModel.create(name: "Jim", tag_list: "jim, steve")
474
-
475
- expect(TaggableModel.tagged_with(%w[bob tricia], wild: true, any: true).to_a.sort_by { |o| o.id }).to eq([bob, frank, steve])
476
- expect(TaggableModel.tagged_with(%w[bob tricia], wild: true, exclude: true).to_a).to eq([jim])
477
- expect(TaggableModel.tagged_with('ji', wild: true, any: true).to_a).to match_array([frank, jim])
478
- end
479
- end
480
-
481
- it "should be able to find tagged on a custom tag context" do
482
- bob = TaggableModel.create(name: "Bob")
483
- bob.set_tag_list_on(:rotors, "spinning, jumping")
484
- expect(bob.tag_list_on(:rotors)).to eq(%w[spinning jumping])
485
- bob.save
486
-
487
- expect(TaggableModel.tagged_with("spinning", on: :rotors).to_a).to eq([bob])
488
- end
489
-
490
- it "should be able to use named scopes to chain tag finds" do
491
- bob = TaggableModel.create(name: "Bob", tag_list: "fitter, happier, more productive", skill_list: "ruby, rails, css")
492
- frank = TaggableModel.create(name: "Frank", tag_list: "weaker, depressed, inefficient", skill_list: "ruby, rails, css")
493
- steve = TaggableModel.create(name: "Steve", tag_list: "fitter, happier, more productive", skill_list: "c++, java, python")
494
-
495
- # Let's only find those productive Rails developers
496
- expect(TaggableModel.tagged_with("rails", on: :skills, order: "taggable_models.name").to_a).to eq([bob, frank])
497
- expect(TaggableModel.tagged_with("happier", on: :tags, order: "taggable_models.name").to_a).to eq([bob, steve])
498
- expect(TaggableModel.tagged_with("rails", on: :skills).tagged_with("happier", on: :tags).to_a).to eq([bob])
499
- expect(TaggableModel.tagged_with("rails").tagged_with("happier", on: :tags).to_a).to eq([bob])
500
- end
501
-
502
- it "should be able to find tagged with only the matching tags" do
503
- TaggableModel.create(name: "Bob", tag_list: "lazy, happier")
504
- TaggableModel.create(name: "Frank", tag_list: "fitter, happier, inefficient")
505
- steve = TaggableModel.create(name: "Steve", tag_list: "fitter, happier")
506
-
507
- expect(TaggableModel.tagged_with("fitter, happier", match_all: true).to_a).to eq([steve])
508
- end
509
-
510
- it "should be able to find tagged with only the matching tags for a context" do
511
- TaggableModel.create(name: "Bob", tag_list: "lazy, happier", skill_list: "ruby, rails, css")
512
- frank = TaggableModel.create(name: "Frank", tag_list: "fitter, happier, inefficient", skill_list: "css")
513
- TaggableModel.create(name: "Steve", tag_list: "fitter, happier", skill_list: "ruby, rails, css")
514
-
515
- expect(TaggableModel.tagged_with("css", on: :skills, match_all: true).to_a).to eq([frank])
516
- end
517
-
518
- it "should be able to find tagged with some excluded tags" do
519
- TaggableModel.create(name: "Bob", tag_list: "happier, lazy")
520
- frank = TaggableModel.create(name: "Frank", tag_list: "happier")
521
- steve = TaggableModel.create(name: "Steve", tag_list: "happier")
522
-
523
- expect(TaggableModel.tagged_with("lazy", exclude: true)).to include(frank, steve)
524
- expect(TaggableModel.tagged_with("lazy", exclude: true).size).to eq(2)
525
- end
526
-
527
- it "should return an empty scope for empty tags" do
528
- ["", " ", nil, []].each do |tag|
529
- expect(TaggableModel.tagged_with(tag)).to be_empty
530
- end
531
- end
532
-
533
- it "should options key not be deleted" do
534
- options = {exclude: true}
535
- TaggableModel.tagged_with("foo", options)
536
- expect(options).to eq({exclude: true})
537
- end
538
-
539
- it "should not delete tags if not updated" do
540
- model = TaggableModel.create(name: "foo", tag_list: "ruby, rails, programming")
541
- model.update(name: "bar")
542
- model.reload
543
- expect(model.tag_list.sort).to eq(%w[ruby rails programming].sort)
544
- end
545
-
546
- context "Duplicates" do
547
- context "should not create duplicate taggings" do
548
- let(:bob) { TaggableModel.create(name: "Bob") }
549
- context "case sensitive" do
550
- it "#add" do
551
- expect(lambda {
552
- bob.tag_list.add "happier"
553
- bob.tag_list.add "happier"
554
- bob.tag_list.add "happier", "rich", "funny"
555
- bob.save
556
- }).to change(MakeTaggable::Tagging, :count).by(3)
557
- end
558
- it "#<<" do
559
- expect(lambda {
560
- bob.tag_list << "social"
561
- bob.tag_list << "social"
562
- bob.tag_list << "social" << "wow"
563
- bob.save
564
- }).to change(MakeTaggable::Tagging, :count).by(2)
565
- end
566
-
567
- it "unicode" do
568
- expect(lambda {
569
- bob.tag_list.add "ПРИВЕТ"
570
- bob.tag_list.add "ПРИВЕТ"
571
- bob.tag_list.add "ПРИВЕТ", "ПРИВЕТ"
572
- bob.save
573
- }).to change(MakeTaggable::Tagging, :count).by(1)
574
- end
575
-
576
- it "#=" do
577
- expect(lambda {
578
- bob.tag_list = ["Happy", "Happy"]
579
- bob.save
580
- }).to change(MakeTaggable::Tagging, :count).by(1)
581
- end
582
- end
583
- context "case insensitive" do
584
- before(:all) { MakeTaggable.force_lowercase = true }
585
- after(:all) { MakeTaggable.force_lowercase = false }
586
-
587
- it "#<<" do
588
- expect(lambda {
589
- bob.tag_list << "Alone"
590
- bob.tag_list << "AloNe"
591
- bob.tag_list << "ALONE" << "In The dark"
592
- bob.save
593
- }).to change(MakeTaggable::Tagging, :count).by(2)
594
- end
595
-
596
- it "#add" do
597
- expect(lambda {
598
- bob.tag_list.add "forever"
599
- bob.tag_list.add "ForEver"
600
- bob.tag_list.add "FOREVER", "ALONE"
601
- bob.save
602
- }).to change(MakeTaggable::Tagging, :count).by(2)
603
- end
604
-
605
- it "unicode" do
606
- expect(lambda {
607
- bob.tag_list.add "ПРИВЕТ"
608
- bob.tag_list.add "привет", "Привет"
609
- bob.save
610
- }).to change(MakeTaggable::Tagging, :count).by(1)
611
- end
612
-
613
- it "#=" do
614
- expect(lambda {
615
- bob.tag_list = ["Happy", "HAPPY"]
616
- bob.save
617
- }).to change(MakeTaggable::Tagging, :count).by(1)
618
- end
619
- end
620
- end
621
-
622
- xit "should not duplicate tags added on different threads", if: supports_concurrency?, skip: "FIXME, Deadlocks in travis" do
623
- # TODO, try with more threads and fix deadlock
624
- thread_count = 4
625
- barrier = Barrier.new thread_count
626
-
627
- expect {
628
- thread_count.times.map { |idx|
629
- Thread.start do
630
- connor = TaggableModel.first_or_create(name: "Connor")
631
- connor.tag_list = "There, can, be, only, one"
632
- barrier.wait
633
- begin
634
- connor.save
635
- rescue MakeTaggable::DuplicateTagError
636
- # second save should succeed
637
- connor.save
638
- end
639
- end
640
- }.map(&:join)
641
- }.to change(MakeTaggable::Tag, :count).by(5)
642
- end
643
- end
644
-
645
- describe "Associations" do
646
- before(:each) do
647
- @taggable = TaggableModel.create(tag_list: "awesome, epic")
648
- end
649
-
650
- it "should not remove tags when creating associated objects" do
651
- @taggable.untaggable_models.create!
652
- @taggable.reload
653
- expect(@taggable.tag_list.size).to eq(2)
654
- end
655
- end
656
-
657
- describe "grouped_column_names_for method" do
658
- it "should return all column names joined for Tag GROUP clause" do
659
- # NOTE: type column supports an STI Tag subclass in the test suite, though
660
- # isn't included by default in the migration generator
661
- expect(@taggable.grouped_column_names_for(MakeTaggable::Tag))
662
- .to eq("#{MakeTaggable.tags_table}.id, #{MakeTaggable.tags_table}.name, #{MakeTaggable.tags_table}.taggings_count, #{MakeTaggable.tags_table}.created_at, #{MakeTaggable.tags_table}.updated_at")
663
- end
664
-
665
- it "should return all column names joined for TaggableModel GROUP clause" do
666
- expect(@taggable.grouped_column_names_for(TaggableModel)).to eq("taggable_models.id, taggable_models.name, taggable_models.type")
667
- end
668
-
669
- it "should return all column names joined for NonStandardIdTaggableModel GROUP clause" do
670
- expect(@taggable.grouped_column_names_for(TaggableModel)).to eq("taggable_models.#{TaggableModel.primary_key}, taggable_models.name, taggable_models.type")
671
- end
672
- end
673
-
674
- describe "NonStandardIdTaggable" do
675
- before(:each) do
676
- @taggable = NonStandardIdTaggableModel.new(name: "Bob Jones")
677
- @taggables = [@taggable, NonStandardIdTaggableModel.new(name: "John Doe")]
678
- end
679
-
680
- it "should have tag types" do
681
- [:tags, :languages, :skills, :needs, :offerings].each do |type|
682
- expect(NonStandardIdTaggableModel.tag_types).to include type
683
- end
684
-
685
- expect(@taggable.tag_types).to eq(NonStandardIdTaggableModel.tag_types)
686
- end
687
-
688
- it "should have tag_counts_on" do
689
- expect(NonStandardIdTaggableModel.tag_counts_on(:tags)).to be_empty
690
-
691
- @taggable.tag_list = %w[awesome epic]
692
- @taggable.save
693
-
694
- expect(NonStandardIdTaggableModel.tag_counts_on(:tags).length).to eq(2)
695
- expect(@taggable.tag_counts_on(:tags).length).to eq(2)
696
- end
697
-
698
- it "should have tags_on" do
699
- expect(NonStandardIdTaggableModel.tags_on(:tags)).to be_empty
700
-
701
- @taggable.tag_list = %w[awesome epic]
702
- @taggable.save
703
-
704
- expect(NonStandardIdTaggableModel.tags_on(:tags).length).to eq(2)
705
- expect(@taggable.tags_on(:tags).length).to eq(2)
706
- end
707
-
708
- it "should be able to create tags" do
709
- @taggable.skill_list = "ruby, rails, css"
710
- expect(@taggable.instance_variable_get("@skill_list").instance_of?(MakeTaggable::TagList)).to be_truthy
711
-
712
- expect(-> {
713
- @taggable.save
714
- }).to change(MakeTaggable::Tag, :count).by(3)
715
-
716
- @taggable.reload
717
- expect(@taggable.skill_list.sort).to eq(%w[ruby rails css].sort)
718
- end
719
-
720
- it "should be able to create tags through the tag list directly" do
721
- @taggable.tag_list_on(:test).add("hello")
722
- expect(@taggable.tag_list_cache_on(:test)).to_not be_empty
723
- expect(@taggable.tag_list_on(:test)).to eq(["hello"])
724
-
725
- @taggable.save
726
- @taggable.save_tags
727
-
728
- @taggable.reload
729
- expect(@taggable.tag_list_on(:test)).to eq(["hello"])
730
- end
731
- end
732
-
733
- describe "Autogenerated methods" do
734
- it "should be overridable" do
735
- expect(TaggableModel.create(tag_list: "woo").tag_list_submethod_called).to be_truthy
736
- end
737
- end
738
-
739
- # See https://github.com/mbleigh/acts-as-taggable-on/pull/457 for details
740
- context "tag_counts and aggreating scopes, compatability with MySQL " do
741
- before(:each) do
742
- TaggableModel.new(name: "Barb Jones").tap { |t| t.tag_list = %w[awesome fun] }.save
743
- TaggableModel.new(name: "John Doe").tap { |t| t.tag_list = %w[cool fun hella] }.save
744
- TaggableModel.new(name: "Jo Doe").tap { |t| t.tag_list = %w[curious young naive sharp] }.save
745
-
746
- TaggableModel.all.each { |t| t.save }
747
- end
748
-
749
- context "Model.limit(x).tag_counts.sum(:tags_count)" do
750
- it "should not break on Mysql" do
751
- expect(TaggableModel.limit(2).tag_counts.sum("tags_count").to_i).to eq(5)
752
- end
753
- end
754
-
755
- context "regression prevention, just making sure these esoteric queries still work" do
756
- context "Model.tag_counts.limit(x)" do
757
- it "should limit the tag objects (not very useful, of course)" do
758
- array_of_tag_counts = TaggableModel.tag_counts.limit(2)
759
- expect(array_of_tag_counts.count).to eq(2)
760
- end
761
- end
762
-
763
- context "Model.tag_counts.sum(:tags_count)" do
764
- it "should limit the total tags used" do
765
- expect(TaggableModel.tag_counts.sum(:tags_count).to_i).to eq(9)
766
- end
767
- end
768
-
769
- context "Model.tag_counts.limit(2).sum(:tags_count)" do
770
- it "limit should have no effect; this is just a sanity check" do
771
- expect(TaggableModel.tag_counts.limit(2).sum(:tags_count).to_i).to eq(9)
772
- end
773
- end
774
- end
775
- end
776
- end
777
-
778
- describe "Taggable model with json columns", if: postgresql_support_json? do
779
- before(:each) do
780
- @taggable = TaggableModelWithJson.new(name: "Bob Jones")
781
- @taggables = [@taggable, TaggableModelWithJson.new(name: "John Doe")]
782
- end
783
-
784
- it "should be able to find by tag with context" do
785
- @taggable.skill_list = "ruby, rails, css"
786
- @taggable.tag_list = "bob, charlie"
787
- @taggable.save
788
-
789
- expect(TaggableModelWithJson.tagged_with("ruby").first).to eq(@taggable)
790
- expect(TaggableModelWithJson.tagged_with("ruby, css").first).to eq(@taggable)
791
- expect(TaggableModelWithJson.tagged_with("bob", on: :skills).first).to_not eq(@taggable)
792
- expect(TaggableModelWithJson.tagged_with("bob", on: :tags).first).to eq(@taggable)
793
- end
794
-
795
- it "should be able to find tagged with any tag" do
796
- bob = TaggableModelWithJson.create(name: "Bob", tag_list: "fitter, happier, more productive", skill_list: "ruby, rails, css")
797
- frank = TaggableModelWithJson.create(name: "Frank", tag_list: "weaker, depressed, inefficient", skill_list: "ruby, rails, css")
798
- steve = TaggableModelWithJson.create(name: "Steve", tag_list: "fitter, happier, more productive", skill_list: "c++, java, ruby")
799
-
800
- expect(TaggableModelWithJson.tagged_with(%w[ruby java], order: "taggable_model_with_jsons.name", any: true).to_a).to eq([bob, frank, steve])
801
- expect(TaggableModelWithJson.tagged_with(%w[c++ fitter], order: "taggable_model_with_jsons.name", any: true).to_a).to eq([bob, steve])
802
- expect(TaggableModelWithJson.tagged_with(%w[depressed css], order: "taggable_model_with_jsons.name", any: true).to_a).to eq([bob, frank])
803
- end
804
- end