tagtical 1.0.6

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 (41) hide show
  1. data/CHANGELOG +25 -0
  2. data/Gemfile +20 -0
  3. data/Gemfile.lock +25 -0
  4. data/MIT-LICENSE +20 -0
  5. data/README.rdoc +306 -0
  6. data/Rakefile +59 -0
  7. data/VERSION +1 -0
  8. data/generators/tagtical_migration/tagtical_migration_generator.rb +7 -0
  9. data/generators/tagtical_migration/templates/migration.rb +34 -0
  10. data/lib/generators/tagtical/migration/migration_generator.rb +32 -0
  11. data/lib/generators/tagtical/migration/templates/active_record/migration.rb +35 -0
  12. data/lib/tagtical/acts_as_tagger.rb +69 -0
  13. data/lib/tagtical/compatibility/Gemfile +8 -0
  14. data/lib/tagtical/compatibility/active_record_backports.rb +21 -0
  15. data/lib/tagtical/tag.rb +314 -0
  16. data/lib/tagtical/tag_list.rb +133 -0
  17. data/lib/tagtical/taggable/cache.rb +53 -0
  18. data/lib/tagtical/taggable/collection.rb +141 -0
  19. data/lib/tagtical/taggable/core.rb +317 -0
  20. data/lib/tagtical/taggable/ownership.rb +110 -0
  21. data/lib/tagtical/taggable/related.rb +60 -0
  22. data/lib/tagtical/taggable.rb +51 -0
  23. data/lib/tagtical/tagging.rb +42 -0
  24. data/lib/tagtical/tags_helper.rb +17 -0
  25. data/lib/tagtical.rb +47 -0
  26. data/rails/init.rb +1 -0
  27. data/spec/bm.rb +53 -0
  28. data/spec/database.yml +17 -0
  29. data/spec/database.yml.sample +17 -0
  30. data/spec/models.rb +60 -0
  31. data/spec/schema.rb +46 -0
  32. data/spec/spec_helper.rb +159 -0
  33. data/spec/tagtical/acts_as_tagger_spec.rb +94 -0
  34. data/spec/tagtical/tag_list_spec.rb +102 -0
  35. data/spec/tagtical/tag_spec.rb +301 -0
  36. data/spec/tagtical/taggable_spec.rb +460 -0
  37. data/spec/tagtical/tagger_spec.rb +76 -0
  38. data/spec/tagtical/tagging_spec.rb +52 -0
  39. data/spec/tagtical/tags_helper_spec.rb +28 -0
  40. data/spec/tagtical/tagtical_spec.rb +340 -0
  41. metadata +132 -0
@@ -0,0 +1,301 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Tagtical::Tag do
4
+
5
+ before do
6
+ clean_database!
7
+ @klass = Tagtical::Tag
8
+ @tag = @klass.new(:value => "train")
9
+ end
10
+
11
+ subject { @tag }
12
+
13
+ it { should be_valid }
14
+
15
+ its(:count) { should == 0 }
16
+ its(:to_s) { should == @tag.value }
17
+
18
+ specify { @klass.sti_name.should be_nil }
19
+
20
+ its(:type) { should be_nil }
21
+
22
+ describe ".find_sti_class" do
23
+ specify do
24
+ {"skill" => Tag::Skill, "tag" => @klass}.each do |arg, result|
25
+ @klass.send(:find_sti_class, arg).should == result
26
+ end
27
+ end
28
+ end
29
+
30
+ describe "validations" do
31
+
32
+ it "should require a value" do
33
+ {"" => 1, nil => 1, "foo" => 0}.each do |value, error_count|
34
+ @tag.value = value
35
+ @tag.valid?
36
+ @tag.errors[:value].should have(error_count).items
37
+ end
38
+ end
39
+
40
+ it "should be unique on value and type" do
41
+ lambda {
42
+ Tag::Skill.create!(:value => "foo")
43
+ Tag::Craft.create!(:value => "foo")
44
+ }.should change(@klass, :count).by(2)
45
+ end
46
+
47
+ context "when possible_values specified" do
48
+ before { @klass.possible_values = %w{knife fork spoon} }
49
+ after { @klass.possible_values = nil}
50
+
51
+ it "should not be valid if value is not in possible_values" do
52
+ @tag.value = "glass"
53
+ @tag.should be_invalid
54
+ @tag.errors[:value][0].should == %{Value "glass" not found in list: ["knife", "fork", "spoon"]}
55
+ end
56
+ end
57
+
58
+ end
59
+
60
+ describe "tag scopes" do
61
+ before do
62
+ Tagtical::Tag.create(:value => "Plane")
63
+ Tag::Skill.create(:value => "Kung Fu")
64
+ Tag::Craft.create(:value => "Painting")
65
+ NeedTag.create(:value => "chair")
66
+ end
67
+
68
+ it "should retrieve tags finder type conditions" do
69
+ Tagtical::Tag.skills.should have_tag_values ["Kung Fu", "Painting"]
70
+ Tagtical::Tag.skills(:only => :current).should have_tag_values ["Kung Fu"]
71
+ Tagtical::Tag.crafts(:only => :parents).should have_tag_values ["Kung Fu", "Plane"]
72
+ end
73
+
74
+ end
75
+
76
+ describe "#dump_value" do
77
+ before do
78
+ @tag = Tagtical::Tag::PartTag.new(:value => "FOO")
79
+ end
80
+
81
+ its(:value) { should == "foo" }
82
+
83
+ it "should accept a nil value" do
84
+ lambda { @tag.value = nil }.should_not raise_error
85
+ @tag.value.should be_nil
86
+ end
87
+ end
88
+
89
+ describe "#load_value" do
90
+ before do
91
+ @tag = Tag::Skill.new(:value => "basketball")
92
+ end
93
+
94
+ specify { @tag[:value].should == "basketball" }
95
+
96
+ its(:value) { should == "basketballer" }
97
+
98
+ it "should accept a nil value" do
99
+ lambda { @tag.value = nil }.should_not raise_error
100
+ @tag.value.should be_nil
101
+ end
102
+ end
103
+
104
+ it "should refresh @value on value setter" do
105
+ @tag.value = "foo"
106
+ @tag.value.should == "foo"
107
+ @tag.value = "bar"
108
+ @tag.value.should == "bar"
109
+ end
110
+
111
+ describe "sort" do
112
+ before do
113
+ @tag1 = @klass.new(:value => "car").tap { |x| x["relevance"] = "2.5" }
114
+ @tag2 = @klass.new(:value => "plane").tap { |x| x["relevance"] = "1.7" }
115
+ @tag3 = @klass.new(:value => "bike").tap { |x| x["relevance"] = "1.1" }
116
+ @tags = [@tag1, @tag2, @tag3]
117
+ end
118
+
119
+ it "should sort by relevance if all tags have them" do
120
+ @tags.sort.map(&:value).should == ["bike", "plane", "car"]
121
+ end
122
+
123
+ it "should fallback gracefully when relevance not provided" do
124
+ @tag3["relevance"] = nil
125
+ @tags.sort.map(&:value).should == ["bike", "plane", "car"]
126
+ end
127
+
128
+ it "should sort by value when no relevances provided" do
129
+ @tags.each { |t| t["relevance"] = nil }
130
+ @tags.sort.map(&:value).should == ["bike", "car", "plane"]
131
+ end
132
+ end
133
+
134
+ describe "#==" do
135
+ it { should == @tag }
136
+ it { should_not == "tain" }
137
+ it { should_not == @klass.new }
138
+ end
139
+
140
+ describe "#find_or_create_tags" do
141
+ before(:each) do
142
+ @klass.create!(:value => "awesome")
143
+ @klass.create!(:value => "epic")
144
+ end
145
+
146
+ it "should find both tags" do
147
+ lambda {
148
+ @klass.find_or_create_tags("awesome", "epic")
149
+ }.should change(@klass, :count).by(0)
150
+ end
151
+ end
152
+
153
+ describe "#where_any_like" do
154
+ before do
155
+ @klass.create!(:value => "awesome")
156
+ @klass.create!(:value => "epic")
157
+ end
158
+
159
+ it "should find both tags wildcard search" do
160
+ @klass.where_any_like(["awe", "epic"], :wildcard => true).should have(2).items
161
+ end
162
+
163
+ it "should not be case sensitive" do
164
+ @klass.where_any_like(["AWESOME", "EpIc"]).should have(2).items
165
+ end
166
+
167
+ end
168
+
169
+ describe ".find_or_create_with_like_by_value!" do
170
+ before do
171
+ @tag.value = "awesome"
172
+ @tag.save
173
+ end
174
+
175
+ it "should find by name" do
176
+ @klass.find_or_create_with_like_by_value!("awesome").should == @tag
177
+ end
178
+
179
+ it "should find by name case insensitive" do
180
+ @klass.find_or_create_with_like_by_value!("AWESOME").should == @tag
181
+ end
182
+
183
+ it "should create by name" do
184
+ lambda {
185
+ @klass.find_or_create_with_like_by_value!("epic")
186
+ }.should change(@klass, :count).by(1)
187
+ end
188
+ end
189
+
190
+ describe ".find_or_create_tags" do
191
+ before(:each) do
192
+ @tag.value = "awesome"
193
+ @tag.save!
194
+ end
195
+
196
+ it "should find by name" do
197
+ @klass.find_or_create_tags("awesome").should == {@tag => "awesome"}
198
+ end
199
+
200
+ it "should find by name case insensitive" do
201
+ @klass.find_or_create_tags("AWESOME").should == {@tag => "AWESOME"}
202
+ end
203
+
204
+ it "should create by name" do
205
+ lambda {
206
+ @klass.find_or_create_tags("epic")
207
+ }.should change(@klass, :count).by(1)
208
+ end
209
+
210
+ it "should find or create by name" do
211
+ lambda {
212
+ @klass.find_or_create_tags("awesome", "epic").keys.map(&:value).should == ["awesome", "epic"]
213
+ }.should change(@klass, :count).by(1)
214
+ end
215
+
216
+ it "should return an empty array if no tags are specified" do
217
+ @klass.find_or_create_tags([]).should == {}
218
+ end
219
+ end
220
+
221
+ it "should require a name" do
222
+ @tag.value = nil
223
+ @tag.valid?
224
+
225
+ if ActiveRecord::VERSION::MAJOR >= 3
226
+ @tag.errors[:value].should == ["can't be blank"]
227
+ else
228
+ @tag.errors[:value].should == "can't be blank"
229
+ end
230
+
231
+ @tag.value = "something"
232
+ @tag.valid?
233
+
234
+ if ActiveRecord::VERSION::MAJOR >= 3
235
+ @tag.errors[:value].should == []
236
+ else
237
+ @tag.errors[:value].should be_nil
238
+ end
239
+ end
240
+
241
+ it "#where_any" do
242
+ @tag.value = "cool"
243
+ @tag.save!
244
+ @klass.where_any('cool').should include(@tag)
245
+ end
246
+
247
+ describe "Type" do
248
+ before do
249
+ @klass = @klass::Type
250
+ @type = @klass.new("skill")
251
+ end
252
+ subject { @type }
253
+
254
+ its(:klass) { should == Tag::Skill }
255
+ its(:scope_name) { should == :skills }
256
+
257
+ describe "initialize" do
258
+ it "converts string into correct format" do
259
+ {"ClassNames" => "class_name", "photo_tags" => "photo", :photo => "photo"}.each do |input, result|
260
+ @klass.new(input).should == result
261
+ end
262
+ end
263
+ end
264
+
265
+ describe ".[]" do
266
+ specify { @klass[@type].should equal @type }
267
+ specify { @klass["foo"].should be_a @klass }
268
+ end
269
+
270
+ describe "#==" do
271
+ {"foo" => false, "skill" => true, Tagtical::Tag::Type.new("skill") => true}.each do |obj, result|
272
+ specify { (subject==obj).should==result }
273
+ end
274
+ end
275
+
276
+ describe "#derive_class_candidates" do
277
+ specify do
278
+ subject.send(:derive_class_candidates).should include(
279
+ "Tagtical::Tag::Skill", "Tag::Skill", "Skill",
280
+ "Tagtical::Tag::SkillTag", "Tag::SkillTag", "SkillTag"
281
+ )
282
+ end
283
+ end
284
+
285
+ describe "#tag_list_name" do
286
+ context "when prefix is not specified" do
287
+ its(:tag_list_name) { should == "skill_list" }
288
+ end
289
+ context "when prefix is specified" do
290
+ specify { subject.tag_list_name(:all).should == "all_skill_list" }
291
+ end
292
+ end
293
+
294
+ context "when type is 'Tag'" do
295
+ before { @type = @klass.new("tag") }
296
+ its(:klass) { should == Tagtical::Tag }
297
+ its(:scope_name) { should == :tags }
298
+ end
299
+
300
+ end
301
+ end