make_taggable 0.6.3

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 (156) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ci.yml +47 -0
  3. data/.gitignore +13 -0
  4. data/.rspec +3 -0
  5. data/.standard.yml +18 -0
  6. data/.standard_todo.yml +5 -0
  7. data/.travis.yml +36 -0
  8. data/Appraisals +11 -0
  9. data/CHANGELOG.md +0 -0
  10. data/CODE_OF_CONDUCT.md +74 -0
  11. data/CONTRIBUTING.md +57 -0
  12. data/Gemfile +16 -0
  13. data/LICENSE.md +20 -0
  14. data/LICENSE.txt +21 -0
  15. data/README.md +478 -0
  16. data/Rakefile +7 -0
  17. data/bin/console +14 -0
  18. data/bin/setup +8 -0
  19. data/db/migrate/1_create_make_taggable_tags.rb +10 -0
  20. data/db/migrate/2_create_make_taggable_taggings.rb +12 -0
  21. data/db/migrate/3_add_index_to_tags.rb +5 -0
  22. data/db/migrate/4_add_index_to_taggings.rb +12 -0
  23. data/gemfiles/rails_5.gemfile +9 -0
  24. data/gemfiles/rails_6.gemfile +9 -0
  25. data/gemfiles/rails_master.gemfile +9 -0
  26. data/lib/make_taggable.rb +134 -0
  27. data/lib/make_taggable/default_parser.rb +75 -0
  28. data/lib/make_taggable/engine.rb +4 -0
  29. data/lib/make_taggable/generic_parser.rb +19 -0
  30. data/lib/make_taggable/tag.rb +131 -0
  31. data/lib/make_taggable/tag_list.rb +102 -0
  32. data/lib/make_taggable/taggable.rb +100 -0
  33. data/lib/make_taggable/taggable/cache.rb +90 -0
  34. data/lib/make_taggable/taggable/collection.rb +183 -0
  35. data/lib/make_taggable/taggable/core.rb +323 -0
  36. data/lib/make_taggable/taggable/ownership.rb +137 -0
  37. data/lib/make_taggable/taggable/related.rb +71 -0
  38. data/lib/make_taggable/taggable/tag_list_type.rb +4 -0
  39. data/lib/make_taggable/taggable/tagged_with_query.rb +16 -0
  40. data/lib/make_taggable/taggable/tagged_with_query/all_tags_query.rb +111 -0
  41. data/lib/make_taggable/taggable/tagged_with_query/any_tags_query.rb +68 -0
  42. data/lib/make_taggable/taggable/tagged_with_query/exclude_tags_query.rb +81 -0
  43. data/lib/make_taggable/taggable/tagged_with_query/query_base.rb +61 -0
  44. data/lib/make_taggable/tagger.rb +89 -0
  45. data/lib/make_taggable/tagging.rb +32 -0
  46. data/lib/make_taggable/tags_helper.rb +15 -0
  47. data/lib/make_taggable/utils.rb +34 -0
  48. data/lib/make_taggable/version.rb +4 -0
  49. data/lib/tasks/tags_collate_utf8.rake +17 -0
  50. data/make_taggable.gemspec +26 -0
  51. data/spec/dummy/README.md +24 -0
  52. data/spec/dummy/Rakefile +6 -0
  53. data/spec/dummy/app/assets/config/manifest.js +2 -0
  54. data/spec/dummy/app/channels/application_cable/channel.rb +4 -0
  55. data/spec/dummy/app/channels/application_cable/connection.rb +4 -0
  56. data/spec/dummy/app/controllers/application_controller.rb +2 -0
  57. data/spec/dummy/app/controllers/concerns/.keep +0 -0
  58. data/spec/dummy/app/jobs/application_job.rb +7 -0
  59. data/spec/dummy/app/mailers/application_mailer.rb +4 -0
  60. data/spec/dummy/app/models/altered_inheriting_taggable_model.rb +5 -0
  61. data/spec/dummy/app/models/application_record.rb +3 -0
  62. data/spec/dummy/app/models/cached_model.rb +3 -0
  63. data/spec/dummy/app/models/cached_model_with_array.rb +11 -0
  64. data/spec/dummy/app/models/columns_override_model.rb +5 -0
  65. data/spec/dummy/app/models/company.rb +15 -0
  66. data/spec/dummy/app/models/concerns/.keep +0 -0
  67. data/spec/dummy/app/models/inheriting_taggable_model.rb +4 -0
  68. data/spec/dummy/app/models/market.rb +2 -0
  69. data/spec/dummy/app/models/non_standard_id_taggable_model.rb +8 -0
  70. data/spec/dummy/app/models/ordered_taggable_model.rb +4 -0
  71. data/spec/dummy/app/models/other_cached_model.rb +3 -0
  72. data/spec/dummy/app/models/other_taggable_model.rb +4 -0
  73. data/spec/dummy/app/models/student.rb +4 -0
  74. data/spec/dummy/app/models/taggable_model.rb +14 -0
  75. data/spec/dummy/app/models/untaggable_model.rb +3 -0
  76. data/spec/dummy/app/models/user.rb +3 -0
  77. data/spec/dummy/app/views/layouts/mailer.html.erb +13 -0
  78. data/spec/dummy/app/views/layouts/mailer.text.erb +1 -0
  79. data/spec/dummy/bin/rails +4 -0
  80. data/spec/dummy/bin/rake +4 -0
  81. data/spec/dummy/bin/setup +33 -0
  82. data/spec/dummy/config.ru +5 -0
  83. data/spec/dummy/config/application.rb +19 -0
  84. data/spec/dummy/config/boot.rb +5 -0
  85. data/spec/dummy/config/cable.yml +10 -0
  86. data/spec/dummy/config/credentials.yml.enc +1 -0
  87. data/spec/dummy/config/database.yml +25 -0
  88. data/spec/dummy/config/environment.rb +5 -0
  89. data/spec/dummy/config/environments/development.rb +52 -0
  90. data/spec/dummy/config/environments/production.rb +105 -0
  91. data/spec/dummy/config/environments/test.rb +49 -0
  92. data/spec/dummy/config/initializers/application_controller_renderer.rb +8 -0
  93. data/spec/dummy/config/initializers/backtrace_silencers.rb +7 -0
  94. data/spec/dummy/config/initializers/cors.rb +16 -0
  95. data/spec/dummy/config/initializers/filter_parameter_logging.rb +4 -0
  96. data/spec/dummy/config/initializers/inflections.rb +16 -0
  97. data/spec/dummy/config/initializers/mime_types.rb +4 -0
  98. data/spec/dummy/config/initializers/wrap_parameters.rb +14 -0
  99. data/spec/dummy/config/locales/en.yml +33 -0
  100. data/spec/dummy/config/master.key +1 -0
  101. data/spec/dummy/config/puma.rb +38 -0
  102. data/spec/dummy/config/routes.rb +3 -0
  103. data/spec/dummy/config/spring.rb +6 -0
  104. data/spec/dummy/config/storage.yml +34 -0
  105. data/spec/dummy/db/migrate/20201119220853_create_taggable_models.rb +8 -0
  106. data/spec/dummy/db/migrate/20201119221037_create_columns_override_models.rb +9 -0
  107. data/spec/dummy/db/migrate/20201119221121_create_non_standard_id_taggable_models.rb +8 -0
  108. data/spec/dummy/db/migrate/20201119221228_create_untaggable_models.rb +8 -0
  109. data/spec/dummy/db/migrate/20201119221247_create_cached_models.rb +9 -0
  110. data/spec/dummy/db/migrate/20201119221314_create_other_cached_models.rb +11 -0
  111. data/spec/dummy/db/migrate/20201119221343_create_companies.rb +7 -0
  112. data/spec/dummy/db/migrate/20201119221416_create_users.rb +7 -0
  113. data/spec/dummy/db/migrate/20201119221434_create_other_taggable_models.rb +8 -0
  114. data/spec/dummy/db/migrate/20201119221507_create_ordered_taggable_models.rb +8 -0
  115. data/spec/dummy/db/migrate/20201119221530_create_cache_methods_injected_models.rb +7 -0
  116. data/spec/dummy/db/migrate/20201119221629_create_other_cached_with_array_models.rb +11 -0
  117. data/spec/dummy/db/migrate/20201119221746_create_taggable_model_with_jsons.rb +9 -0
  118. data/spec/dummy/db/migrate/20201119222429_create_make_taggable_tags.make_taggable_engine.rb +11 -0
  119. data/spec/dummy/db/migrate/20201119222430_create_make_taggable_taggings.make_taggable_engine.rb +13 -0
  120. data/spec/dummy/db/migrate/20201119222431_add_index_to_tags.make_taggable_engine.rb +6 -0
  121. data/spec/dummy/db/migrate/20201119222432_add_index_to_taggings.make_taggable_engine.rb +13 -0
  122. data/spec/dummy/db/schema.rb +117 -0
  123. data/spec/dummy/db/seeds.rb +7 -0
  124. data/spec/dummy/lib/tasks/.keep +0 -0
  125. data/spec/dummy/log/.keep +0 -0
  126. data/spec/dummy/public/robots.txt +1 -0
  127. data/spec/dummy/storage/.keep +0 -0
  128. data/spec/dummy/test/channels/application_cable/connection_test.rb +11 -0
  129. data/spec/dummy/test/controllers/.keep +0 -0
  130. data/spec/dummy/test/fixtures/.keep +0 -0
  131. data/spec/dummy/test/fixtures/files/.keep +0 -0
  132. data/spec/dummy/test/integration/.keep +0 -0
  133. data/spec/dummy/test/mailers/.keep +0 -0
  134. data/spec/dummy/test/models/.keep +0 -0
  135. data/spec/dummy/test/test_helper.rb +13 -0
  136. data/spec/dummy/vendor/.keep +0 -0
  137. data/spec/make_taggable/acts_as_tagger_spec.rb +112 -0
  138. data/spec/make_taggable/caching_spec.rb +123 -0
  139. data/spec/make_taggable/default_parser_spec.rb +45 -0
  140. data/spec/make_taggable/dirty_spec.rb +140 -0
  141. data/spec/make_taggable/generic_parser_spec.rb +13 -0
  142. data/spec/make_taggable/make_taggable_spec.rb +260 -0
  143. data/spec/make_taggable/related_spec.rb +93 -0
  144. data/spec/make_taggable/single_table_inheritance_spec.rb +220 -0
  145. data/spec/make_taggable/tag_list_spec.rb +169 -0
  146. data/spec/make_taggable/tag_spec.rb +297 -0
  147. data/spec/make_taggable/taggable_spec.rb +804 -0
  148. data/spec/make_taggable/tagger_spec.rb +149 -0
  149. data/spec/make_taggable/tagging_spec.rb +115 -0
  150. data/spec/make_taggable/tags_helper_spec.rb +43 -0
  151. data/spec/make_taggable/utils_spec.rb +22 -0
  152. data/spec/make_taggable_spec.rb +5 -0
  153. data/spec/spec_helper.rb +18 -0
  154. data/spec/support/array.rb +9 -0
  155. data/spec/support/helpers.rb +31 -0
  156. metadata +391 -0
@@ -0,0 +1,93 @@
1
+ require "spec_helper"
2
+
3
+ describe "Acts As Taggable On" do
4
+ describe "Related Objects" do
5
+ # TODO, shared example
6
+ it "should find related objects based on tag names on context" do
7
+ taggable1 = TaggableModel.create!(name: "Taggable 1", tag_list: "one, two")
8
+ taggable2 = TaggableModel.create!(name: "Taggable 2", tag_list: "three, four")
9
+ taggable3 = TaggableModel.create!(name: "Taggable 3", tag_list: "one, four")
10
+
11
+ expect(taggable1.find_related_tags).to include(taggable3)
12
+ expect(taggable1.find_related_tags).to_not include(taggable2)
13
+ end
14
+
15
+ it "finds related tags for ordered taggable on" do
16
+ taggable1 = OrderedTaggableModel.create!(name: "Taggable 1", colour_list: "one, two")
17
+ taggable2 = OrderedTaggableModel.create!(name: "Taggable 2", colour_list: "three, four")
18
+ taggable3 = OrderedTaggableModel.create!(name: "Taggable 3", colour_list: "one, four")
19
+
20
+ expect(taggable1.find_related_colours).to include(taggable3)
21
+ expect(taggable1.find_related_colours).to_not include(taggable2)
22
+ end
23
+
24
+ it "should find related objects based on tag names on context - non standard id" do
25
+ taggable1 = NonStandardIdTaggableModel.create!(name: "Taggable 1", tag_list: "one, two")
26
+ taggable2 = NonStandardIdTaggableModel.create!(name: "Taggable 2", tag_list: "three, four")
27
+ taggable3 = NonStandardIdTaggableModel.create!(name: "Taggable 3", tag_list: "one, four")
28
+
29
+ expect(taggable1.find_related_tags).to include(taggable3)
30
+ expect(taggable1.find_related_tags).to_not include(taggable2)
31
+ end
32
+
33
+ it "should find other related objects based on tag names on context" do
34
+ taggable1 = TaggableModel.create!(name: "Taggable 1", tag_list: "one, two")
35
+ taggable2 = OtherTaggableModel.create!(name: "Taggable 2", tag_list: "three, four")
36
+ taggable3 = OtherTaggableModel.create!(name: "Taggable 3", tag_list: "one, four")
37
+
38
+ expect(taggable1.find_related_tags_for(OtherTaggableModel)).to include(taggable3)
39
+ expect(taggable1.find_related_tags_for(OtherTaggableModel)).to_not include(taggable2)
40
+ end
41
+
42
+ it "should find other related objects based on tags only from particular context" do
43
+ taggable1 = TaggableModel.create!(name: "Taggable 1", tag_list: "one, two")
44
+ taggable2 = TaggableModel.create!(name: "Taggable 2", tag_list: "three, four", skill_list: "one, two")
45
+ taggable3 = TaggableModel.create!(name: "Taggable 3", tag_list: "one, four")
46
+
47
+ expect(taggable1.find_related_tags).to include(taggable3)
48
+ expect(taggable1.find_related_tags).to_not include(taggable2)
49
+ end
50
+
51
+ shared_examples "a collection" do
52
+ it do
53
+ taggable1 = described_class.create!(name: "Taggable 1", tag_list: "one")
54
+ taggable2 = described_class.create!(name: "Taggable 2", tag_list: "one, two")
55
+
56
+ expect(taggable1.find_related_tags).to include(taggable2)
57
+ expect(taggable1.find_related_tags).to_not include(taggable1)
58
+ end
59
+ end
60
+
61
+ # it 'should not include the object itself in the list of related objects' do
62
+ describe TaggableModel do
63
+ it_behaves_like "a collection"
64
+ end
65
+
66
+ # it 'should not include the object itself in the list of related objects - non standard id' do
67
+ describe NonStandardIdTaggableModel do
68
+ it_behaves_like "a collection"
69
+ end
70
+
71
+ context "Ignored Tags" do
72
+ let(:taggable1) { TaggableModel.create!(name: "Taggable 1", tag_list: "one, two, four") }
73
+ let(:taggable2) { TaggableModel.create!(name: "Taggable 2", tag_list: "two, three") }
74
+ let(:taggable3) { TaggableModel.create!(name: "Taggable 3", tag_list: "one, three") }
75
+
76
+ it "should not include ignored tags in related search" do
77
+ expect(taggable1.find_related_tags(ignore: "two")).to_not include(taggable2)
78
+ expect(taggable1.find_related_tags(ignore: "two")).to include(taggable3)
79
+ end
80
+
81
+ it "should accept array of ignored tags" do
82
+ taggable4 = TaggableModel.create!(name: "Taggable 4", tag_list: "four")
83
+
84
+ expect(taggable1.find_related_tags(ignore: ["two", "four"])).to_not include(taggable2)
85
+ expect(taggable1.find_related_tags(ignore: ["two", "four"])).to_not include(taggable4)
86
+ end
87
+
88
+ it "should accept symbols as ignored tags" do
89
+ expect(taggable1.find_related_tags(ignore: :two)).to_not include(taggable2)
90
+ end
91
+ end
92
+ end
93
+ end
@@ -0,0 +1,220 @@
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
+ before do
28
+ inheriting_1.offering_list = "one, two"
29
+ inheriting_1.need_list = "one, two"
30
+ inheriting_1.save!
31
+
32
+ inheriting_2.need_list = "one, two"
33
+ inheriting_2.save!
34
+
35
+ inheriting_3.offering_list = "one, two"
36
+ inheriting_3.save!
37
+
38
+ inheriting_4.tag_list = "one, two, three, four"
39
+ inheriting_4.save!
40
+
41
+ taggable.need_list = "one, two"
42
+ taggable.save!
43
+ end
44
+
45
+ it "should find objects with tags of matching contexts" do
46
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to include(inheriting_2)
47
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(inheriting_3)
48
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(inheriting_4)
49
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(taggable)
50
+
51
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to include(inheriting_2)
52
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to_not include(inheriting_3)
53
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to_not include(inheriting_4)
54
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to include(taggable)
55
+ end
56
+
57
+ it "should not include the object itself in the list of related objects with tags of matching contexts" do
58
+ expect(inheriting_1.find_matching_contexts(:offerings, :needs)).to_not include(inheriting_1)
59
+ expect(inheriting_1.find_matching_contexts_for(InheritingTaggableModel, :offerings, :needs)).to_not include(inheriting_1)
60
+ expect(inheriting_1.find_matching_contexts_for(TaggableModel, :offerings, :needs)).to_not include(inheriting_1)
61
+ end
62
+ end
63
+
64
+ context "find related tags" do
65
+ before do
66
+ inheriting_1.tag_list = "one, two"
67
+ inheriting_1.save
68
+
69
+ inheriting_2.tag_list = "three, four"
70
+ inheriting_2.save
71
+
72
+ inheriting_3.tag_list = "one, four"
73
+ inheriting_3.save
74
+
75
+ taggable.tag_list = "one, two, three, four"
76
+ taggable.save
77
+ end
78
+
79
+ it "should find related objects based on tag names on context" do
80
+ expect(inheriting_1.find_related_tags).to include(inheriting_3)
81
+ expect(inheriting_1.find_related_tags).to_not include(inheriting_2)
82
+ expect(inheriting_1.find_related_tags).to_not include(taggable)
83
+
84
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to include(inheriting_3)
85
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to_not include(inheriting_2)
86
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to include(taggable)
87
+ end
88
+
89
+ it "should not include the object itself in the list of related objects" do
90
+ expect(inheriting_1.find_related_tags).to_not include(inheriting_1)
91
+ expect(inheriting_1.find_related_tags_for(InheritingTaggableModel)).to_not include(inheriting_1)
92
+ expect(inheriting_1.find_related_tags_for(TaggableModel)).to_not include(inheriting_1)
93
+ end
94
+ end
95
+
96
+ describe "tag list" do
97
+ before do
98
+ @inherited_same = InheritingTaggableModel.new(name: "inherited same")
99
+ @inherited_different = AlteredInheritingTaggableModel.new(name: "inherited different")
100
+ end
101
+
102
+ # TODO, shared example
103
+ it "should be able to save tags for inherited models" do
104
+ inheriting_model.tag_list = "bob, kelso"
105
+ inheriting_model.save
106
+ expect(InheritingTaggableModel.tagged_with("bob").first).to eq(inheriting_model)
107
+ end
108
+
109
+ it "should find STI tagged models on the superclass" do
110
+ inheriting_model.tag_list = "bob, kelso"
111
+ inheriting_model.save
112
+ expect(TaggableModel.tagged_with("bob").first).to eq(inheriting_model)
113
+ end
114
+
115
+ it "should be able to add on contexts only to some subclasses" do
116
+ altered_inheriting.part_list = "fork, spoon"
117
+ altered_inheriting.save
118
+ expect(InheritingTaggableModel.tagged_with("fork", on: :parts)).to be_empty
119
+ expect(AlteredInheritingTaggableModel.tagged_with("fork", on: :parts).first).to eq(altered_inheriting)
120
+ end
121
+
122
+ it "should have different tag_counts_on for inherited models" do
123
+ inheriting_model.tag_list = "bob, kelso"
124
+ inheriting_model.save!
125
+ altered_inheriting.tag_list = "fork, spoon"
126
+ altered_inheriting.save!
127
+
128
+ expect(InheritingTaggableModel.tag_counts_on(:tags, order: "#{MakeTaggable.tags_table}.id").map(&:name)).to eq(%w[bob kelso])
129
+ expect(AlteredInheritingTaggableModel.tag_counts_on(:tags, order: "#{MakeTaggable.tags_table}.id").map(&:name)).to eq(%w[fork spoon])
130
+ expect(TaggableModel.tag_counts_on(:tags, order: "#{MakeTaggable.tags_table}.id").map(&:name)).to eq(%w[bob kelso fork spoon])
131
+ end
132
+
133
+ it "should have different tags_on for inherited models" do
134
+ inheriting_model.tag_list = "bob, kelso"
135
+ inheriting_model.save!
136
+ altered_inheriting.tag_list = "fork, spoon"
137
+ altered_inheriting.save!
138
+
139
+ expect(InheritingTaggableModel.tags_on(:tags, order: "#{MakeTaggable.tags_table}.id").map(&:name)).to eq(%w[bob kelso])
140
+ expect(AlteredInheritingTaggableModel.tags_on(:tags, order: "#{MakeTaggable.tags_table}.id").map(&:name)).to eq(%w[fork spoon])
141
+ expect(TaggableModel.tags_on(:tags, order: "#{MakeTaggable.tags_table}.id").map(&:name)).to eq(%w[bob kelso fork spoon])
142
+ end
143
+
144
+ it "should store same tag without validation conflict" do
145
+ taggable.tag_list = "one"
146
+ taggable.save!
147
+
148
+ inheriting_model.tag_list = "one"
149
+ inheriting_model.save!
150
+
151
+ inheriting_model.update! name: "foo"
152
+ end
153
+
154
+ it "should only join with taggable table to check type for inherited models" do
155
+ expect(TaggableModel.tag_counts_on(:tags).to_sql).to_not match(/INNER JOIN taggable_models ON/)
156
+ expect(InheritingTaggableModel.tag_counts_on(:tags).to_sql).to match(/INNER JOIN taggable_models ON/)
157
+ end
158
+ end
159
+
160
+ describe "ownership" do
161
+ it "should have taggings" do
162
+ student.tag(taggable, with: "ruby,scheme", on: :tags)
163
+ expect(student.owned_taggings.count).to eq(2)
164
+ end
165
+
166
+ it "should have tags" do
167
+ student.tag(taggable, with: "ruby,scheme", on: :tags)
168
+ expect(student.owned_tags.count).to eq(2)
169
+ end
170
+
171
+ it "should return tags for the inheriting tagger" do
172
+ student.tag(taggable, with: "ruby, scheme", on: :tags)
173
+ expect(taggable.tags_from(student)).to eq(%w[ruby scheme])
174
+ end
175
+
176
+ it "returns all owner tags on the taggable" do
177
+ student.tag(taggable, with: "ruby, scheme", on: :tags)
178
+ student.tag(taggable, with: "skill_one", on: :skills)
179
+ student.tag(taggable, with: "english, spanish", on: :language)
180
+ expect(taggable.owner_tags(student).count).to eq(5)
181
+ expect(taggable.owner_tags(student).sort == %w[english ruby scheme skill_one spanish])
182
+ end
183
+
184
+ it "returns owner tags on the tagger" do
185
+ student.tag(taggable, with: "ruby, scheme", on: :tags)
186
+ expect(taggable.owner_tags_on(student, :tags).count).to eq(2)
187
+ end
188
+
189
+ it "returns owner tags on the taggable for an array of contexts" do
190
+ student.tag(taggable, with: "ruby, scheme", on: :tags)
191
+ student.tag(taggable, with: "skill_one, skill_two", on: :skills)
192
+ expect(taggable.owner_tags_on(student, [:tags, :skills]).count).to eq(4)
193
+ expect(taggable.owner_tags_on(student, [:tags, :skills]).sort == %w[ruby scheme skill_one skill_two])
194
+ end
195
+
196
+ it "should scope objects returned by tagged_with by owners" do
197
+ student.tag(taggable, with: "ruby, scheme", on: :tags)
198
+ expect(TaggableModel.tagged_with(%w[ruby scheme], owned_by: student).count).to eq(1)
199
+ end
200
+ end
201
+
202
+ describe "a subclass of Tag" do
203
+ let(:company) { Company.new(name: "Dewey, Cheatham & Howe") }
204
+ let(:user) { User.create! }
205
+
206
+ subject { Market.create! name: "finance" }
207
+
208
+ it "sets STI type through string list" do
209
+ company.market_list = "law, accounting"
210
+ company.save!
211
+ expect(Market.count).to eq(2)
212
+ end
213
+
214
+ it "does not interfere with a normal Tag context on the same model" do
215
+ company.location_list = "cambridge"
216
+ company.save!
217
+ expect(MakeTaggable::Tag.where(name: "cambridge")).to_not be_empty
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,169 @@
1
+ require "spec_helper"
2
+
3
+ describe MakeTaggable::TagList do
4
+ let(:tag_list) { MakeTaggable::TagList.new("awesome", "radical") }
5
+ let(:another_tag_list) { MakeTaggable::TagList.new("awesome", "crazy", "alien") }
6
+
7
+ it { should be_kind_of Array }
8
+
9
+ describe "#add" do
10
+ it "should be able to be add a new tag word" do
11
+ tag_list.add("cool")
12
+ expect(tag_list.include?("cool")).to be_truthy
13
+ end
14
+
15
+ it "should be able to add delimited lists of words" do
16
+ tag_list.add("cool, wicked", parse: true)
17
+ expect(tag_list).to include("cool", "wicked")
18
+ end
19
+
20
+ it "should be able to add delimited list of words with quoted delimiters" do
21
+ tag_list.add("'cool, wicked', \"really cool, really wicked\"", parse: true)
22
+ expect(tag_list).to include("cool, wicked", "really cool, really wicked")
23
+ end
24
+
25
+ it "should be able to handle other uses of quotation marks correctly" do
26
+ tag_list.add("john's cool car, mary's wicked toy", parse: true)
27
+ expect(tag_list).to include("john's cool car", "mary's wicked toy")
28
+ end
29
+
30
+ it "should be able to add an array of words" do
31
+ tag_list.add(%w[cool wicked], parse: true)
32
+ expect(tag_list).to include("cool", "wicked")
33
+ end
34
+
35
+ it "should quote escape tags with commas in them" do
36
+ tag_list.add("cool", "rad,bodacious")
37
+ expect(tag_list.to_s).to eq("awesome, radical, cool, \"rad,bodacious\"")
38
+ end
39
+ end
40
+
41
+ describe "#remove" do
42
+ it "should be able to remove words" do
43
+ tag_list.remove("awesome")
44
+ expect(tag_list).to_not include("awesome")
45
+ end
46
+
47
+ it "should be able to remove delimited lists of words" do
48
+ tag_list.remove("awesome, radical", parse: true)
49
+ expect(tag_list).to be_empty
50
+ end
51
+
52
+ it "should be able to remove an array of words" do
53
+ tag_list.remove(%w[awesome radical], parse: true)
54
+ expect(tag_list).to be_empty
55
+ end
56
+ end
57
+
58
+ describe "#+" do
59
+ it "should not have duplicate tags" do
60
+ new_tag_list = tag_list + another_tag_list
61
+ expect(tag_list).to eq(%w[awesome radical])
62
+ expect(another_tag_list).to eq(%w[awesome crazy alien])
63
+ expect(new_tag_list).to eq(%w[awesome radical crazy alien])
64
+ end
65
+
66
+ it "should have class : MakeTaggable::TagList" do
67
+ new_tag_list = tag_list + another_tag_list
68
+ expect(new_tag_list.class).to eq(MakeTaggable::TagList)
69
+ end
70
+ end
71
+
72
+ describe "#concat" do
73
+ it "should not have duplicate tags" do
74
+ expect(tag_list.concat(another_tag_list)).to eq(%w[awesome radical crazy alien])
75
+ end
76
+
77
+ it "should have class : MakeTaggable::TagList" do
78
+ new_tag_list = tag_list.concat(another_tag_list)
79
+ expect(new_tag_list.class).to eq(MakeTaggable::TagList)
80
+ end
81
+
82
+ context "without duplicates" do
83
+ let(:arr) { ["crazy", "alien"] }
84
+ let(:another_tag_list) { MakeTaggable::TagList.new(*arr) }
85
+ it "adds other list" do
86
+ expect(tag_list.concat(another_tag_list)).to eq(%w[awesome radical crazy alien])
87
+ end
88
+
89
+ it "adds other array" do
90
+ expect(tag_list.concat(arr)).to eq(%w[awesome radical crazy alien])
91
+ end
92
+ end
93
+ end
94
+
95
+ describe "#to_s" do
96
+ it "should give a delimited list of words when converted to string" do
97
+ expect(tag_list.to_s).to eq("awesome, radical")
98
+ end
99
+
100
+ it "should be able to call to_s on a frozen tag list" do
101
+ tag_list.freeze
102
+ expect(-> { tag_list.add("cool", "rad,bodacious") }).to raise_error(RuntimeError)
103
+ expect(-> { tag_list.to_s }).to_not raise_error
104
+ end
105
+ end
106
+
107
+ describe "cleaning" do
108
+ it "should parameterize if force_parameterize is set to true" do
109
+ MakeTaggable.force_parameterize = true
110
+ tag_list = MakeTaggable::TagList.new("awesome()", "radical)(cc")
111
+
112
+ expect(tag_list.to_s).to eq("awesome, radical-cc")
113
+ MakeTaggable.force_parameterize = false
114
+ end
115
+
116
+ it "should lowercase if force_lowercase is set to true" do
117
+ MakeTaggable.force_lowercase = true
118
+
119
+ tag_list = MakeTaggable::TagList.new("aweSomE", "RaDicaL", "Entrée")
120
+ expect(tag_list.to_s).to eq("awesome, radical, entrée")
121
+
122
+ MakeTaggable.force_lowercase = false
123
+ end
124
+
125
+ it "should ignore case when removing duplicates if strict_case_match is false" do
126
+ tag_list = MakeTaggable::TagList.new("Junglist", "JUNGLIST", "Junglist", "Massive", "MASSIVE", "MASSIVE")
127
+
128
+ expect(tag_list.to_s).to eq("Junglist, Massive")
129
+ end
130
+
131
+ it "should not ignore case when removing duplicates if strict_case_match is true" do
132
+ MakeTaggable.strict_case_match = true
133
+ tag_list = MakeTaggable::TagList.new("Junglist", "JUNGLIST", "Junglist", "Massive", "MASSIVE", "MASSIVE")
134
+
135
+ expect(tag_list.to_s).to eq("Junglist, JUNGLIST, Massive, MASSIVE")
136
+ MakeTaggable.strict_case_match = false
137
+ end
138
+ end
139
+
140
+ describe "custom parser" do
141
+ let(:parser) { double(parse: %w[cool wicked]) }
142
+ let(:parser_class) { stub_const("MyParser", Class) }
143
+
144
+ it "should use a the default parser if none is set as parameter" do
145
+ allow(MakeTaggable.default_parser).to receive(:new).and_return(parser)
146
+ MakeTaggable::TagList.new("cool, wicked", parse: true)
147
+
148
+ expect(parser).to have_received(:parse)
149
+ end
150
+
151
+ it "should use the custom parser passed as parameter" do
152
+ allow(parser_class).to receive(:new).and_return(parser)
153
+
154
+ MakeTaggable::TagList.new("cool, wicked", parser: parser_class)
155
+
156
+ expect(parser).to have_received(:parse)
157
+ end
158
+
159
+ it "should use the parser setted as attribute" do
160
+ allow(parser_class).to receive(:new).with("new, tag").and_return(parser)
161
+
162
+ tag_list = MakeTaggable::TagList.new("example")
163
+ tag_list.parser = parser_class
164
+ tag_list.add("new, tag", parse: true)
165
+
166
+ expect(parser).to have_received(:parse)
167
+ end
168
+ end
169
+ end