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,340 @@
1
+ require File.expand_path('../../spec_helper', __FILE__)
2
+
3
+ describe Tagtical do
4
+ before(:each) do
5
+ clean_database!
6
+ end
7
+
8
+ it "should provide a class method 'taggable?' that is false for untaggable models" do
9
+ UntaggableModel.should_not be_taggable
10
+ end
11
+
12
+ describe "Taggable Method Generation" do
13
+ before(:each) do
14
+ clean_database!
15
+ TaggableModel.write_inheritable_attribute(:tag_types, [])
16
+ TaggableModel.acts_as_taggable(:tags, :languages, :skills, :needs, :offerings)
17
+ @taggable = TaggableModel.new(:name => "Bob Jones")
18
+ end
19
+
20
+ it "should respond 'true' to taggable?" do
21
+ @taggable.class.should be_taggable
22
+ end
23
+
24
+ it "should create a class attribute for tag types" do
25
+ @taggable.class.should respond_to(:tag_types)
26
+ end
27
+
28
+ it "should create an instance attribute for tag types" do
29
+ @taggable.should respond_to(:tag_types)
30
+ end
31
+
32
+ it "should have all tag types" do
33
+ @taggable.tag_types.should == [:tags, :languages, :skills, :needs, :offerings]
34
+ end
35
+
36
+ it "should generate an association for each tag type" do
37
+ @taggable.should respond_to(:tags, :skills, :languages)
38
+ end
39
+
40
+ it "should add tagged_with and tag_counts to singleton" do
41
+ TaggableModel.should respond_to(:tagged_with, :tag_counts)
42
+ end
43
+
44
+ it "should generate methods for each tag_type" do
45
+ TaggableModel.should respond_to(:with_tags, :with_languages, :with_skills, :with_needs, :with_offerings)
46
+ end
47
+
48
+ it "should generate a tag_list accessor/setter for each tag type" do
49
+ @taggable.should respond_to(:tag_list, :skill_list, :language_list)
50
+ @taggable.should respond_to(:tag_list=, :skill_list=, :language_list=)
51
+ end
52
+
53
+ it "should generate a tag_list accessor, that includes owned tags, for each tag type" do
54
+ @taggable.should respond_to(:all_tags_list, :all_skills_list, :all_languages_list)
55
+ end
56
+ end
57
+
58
+ describe "Single Table Inheritance" do
59
+ before do
60
+ @taggable = TaggableModel.new(:name => "taggable")
61
+ @inherited_same = InheritingTaggableModel.new(:name => "inherited same")
62
+ @inherited_different = AlteredInheritingTaggableModel.new(:name => "inherited different")
63
+ end
64
+
65
+ it "should pass on tag contexts to STI-inherited models" do
66
+ @inherited_same.should respond_to(:tag_list, :skill_list, :language_list)
67
+ @inherited_different.should respond_to(:tag_list, :skill_list, :language_list)
68
+ end
69
+
70
+ it "should have tag contexts added in altered STI models" do
71
+ @inherited_different.should respond_to(:part_list)
72
+ end
73
+ end
74
+
75
+ describe "Reloading" do
76
+ it "should save a model instantiated by Model.find" do
77
+ taggable = TaggableModel.create!(:name => "Taggable")
78
+ found_taggable = TaggableModel.find(taggable.id)
79
+ found_taggable.save
80
+ end
81
+ end
82
+
83
+ describe "Related Objects" do
84
+ it "should find related objects based on tag names on context" do
85
+ taggable1 = TaggableModel.create!(:name => "Taggable 1")
86
+ taggable2 = TaggableModel.create!(:name => "Taggable 2")
87
+ taggable3 = TaggableModel.create!(:name => "Taggable 3")
88
+
89
+ taggable1.tag_list = "one, two"
90
+ taggable1.save
91
+
92
+ taggable2.tag_list = "three, four"
93
+ taggable2.save
94
+
95
+ taggable3.tag_list = "one, four"
96
+ taggable3.save
97
+
98
+ taggable1.find_related_tags.should include(taggable3)
99
+ taggable1.find_related_tags.should_not include(taggable2)
100
+ end
101
+
102
+ it "should find other related objects based on tag names on context" do
103
+ taggable1 = TaggableModel.create!(:name => "Taggable 1")
104
+ taggable2 = OtherTaggableModel.create!(:name => "Taggable 2")
105
+ taggable3 = OtherTaggableModel.create!(:name => "Taggable 3")
106
+
107
+ taggable1.tag_list = "one, two"
108
+ taggable1.save
109
+
110
+ taggable2.tag_list = "three, four"
111
+ taggable2.save
112
+
113
+ taggable3.tag_list = "one, four"
114
+ taggable3.save
115
+
116
+ taggable1.find_related_tags_for(OtherTaggableModel).should include(taggable3)
117
+ taggable1.find_related_tags_for(OtherTaggableModel).should_not include(taggable2)
118
+ end
119
+
120
+ it "should not include the object itself in the list of related objects" do
121
+ taggable1 = TaggableModel.create!(:name => "Taggable 1")
122
+ taggable2 = TaggableModel.create!(:name => "Taggable 2")
123
+
124
+ taggable1.tag_list = "one"
125
+ taggable1.save
126
+
127
+ taggable2.tag_list = "one, two"
128
+ taggable2.save
129
+
130
+ taggable1.find_related_tags.should include(taggable2)
131
+ taggable1.find_related_tags.should_not include(taggable1)
132
+ end
133
+ end
134
+
135
+ describe "Matching Contexts" do
136
+ it "should find objects with tags of matching contexts" do
137
+ taggable1 = TaggableModel.create!(:name => "Taggable 1")
138
+ taggable2 = TaggableModel.create!(:name => "Taggable 2")
139
+ taggable3 = TaggableModel.create!(:name => "Taggable 3")
140
+
141
+ taggable1.offering_list = "one, two"
142
+ taggable1.save!
143
+
144
+ taggable2.need_list = "one, two"
145
+ taggable2.save!
146
+
147
+ taggable3.offering_list = "one, two"
148
+ taggable3.save!
149
+
150
+ taggable1.find_matching_contexts(:offerings, :needs).should include(taggable2)
151
+ taggable1.find_matching_contexts(:offerings, :needs).should_not include(taggable3)
152
+ end
153
+
154
+ it "should find other related objects with tags of matching contexts" do
155
+ taggable1 = TaggableModel.create!(:name => "Taggable 1")
156
+ taggable2 = OtherTaggableModel.create!(:name => "Taggable 2")
157
+ taggable3 = OtherTaggableModel.create!(:name => "Taggable 3")
158
+
159
+ taggable1.offering_list = "one, two"
160
+ taggable1.save
161
+
162
+ taggable2.need_list = "one, two"
163
+ taggable2.save
164
+
165
+ taggable3.offering_list = "one, two"
166
+ taggable3.save
167
+
168
+ taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should include(taggable2)
169
+ taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should_not include(taggable3)
170
+ end
171
+
172
+ it "should not include the object itself in the list of related objects" do
173
+ taggable1 = TaggableModel.create!(:name => "Taggable 1")
174
+ taggable2 = TaggableModel.create!(:name => "Taggable 2")
175
+
176
+ taggable1.tag_list = "one"
177
+ taggable1.save
178
+
179
+ taggable2.tag_list = "one, two"
180
+ taggable2.save
181
+
182
+ taggable1.find_related_tags.should include(taggable2)
183
+ taggable1.find_related_tags.should_not include(taggable1)
184
+ end
185
+ end
186
+
187
+ describe 'Tagging Contexts' do
188
+ it 'should eliminate duplicate tagging contexts ' do
189
+ TaggableModel.acts_as_taggable(:skills, :skills)
190
+ TaggableModel.tag_types.freq["skill"].should == 1
191
+ end
192
+
193
+ it "should not contain embedded/nested arrays" do
194
+ TaggableModel.acts_as_taggable([:skills], [:skills])
195
+ TaggableModel.tag_types.freq[[:skills]].should == 0
196
+ end
197
+
198
+ it "should _flatten_ the content of arrays" do
199
+ TaggableModel.acts_as_taggable([:skills], [:skills])
200
+ TaggableModel.tag_types.freq["skill"].should == 1
201
+ end
202
+
203
+ it "should support tag_types without an associated Tag subclass" do
204
+ lambda { TaggableModel.acts_as_taggable(:doesnt_exist) }.should_not raise_error
205
+ end
206
+
207
+ it "should not raise an error when passed nil" do
208
+ lambda {
209
+ TaggableModel.acts_as_taggable()
210
+ }.should_not raise_error
211
+ end
212
+
213
+ it "should not raise an error when passed [nil]" do
214
+ lambda {
215
+ TaggableModel.acts_as_taggable([nil])
216
+ }.should_not raise_error
217
+ end
218
+
219
+ context "when Tag subclass is not present" do
220
+
221
+ before do
222
+ TaggableModel.acts_as_taggable(:machines)
223
+ @taggable_model = TaggableModel.create!(:name => "Taggable 1", :tag_list => "random, tags")
224
+ @taggable_model.machine_list = "car, plane, train"
225
+ @taggable_model.save!
226
+ @taggable_model.reload
227
+ @tag_type = @taggable_model.tag_types.find { |t| t=="machine" }
228
+ end
229
+
230
+ specify { @tag_type.klass.should be_nil }
231
+
232
+ it "should have basic tagging methods" do
233
+ @taggable_model.machines.map(&:value).sort.should == ["car", "plane", "train"]
234
+ @taggable_model.tags.machines.map(&:value).sort.should == ["car", "plane", "train"]
235
+ end
236
+
237
+ it "should instantiate with Tagtical::Tag" do
238
+ @taggable_model.machines.each { |tag| tag.should be_an_instance_of Tagtical::Tag }
239
+ end
240
+
241
+ end
242
+ end
243
+
244
+ describe "Tagging with Symbols" do
245
+ it "should tag with symbols" do
246
+ @taggable_model = TaggableModel.create!(:name => "Taggable", :tag_list => [:tag1, :tag2])
247
+ @taggable_model.tag_list.should == ["tag1", "tag2"]
248
+ end
249
+
250
+ end
251
+
252
+ describe "Tagging With Relevance" do
253
+ before do
254
+ @taggable_model = TaggableModel.create!(:name => "Taggable", :tag_list => {"random" => 0.45, "tags" => 1.54}, :skill_list => "tennis, pottery")
255
+ end
256
+
257
+ it "should have tags with relevance" do
258
+ @taggable_model.tags.sort.map(&:relevance).should == [0.45, Tagtical::Tagging.default_relevance, Tagtical::Tagging.default_relevance, 1.54]
259
+ end
260
+
261
+ it "should have skills with relevance" do
262
+ @taggable_model.skills.first.relevance.should == Tagtical::Tagging.default_relevance
263
+ end
264
+
265
+ it "should overwrite relevance" do
266
+ @taggable_model.tag_list = {"tennis" => 6.0}
267
+ @taggable_model.save!
268
+ @taggable_model.reload
269
+ @taggable_model.skills.find_by_value("tennis").relevance.should == 6.0
270
+ end
271
+
272
+ it "should be able to change the tag type and update the relevance" do
273
+ @taggable_model.craft_list = {"pottery" => 4.56}
274
+ @taggable_model.save!
275
+ @taggable_model.reload
276
+ skills = @taggable_model.skills.find_all_by_value("pottery")
277
+ skills.should have(1).items
278
+ skills.first.relevance.should == 4.56
279
+ skills.first.should be_an_instance_of Tag::Craft
280
+ end
281
+
282
+ end
283
+
284
+ describe 'Caching' do
285
+ before(:each) do
286
+ @taggable = CachedModel.new(:name => "Bob Jones")
287
+ end
288
+
289
+ it "should add saving of tag lists and cached tag lists to the instance" do
290
+ @taggable.should respond_to(:save_cached_tag_list)
291
+ @taggable.should respond_to(:save_tags)
292
+ end
293
+
294
+ it "should generate a cached column checker for each tag type" do
295
+ CachedModel.should respond_to(:caching_tag_list?)
296
+ end
297
+
298
+ it 'should not have cached tags' do
299
+ @taggable.cached_tag_list.should be_blank
300
+ end
301
+
302
+ it 'should cache tags' do
303
+ @taggable.update_attributes(:tag_list => 'awesome, epic')
304
+ @taggable.cached_tag_list.should == 'awesome, epic'
305
+ end
306
+
307
+ it 'should keep the cache' do
308
+ @taggable.update_attributes(:tag_list => 'awesome, epic')
309
+ @taggable = CachedModel.find(@taggable)
310
+ @taggable.save!
311
+ @taggable.cached_tag_list.should == 'awesome, epic'
312
+ end
313
+
314
+ it 'should update the cache' do
315
+ @taggable.update_attributes(:tag_list => 'awesome, epic')
316
+ @taggable.update_attributes(:tag_list => 'awesome')
317
+ @taggable.cached_tag_list.should == 'awesome'
318
+ end
319
+
320
+ it 'should remove the cache' do
321
+ @taggable.update_attributes(:tag_list => 'awesome, epic')
322
+ @taggable.update_attributes(:tag_list => '')
323
+ @taggable.cached_tag_list.should be_blank
324
+ end
325
+
326
+ it 'should have a tag list' do
327
+ @taggable.update_attributes(:tag_list => 'awesome, epic')
328
+ @taggable = CachedModel.find(@taggable.id)
329
+ @taggable.tag_list.sort.should == %w(awesome epic).sort
330
+ end
331
+
332
+ it 'should keep the tag list' do
333
+ @taggable.update_attributes(:tag_list => 'awesome, epic')
334
+ @taggable = CachedModel.find(@taggable.id)
335
+ @taggable.save!
336
+ @taggable.tag_list.sort.should == %w(awesome epic).sort
337
+ end
338
+ end
339
+
340
+ end
metadata ADDED
@@ -0,0 +1,132 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tagtical
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.6
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Aryk Grosz
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+ date: 2011-07-10 00:00:00.000000000Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: sqlite3-ruby
16
+ requirement: &2161646020 !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: *2161646020
25
+ - !ruby/object:Gem::Dependency
26
+ name: mysql
27
+ requirement: &2161645540 !ruby/object:Gem::Requirement
28
+ none: false
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ type: :runtime
34
+ prerelease: false
35
+ version_requirements: *2161645540
36
+ - !ruby/object:Gem::Dependency
37
+ name: jeweler
38
+ requirement: &2161645060 !ruby/object:Gem::Requirement
39
+ none: false
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ type: :runtime
45
+ prerelease: false
46
+ version_requirements: *2161645060
47
+ - !ruby/object:Gem::Dependency
48
+ name: rcov
49
+ requirement: &2161644580 !ruby/object:Gem::Requirement
50
+ none: false
51
+ requirements:
52
+ - - ! '>='
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ type: :runtime
56
+ prerelease: false
57
+ version_requirements: *2161644580
58
+ description: Tagtical allows you do create subclasses for Tag and add additional functionality
59
+ in an STI fashion. For example. You could do Tag::Color.find_by_name('blue').to_rgb.
60
+ It also supports storing weights or relevance on the taggings.
61
+ email: aryk@mixbook.com
62
+ executables: []
63
+ extensions: []
64
+ extra_rdoc_files:
65
+ - README.rdoc
66
+ files:
67
+ - CHANGELOG
68
+ - Gemfile
69
+ - Gemfile.lock
70
+ - MIT-LICENSE
71
+ - README.rdoc
72
+ - Rakefile
73
+ - VERSION
74
+ - generators/tagtical_migration/tagtical_migration_generator.rb
75
+ - generators/tagtical_migration/templates/migration.rb
76
+ - lib/generators/tagtical/migration/migration_generator.rb
77
+ - lib/generators/tagtical/migration/templates/active_record/migration.rb
78
+ - lib/tagtical.rb
79
+ - lib/tagtical/acts_as_tagger.rb
80
+ - lib/tagtical/compatibility/Gemfile
81
+ - lib/tagtical/compatibility/active_record_backports.rb
82
+ - lib/tagtical/tag.rb
83
+ - lib/tagtical/tag_list.rb
84
+ - lib/tagtical/taggable.rb
85
+ - lib/tagtical/taggable/cache.rb
86
+ - lib/tagtical/taggable/collection.rb
87
+ - lib/tagtical/taggable/core.rb
88
+ - lib/tagtical/taggable/ownership.rb
89
+ - lib/tagtical/taggable/related.rb
90
+ - lib/tagtical/tagging.rb
91
+ - lib/tagtical/tags_helper.rb
92
+ - rails/init.rb
93
+ - spec/bm.rb
94
+ - spec/database.yml
95
+ - spec/database.yml.sample
96
+ - spec/models.rb
97
+ - spec/schema.rb
98
+ - spec/spec_helper.rb
99
+ - spec/tagtical/acts_as_tagger_spec.rb
100
+ - spec/tagtical/tag_list_spec.rb
101
+ - spec/tagtical/tag_spec.rb
102
+ - spec/tagtical/taggable_spec.rb
103
+ - spec/tagtical/tagger_spec.rb
104
+ - spec/tagtical/tagging_spec.rb
105
+ - spec/tagtical/tags_helper_spec.rb
106
+ - spec/tagtical/tagtical_spec.rb
107
+ homepage: https://github.com/Mixbook/tagtical
108
+ licenses: []
109
+ post_install_message:
110
+ rdoc_options: []
111
+ require_paths:
112
+ - lib
113
+ required_ruby_version: !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ! '>='
117
+ - !ruby/object:Gem::Version
118
+ version: '0'
119
+ required_rubygems_version: !ruby/object:Gem::Requirement
120
+ none: false
121
+ requirements:
122
+ - - ! '>='
123
+ - !ruby/object:Gem::Version
124
+ version: '0'
125
+ requirements: []
126
+ rubyforge_project:
127
+ rubygems_version: 1.8.5
128
+ signing_key:
129
+ specification_version: 3
130
+ summary: Tagtical is a tagging plugin for Rails that provides weighting, contexts,
131
+ and inheritance for tags.
132
+ test_files: []