acts-as-taggable-on 2.0.0 → 3.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.travis.yml +23 -0
  4. data/Appraisals +20 -0
  5. data/CHANGELOG.md +112 -0
  6. data/CONTRIBUTING.md +44 -0
  7. data/Gemfile +9 -5
  8. data/Guardfile +5 -0
  9. data/{MIT-LICENSE → LICENSE.md} +1 -1
  10. data/README.md +385 -0
  11. data/Rakefile +13 -53
  12. data/UPGRADING.md +13 -0
  13. data/acts-as-taggable-on.gemspec +38 -0
  14. data/{lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb → db/migrate/1_acts_as_taggable_on_migration.rb} +5 -3
  15. data/db/migrate/2_add_missing_unique_indices.rb +19 -0
  16. data/db/migrate/3_add_taggings_counter_cache_to_tags.rb +14 -0
  17. data/gemfiles/activerecord_3.2.gemfile +15 -0
  18. data/gemfiles/activerecord_4.0.gemfile +15 -0
  19. data/gemfiles/activerecord_4.1.gemfile +15 -0
  20. data/gemfiles/activerecord_edge.gemfile +16 -0
  21. data/lib/acts-as-taggable-on.rb +65 -22
  22. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +53 -24
  23. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +120 -42
  24. data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +35 -0
  25. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +309 -124
  26. data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +36 -0
  27. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +96 -72
  28. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +43 -36
  29. data/lib/acts_as_taggable_on/engine.rb +5 -0
  30. data/lib/acts_as_taggable_on/tag.rb +133 -63
  31. data/lib/acts_as_taggable_on/tag_list.rb +162 -81
  32. data/lib/acts_as_taggable_on/taggable.rb +101 -0
  33. data/lib/acts_as_taggable_on/{acts_as_tagger.rb → tagger.rb} +34 -13
  34. data/lib/acts_as_taggable_on/tagging.rb +28 -18
  35. data/lib/acts_as_taggable_on/tags_helper.rb +12 -14
  36. data/lib/acts_as_taggable_on/utils.rb +62 -0
  37. data/lib/acts_as_taggable_on/version.rb +4 -0
  38. data/lib/acts_as_taggable_on.rb +6 -0
  39. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +189 -195
  40. data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +78 -81
  41. data/spec/acts_as_taggable_on/caching_spec.rb +76 -0
  42. data/spec/acts_as_taggable_on/related_spec.rb +89 -0
  43. data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +210 -0
  44. data/spec/acts_as_taggable_on/tag_list_spec.rb +149 -61
  45. data/spec/acts_as_taggable_on/tag_spec.rb +245 -65
  46. data/spec/acts_as_taggable_on/taggable_spec.rb +776 -187
  47. data/spec/acts_as_taggable_on/tagger_spec.rb +119 -70
  48. data/spec/acts_as_taggable_on/tagging_spec.rb +17 -21
  49. data/spec/acts_as_taggable_on/tags_helper_spec.rb +38 -22
  50. data/spec/acts_as_taggable_on/utils_spec.rb +15 -0
  51. data/spec/internal/app/models/altered_inheriting_taggable_model.rb +3 -0
  52. data/spec/internal/app/models/cached_model.rb +3 -0
  53. data/spec/internal/app/models/cached_model_with_array.rb +5 -0
  54. data/spec/internal/app/models/company.rb +15 -0
  55. data/spec/internal/app/models/inheriting_taggable_model.rb +2 -0
  56. data/spec/internal/app/models/market.rb +2 -0
  57. data/spec/internal/app/models/models.rb +90 -0
  58. data/spec/internal/app/models/non_standard_id_taggable_model.rb +8 -0
  59. data/spec/internal/app/models/ordered_taggable_model.rb +4 -0
  60. data/spec/internal/app/models/other_cached_model.rb +3 -0
  61. data/spec/internal/app/models/other_taggable_model.rb +4 -0
  62. data/spec/internal/app/models/student.rb +2 -0
  63. data/spec/internal/app/models/taggable_model.rb +13 -0
  64. data/spec/internal/app/models/untaggable_model.rb +3 -0
  65. data/spec/internal/app/models/user.rb +3 -0
  66. data/spec/internal/config/database.yml.sample +19 -0
  67. data/spec/internal/db/schema.rb +97 -0
  68. data/spec/schema.rb +57 -18
  69. data/spec/spec_helper.rb +12 -47
  70. data/spec/support/array.rb +9 -0
  71. data/spec/support/database.rb +42 -0
  72. data/spec/support/database_cleaner.rb +21 -0
  73. metadata +286 -63
  74. data/CHANGELOG +0 -25
  75. data/README.rdoc +0 -221
  76. data/VERSION +0 -1
  77. data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +0 -7
  78. data/generators/acts_as_taggable_on_migration/templates/migration.rb +0 -29
  79. data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +0 -53
  80. data/lib/acts_as_taggable_on/compatibility/Gemfile +0 -6
  81. data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +0 -17
  82. data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +0 -31
  83. data/rails/init.rb +0 -1
  84. data/spec/bm.rb +0 -52
  85. data/spec/models.rb +0 -30
  86. /data/{spec/spec.opts → .rspec} +0 -0
@@ -0,0 +1,76 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Acts As Taggable On' do
4
+
5
+ describe 'Caching' do
6
+ before(:each) do
7
+ @taggable = CachedModel.new(name: 'Bob Jones')
8
+ @another_taggable = OtherCachedModel.new(name: 'John Smith')
9
+ end
10
+
11
+ it 'should add saving of tag lists and cached tag lists to the instance' do
12
+ expect(@taggable).to respond_to(:save_cached_tag_list)
13
+ expect(@another_taggable).to respond_to(:save_cached_tag_list)
14
+
15
+ expect(@taggable).to respond_to(:save_tags)
16
+ end
17
+
18
+ it 'should add cached tag lists to the instance if cached column is not present' do
19
+ expect(TaggableModel.new(name: 'Art Kram')).to_not respond_to(:save_cached_tag_list)
20
+ end
21
+
22
+ it 'should generate a cached column checker for each tag type' do
23
+ expect(CachedModel).to respond_to(:caching_tag_list?)
24
+ expect(OtherCachedModel).to respond_to(:caching_language_list?)
25
+ end
26
+
27
+ it 'should not have cached tags' do
28
+ expect(@taggable.cached_tag_list).to be_blank
29
+ expect(@another_taggable.cached_language_list).to be_blank
30
+ end
31
+
32
+ it 'should cache tags' do
33
+ @taggable.update_attributes(tag_list: 'awesome, epic')
34
+ expect(@taggable.cached_tag_list).to eq('awesome, epic')
35
+
36
+ @another_taggable.update_attributes(language_list: 'ruby, .net')
37
+ expect(@another_taggable.cached_language_list).to eq('ruby, .net')
38
+ end
39
+
40
+ it 'should keep the cache' do
41
+ @taggable.update_attributes(tag_list: 'awesome, epic')
42
+ @taggable = CachedModel.find(@taggable.id)
43
+ @taggable.save!
44
+ expect(@taggable.cached_tag_list).to eq('awesome, epic')
45
+ end
46
+
47
+ it 'should update the cache' do
48
+ @taggable.update_attributes(tag_list: 'awesome, epic')
49
+ @taggable.update_attributes(tag_list: 'awesome')
50
+ expect(@taggable.cached_tag_list).to eq('awesome')
51
+ end
52
+
53
+ it 'should remove the cache' do
54
+ @taggable.update_attributes(tag_list: 'awesome, epic')
55
+ @taggable.update_attributes(tag_list: '')
56
+ expect(@taggable.cached_tag_list).to be_blank
57
+ end
58
+
59
+ it 'should have a tag list' do
60
+ @taggable.update_attributes(tag_list: 'awesome, epic')
61
+ @taggable = CachedModel.find(@taggable.id)
62
+ expect(@taggable.tag_list.sort).to eq(%w(awesome epic).sort)
63
+ end
64
+
65
+ it 'should keep the tag list' do
66
+ @taggable.update_attributes(tag_list: 'awesome, epic')
67
+ @taggable = CachedModel.find(@taggable.id)
68
+ @taggable.save!
69
+ expect(@taggable.tag_list.sort).to eq(%w(awesome epic).sort)
70
+ end
71
+ end
72
+
73
+ describe 'CachingWithArray' do
74
+ pending '#TODO'
75
+ end
76
+ end
@@ -0,0 +1,89 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Acts As Taggable On' do
4
+
5
+ describe 'Related Objects' do
6
+
7
+ #TODO, shared example
8
+ it 'should find related objects based on tag names on context' do
9
+ taggable1 = TaggableModel.create!(name: 'Taggable 1',tag_list: 'one, two')
10
+ taggable2 = TaggableModel.create!(name: 'Taggable 2',tag_list: 'three, four')
11
+ taggable3 = TaggableModel.create!(name: 'Taggable 3',tag_list: 'one, four')
12
+
13
+ expect(taggable1.find_related_tags).to include(taggable3)
14
+ expect(taggable1.find_related_tags).to_not include(taggable2)
15
+ end
16
+
17
+ it 'finds related tags for ordered taggable on' do
18
+ taggable1 = OrderedTaggableModel.create!(name: 'Taggable 1',colour_list: 'one, two')
19
+ taggable2 = OrderedTaggableModel.create!(name: 'Taggable 2',colour_list: 'three, four')
20
+ taggable3 = OrderedTaggableModel.create!(name: 'Taggable 3',colour_list: 'one, four')
21
+
22
+ expect(taggable1.find_related_colours).to include(taggable3)
23
+ expect(taggable1.find_related_colours).to_not include(taggable2)
24
+ end
25
+
26
+ it 'should find related objects based on tag names on context - non standard id' do
27
+ taggable1 = NonStandardIdTaggableModel.create!(name: 'Taggable 1',tag_list: 'one, two')
28
+ taggable2 = NonStandardIdTaggableModel.create!(name: 'Taggable 2',tag_list: 'three, four')
29
+ taggable3 = NonStandardIdTaggableModel.create!(name: 'Taggable 3',tag_list: 'one, four')
30
+
31
+ expect(taggable1.find_related_tags).to include(taggable3)
32
+ expect(taggable1.find_related_tags).to_not include(taggable2)
33
+ end
34
+
35
+ it 'should find other related objects based on tag names on context' do
36
+ taggable1 = TaggableModel.create!(name: 'Taggable 1',tag_list: 'one, two')
37
+ taggable2 = OtherTaggableModel.create!(name: 'Taggable 2',tag_list: 'three, four')
38
+ taggable3 = OtherTaggableModel.create!(name: 'Taggable 3',tag_list: 'one, four')
39
+
40
+ expect(taggable1.find_related_tags_for(OtherTaggableModel)).to include(taggable3)
41
+ expect(taggable1.find_related_tags_for(OtherTaggableModel)).to_not include(taggable2)
42
+ end
43
+
44
+
45
+ shared_examples "a collection" do
46
+ it do
47
+ taggable1 = described_class.create!(name: 'Taggable 1', tag_list: 'one')
48
+ taggable2 = described_class.create!(name: 'Taggable 2', tag_list: 'one, two')
49
+
50
+ expect(taggable1.find_related_tags).to include(taggable2)
51
+ expect(taggable1.find_related_tags).to_not include(taggable1)
52
+ end
53
+ end
54
+
55
+ # it 'should not include the object itself in the list of related objects' do
56
+ describe TaggableModel do
57
+ it_behaves_like "a collection"
58
+ end
59
+
60
+ # it 'should not include the object itself in the list of related objects - non standard id' do
61
+ describe NonStandardIdTaggableModel do
62
+ it_behaves_like "a collection"
63
+ end
64
+
65
+ context 'Ignored Tags' do
66
+ let(:taggable1) { TaggableModel.create!(name: 'Taggable 1', tag_list: 'one, two, four') }
67
+ let(:taggable2) { TaggableModel.create!(name: 'Taggable 2', tag_list: 'two, three') }
68
+ let(:taggable3) { TaggableModel.create!(name: 'Taggable 3', tag_list: 'one, three') }
69
+
70
+ it 'should not include ignored tags in related search' do
71
+ expect(taggable1.find_related_tags(ignore: 'two')).to_not include(taggable2)
72
+ expect(taggable1.find_related_tags(ignore: 'two')).to include(taggable3)
73
+ end
74
+
75
+ it 'should accept array of ignored tags' do
76
+ taggable4 = TaggableModel.create!(name: 'Taggable 4', tag_list: 'four')
77
+
78
+
79
+ expect(taggable1.find_related_tags(ignore: ['two', 'four'])).to_not include(taggable2)
80
+ expect(taggable1.find_related_tags(ignore: ['two', 'four'])).to_not include(taggable4)
81
+ end
82
+
83
+ it 'should accept symbols as ignored tags' do
84
+ expect(taggable1.find_related_tags(ignore: :two)).to_not include(taggable2)
85
+ end
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,210 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Single Table Inheritance' do
4
+ let(:taggable) { TaggableModel.new(name: 'taggable model') }
5
+
6
+ let(:inheriting_model) { InheritingTaggableModel.new(name: 'Inheriting Taggable Model') }
7
+ let(:altered_inheriting) { AlteredInheritingTaggableModel.new(name: 'Altered Inheriting Model') }
8
+
9
+ 1.upto(4) do |n|
10
+ let(:"inheriting_#{n}") { InheritingTaggableModel.new(name: "Inheriting Model #{n}") }
11
+ end
12
+
13
+ let(:student) { Student.create! }
14
+
15
+ describe 'tag contexts' do
16
+ it 'should pass on to STI-inherited models' do
17
+ expect(inheriting_model).to respond_to(:tag_list, :skill_list, :language_list)
18
+ expect(altered_inheriting).to respond_to(:tag_list, :skill_list, :language_list)
19
+ end
20
+
21
+ it 'should pass on to altered STI models' do
22
+ expect(altered_inheriting).to respond_to(:part_list)
23
+ end
24
+ end
25
+
26
+ context 'matching contexts' do
27
+
28
+ before do
29
+ inheriting_1.offering_list = 'one, two'
30
+ inheriting_1.need_list = 'one, two'
31
+ inheriting_1.save!
32
+
33
+ inheriting_2.need_list = 'one, two'
34
+ inheriting_2.save!
35
+
36
+ inheriting_3.offering_list = 'one, two'
37
+ inheriting_3.save!
38
+
39
+ inheriting_4.tag_list = 'one, two, three, four'
40
+ inheriting_4.save!
41
+
42
+ taggable.need_list = 'one, two'
43
+ taggable.save!
44
+ end
45
+
46
+ it 'should find objects with tags of matching contexts' do
47
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to include(inheriting_2)
48
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(inheriting_3)
49
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(inheriting_4)
50
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(taggable)
51
+
52
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to include(inheriting_2)
53
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to_not include(inheriting_3)
54
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to_not include(inheriting_4)
55
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to include(taggable)
56
+ end
57
+
58
+ it 'should not include the object itself in the list of related objects with tags of matching contexts' do
59
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(inheriting_1)
60
+ expect(inheriting_1.find_matching_contexts_for(InheritingTaggableModel, :offerings, :needs)).to_not include(inheriting_1)
61
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to_not include(inheriting_1)
62
+ end
63
+ end
64
+
65
+ context 'find related tags' do
66
+ before do
67
+ inheriting_1.tag_list = 'one, two'
68
+ inheriting_1.save
69
+
70
+ inheriting_2.tag_list = 'three, four'
71
+ inheriting_2.save
72
+
73
+ inheriting_3.tag_list = 'one, four'
74
+ inheriting_3.save
75
+
76
+ taggable.tag_list = 'one, two, three, four'
77
+ taggable.save
78
+ end
79
+
80
+ it 'should find related objects based on tag names on context' do
81
+ expect(inheriting_1.find_related_tags).to include(inheriting_3)
82
+ expect(inheriting_1.find_related_tags).to_not include(inheriting_2)
83
+ expect(inheriting_1.find_related_tags).to_not include(taggable)
84
+
85
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to include(inheriting_3)
86
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to_not include(inheriting_2)
87
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to include(taggable)
88
+ end
89
+
90
+ it 'should not include the object itself in the list of related objects' do
91
+ expect(inheriting_1.find_related_tags).to_not include(inheriting_1)
92
+ expect(inheriting_1.find_related_tags_for(InheritingTaggableModel)).to_not include(inheriting_1)
93
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to_not include(inheriting_1)
94
+ end
95
+ end
96
+
97
+ describe 'tag list' do
98
+ before do
99
+ @inherited_same = InheritingTaggableModel.new(name: 'inherited same')
100
+ @inherited_different = AlteredInheritingTaggableModel.new(name: 'inherited different')
101
+ end
102
+
103
+ #TODO, shared example
104
+ it 'should be able to save tags for inherited models' do
105
+ inheriting_model.tag_list = 'bob, kelso'
106
+ inheriting_model.save
107
+ expect(InheritingTaggableModel.tagged_with('bob').first).to eq(inheriting_model)
108
+ end
109
+
110
+ it 'should find STI tagged models on the superclass' do
111
+ inheriting_model.tag_list = 'bob, kelso'
112
+ inheriting_model.save
113
+ expect(TaggableModel.tagged_with('bob').first).to eq(inheriting_model)
114
+ end
115
+
116
+ it 'should be able to add on contexts only to some subclasses' do
117
+ altered_inheriting.part_list = 'fork, spoon'
118
+ altered_inheriting.save
119
+ expect(InheritingTaggableModel.tagged_with('fork', on: :parts)).to be_empty
120
+ expect(AlteredInheritingTaggableModel.tagged_with('fork', on: :parts).first).to eq(altered_inheriting)
121
+ end
122
+
123
+ it 'should have different tag_counts_on for inherited models' do
124
+ inheriting_model.tag_list = 'bob, kelso'
125
+ inheriting_model.save!
126
+ altered_inheriting.tag_list = 'fork, spoon'
127
+ altered_inheriting.save!
128
+
129
+ expect(InheritingTaggableModel.tag_counts_on(:tags, order: 'tags.id').map(&:name)).to eq(%w(bob kelso))
130
+ expect(AlteredInheritingTaggableModel.tag_counts_on(:tags, order: 'tags.id').map(&:name)).to eq(%w(fork spoon))
131
+ expect(TaggableModel.tag_counts_on(:tags, order: 'tags.id').map(&:name)).to eq(%w(bob kelso fork spoon))
132
+ end
133
+
134
+ it 'should have different tags_on for inherited models' do
135
+ inheriting_model.tag_list = 'bob, kelso'
136
+ inheriting_model.save!
137
+ altered_inheriting.tag_list = 'fork, spoon'
138
+ altered_inheriting.save!
139
+
140
+ expect(InheritingTaggableModel.tags_on(:tags, order: 'tags.id').map(&:name)).to eq(%w(bob kelso))
141
+ expect(AlteredInheritingTaggableModel.tags_on(:tags, order: 'tags.id').map(&:name)).to eq(%w(fork spoon))
142
+ expect(TaggableModel.tags_on(:tags, order: 'tags.id').map(&:name)).to eq(%w(bob kelso fork spoon))
143
+ end
144
+
145
+ it 'should store same tag without validation conflict' do
146
+ taggable.tag_list = 'one'
147
+ taggable.save!
148
+
149
+ inheriting_model.tag_list = 'one'
150
+ inheriting_model.save!
151
+
152
+ inheriting_model.update_attributes! name: 'foo'
153
+ end
154
+ end
155
+
156
+ describe 'ownership' do
157
+ it 'should have taggings' do
158
+ student.tag(taggable, with: 'ruby,scheme', on: :tags)
159
+ expect(student.owned_taggings.count).to eq(2)
160
+ end
161
+
162
+ it 'should have tags' do
163
+ student.tag(taggable, with: 'ruby,scheme', on: :tags)
164
+ expect(student.owned_tags.count).to eq(2)
165
+ end
166
+
167
+ it 'should return tags for the inheriting tagger' do
168
+ student.tag(taggable, with: 'ruby, scheme', on: :tags)
169
+ expect(taggable.tags_from(student)).to eq(%w(ruby scheme))
170
+ end
171
+
172
+ it 'returns owner tags on the tagger' do
173
+ student.tag(taggable, with: 'ruby, scheme', on: :tags)
174
+ expect(taggable.owner_tags_on(student, :tags).count).to eq(2)
175
+ end
176
+
177
+ it 'should scope objects returned by tagged_with by owners' do
178
+ student.tag(taggable, with: 'ruby, scheme', on: :tags)
179
+ expect(TaggableModel.tagged_with(%w(ruby scheme), owned_by: student).count).to eq(1)
180
+ end
181
+ end
182
+
183
+ describe 'a subclass of Tag' do
184
+ let(:company) { Company.new(:name => 'Dewey, Cheatham & Howe') }
185
+ let(:user) { User.create! }
186
+
187
+ subject { Market.create! :name => 'finance' }
188
+
189
+ its(:type) { should eql 'Market' }
190
+
191
+ it 'sets STI type through string list' do
192
+ company.market_list = 'law, accounting'
193
+ company.save!
194
+ expect(Market.count).to eq(2)
195
+ end
196
+
197
+ it 'does not interfere with a normal Tag context on the same model' do
198
+ company.location_list = 'cambridge'
199
+ company.save!
200
+ expect(ActsAsTaggableOn::Tag.where(name: 'cambridge', type: nil)).to_not be_empty
201
+ end
202
+
203
+ it 'is returned with proper type through ownership' do
204
+ user.tag(company, :with => 'ripoffs, rackets', :on => :markets)
205
+ tags = company.owner_tags_on(user, :markets)
206
+ expect(tags.all? { |tag| tag.is_a? Market }).to be_truthy
207
+ end
208
+ end
209
+ end
210
+
@@ -1,70 +1,158 @@
1
- require File.dirname(__FILE__) + '/../spec_helper'
1
+ # encoding: utf-8
2
+ require 'spec_helper'
2
3
 
3
- describe TagList do
4
- before(:each) do
5
- @tag_list = TagList.new("awesome","radical")
6
- end
7
-
8
- it "should be an array" do
9
- @tag_list.is_a?(Array).should be_true
10
- end
11
-
12
- it "should be able to be add a new tag word" do
13
- @tag_list.add("cool")
14
- @tag_list.include?("cool").should be_true
15
- end
16
-
17
- it "should be able to add delimited lists of words" do
18
- @tag_list.add("cool, wicked", :parse => true)
19
- @tag_list.include?("cool").should be_true
20
- @tag_list.include?("wicked").should be_true
21
- end
22
-
23
- it "should be able to add delimited list of words with quoted delimiters" do
24
- @tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
25
- @tag_list.include?("cool, wicked").should be_true
26
- @tag_list.include?("really cool, really wicked").should be_true
27
- end
28
-
29
- it "should be able to handle other uses of quotation marks correctly" do
30
- @tag_list.add("john's cool car, mary's wicked toy", :parse => true)
31
- @tag_list.include?("john's cool car").should be_true
32
- @tag_list.include?("mary's wicked toy").should be_true
4
+ describe ActsAsTaggableOn::TagList do
5
+ let(:tag_list) { ActsAsTaggableOn::TagList.new('awesome', 'radical') }
6
+ let(:another_tag_list) { ActsAsTaggableOn::TagList.new('awesome','crazy', 'alien') }
7
+
8
+ it { should be_kind_of Array }
9
+
10
+ it '#from should return empty array if empty array is passed' do
11
+ expect(ActsAsTaggableOn::TagList.from([])).to be_empty
33
12
  end
34
-
35
- it "should be able to add an array of words" do
36
- @tag_list.add(["cool", "wicked"], :parse => true)
37
- @tag_list.include?("cool").should be_true
38
- @tag_list.include?("wicked").should be_true
13
+
14
+ describe '#add' do
15
+ it 'should be able to be add a new tag word' do
16
+ tag_list.add('cool')
17
+ expect(tag_list.include?('cool')).to be_truthy
18
+ end
19
+
20
+ it 'should be able to add delimited lists of words' do
21
+ tag_list.add('cool, wicked', parse: true)
22
+ expect(tag_list).to include('cool', 'wicked')
23
+ end
24
+
25
+ it 'should be able to add delimited list of words with quoted delimiters' do
26
+ tag_list.add("'cool, wicked', \"really cool, really wicked\"", parse: true)
27
+ expect(tag_list).to include('cool, wicked', 'really cool, really wicked')
28
+ end
29
+
30
+ it 'should be able to handle other uses of quotation marks correctly' do
31
+ tag_list.add("john's cool car, mary's wicked toy", parse: true)
32
+ expect(tag_list).to include("john's cool car", "mary's wicked toy")
33
+ end
34
+
35
+ it 'should be able to add an array of words' do
36
+ tag_list.add(%w(cool wicked), parse: true)
37
+ expect(tag_list).to include('cool', 'wicked')
38
+ end
39
+
40
+ it 'should quote escape tags with commas in them' do
41
+ tag_list.add('cool', 'rad,bodacious')
42
+ expect(tag_list.to_s).to eq("awesome, radical, cool, \"rad,bodacious\"")
43
+ end
44
+
39
45
  end
40
-
41
- it "should be able to remove words" do
42
- @tag_list.remove("awesome")
43
- @tag_list.include?("awesome").should be_false
46
+
47
+ describe '#remove' do
48
+ it 'should be able to remove words' do
49
+ tag_list.remove('awesome')
50
+ expect(tag_list).to_not include('awesome')
51
+ end
52
+
53
+ it 'should be able to remove delimited lists of words' do
54
+ tag_list.remove('awesome, radical', parse: true)
55
+ expect(tag_list).to be_empty
56
+ end
57
+
58
+ it 'should be able to remove an array of words' do
59
+ tag_list.remove(%w(awesome radical), parse: true)
60
+ expect(tag_list).to be_empty
61
+ end
44
62
  end
45
-
46
- it "should be able to remove delimited lists of words" do
47
- @tag_list.remove("awesome, radical", :parse => true)
48
- @tag_list.should be_empty
63
+
64
+ describe '#+' do
65
+ it 'should not have duplicate tags' do
66
+ new_tag_list = tag_list + another_tag_list
67
+ expect(tag_list).to eq(%w[awesome radical])
68
+ expect(another_tag_list).to eq(%w[awesome crazy alien])
69
+ expect(new_tag_list).to eq(%w[awesome radical crazy alien])
70
+ end
71
+
72
+ it 'should have class : ActsAsTaggableOn::TagList' do
73
+ new_tag_list = tag_list + another_tag_list
74
+ expect(new_tag_list.class).to eq(ActsAsTaggableOn::TagList)
75
+ end
49
76
  end
50
-
51
- it "should be able to remove an array of words" do
52
- @tag_list.remove(["awesome", "radical"], :parse => true)
53
- @tag_list.should be_empty
77
+
78
+ describe '#concat' do
79
+ it 'should not have duplicate tags' do
80
+ expect(tag_list.concat(another_tag_list)).to eq(%w[awesome radical crazy alien])
81
+ end
82
+
83
+ it 'should have class : ActsAsTaggableOn::TagList' do
84
+ new_tag_list = tag_list.concat(another_tag_list)
85
+ expect(new_tag_list.class).to eq(ActsAsTaggableOn::TagList)
86
+ end
54
87
  end
55
-
56
- it "should give a delimited list of words when converted to string" do
57
- @tag_list.to_s.should == "awesome, radical"
88
+
89
+ describe '#to_s' do
90
+ it 'should give a delimited list of words when converted to string' do
91
+ expect(tag_list.to_s).to eq('awesome, radical')
92
+ end
93
+
94
+ it 'should be able to call to_s on a frozen tag list' do
95
+ tag_list.freeze
96
+ expect(-> { tag_list.add('cool', 'rad,bodacious') }).to raise_error
97
+ expect(-> { tag_list.to_s }).to_not raise_error
98
+ end
58
99
  end
59
-
60
- it "should quote escape tags with commas in them" do
61
- @tag_list.add("cool","rad,bodacious")
62
- @tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
100
+
101
+ describe 'cleaning' do
102
+ it 'should parameterize if force_parameterize is set to true' do
103
+ ActsAsTaggableOn.force_parameterize = true
104
+ tag_list = ActsAsTaggableOn::TagList.new('awesome()', 'radical)(cc')
105
+
106
+ expect(tag_list.to_s).to eq('awesome, radical-cc')
107
+ ActsAsTaggableOn.force_parameterize = false
108
+ end
109
+
110
+ it 'should lowercase if force_lowercase is set to true' do
111
+ ActsAsTaggableOn.force_lowercase = true
112
+
113
+ tag_list = ActsAsTaggableOn::TagList.new('aweSomE', 'RaDicaL', 'Entrée')
114
+ expect(tag_list.to_s).to eq('awesome, radical, entrée')
115
+
116
+ ActsAsTaggableOn.force_lowercase = false
117
+ end
118
+
63
119
  end
64
-
65
- it "should be able to call to_s on a frozen tag list" do
66
- @tag_list.freeze
67
- lambda { @tag_list.add("cool","rad,bodacious") }.should raise_error
68
- lambda { @tag_list.to_s }.should_not raise_error
120
+
121
+ describe 'Multiple Delimiter' do
122
+ before do
123
+ @old_delimiter = ActsAsTaggableOn.delimiter
124
+ end
125
+
126
+ after do
127
+ ActsAsTaggableOn.delimiter = @old_delimiter
128
+ end
129
+
130
+ it 'should separate tags by delimiters' do
131
+ ActsAsTaggableOn.delimiter = [',', ' ', '\|']
132
+ tag_list = ActsAsTaggableOn::TagList.from 'cool, data|I have'
133
+ expect(tag_list.to_s).to eq('cool, data, I, have')
134
+ end
135
+
136
+ it 'should escape quote' do
137
+ ActsAsTaggableOn.delimiter = [',', ' ', '\|']
138
+ tag_list = ActsAsTaggableOn::TagList.from "'I have'|cool, data"
139
+ expect(tag_list.to_s).to eq('"I have", cool, data')
140
+
141
+ tag_list = ActsAsTaggableOn::TagList.from '"I, have"|cool, data'
142
+ expect(tag_list.to_s).to eq('"I, have", cool, data')
143
+ end
144
+
145
+ it 'should work for utf8 delimiter and long delimiter' do
146
+ ActsAsTaggableOn.delimiter = [',', '的', '可能是']
147
+ tag_list = ActsAsTaggableOn::TagList.from '我的东西可能是不见了,还好有备份'
148
+ expect(tag_list.to_s).to eq('我, 东西, 不见了, 还好有备份')
149
+ end
150
+
151
+ it 'should work for multiple quoted tags' do
152
+ ActsAsTaggableOn.delimiter = [',']
153
+ tag_list = ActsAsTaggableOn::TagList.from '"Ruby Monsters","eat Katzenzungen"'
154
+ expect(tag_list.to_s).to eq('Ruby Monsters, eat Katzenzungen')
155
+ end
69
156
  end
70
- end
157
+
158
+ end