genki-dm-is-taggable 0.1

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.
@@ -0,0 +1,4 @@
1
+ class Tagging
2
+ include DataMapper::Resource
3
+ is :tagging
4
+ end
@@ -0,0 +1,5 @@
1
+ class Article
2
+ include DataMapper::Resource
3
+ property :id, Serial
4
+ is :taggable, :by => ["User", "Bot"]
5
+ end
data/spec/data/bot.rb ADDED
@@ -0,0 +1,6 @@
1
+ class Bot
2
+ include DataMapper::Resource
3
+ property :id, Serial
4
+ property :name, String
5
+ is :tagger, :on => ["Article", "Picture"]
6
+ end
@@ -0,0 +1,5 @@
1
+ class Picture
2
+ include DataMapper::Resource
3
+ property :id, Serial
4
+ is :taggable, :by => ["User", "Bot"]
5
+ end
data/spec/data/user.rb ADDED
@@ -0,0 +1,6 @@
1
+ class User
2
+ include DataMapper::Resource
3
+ property :id, Serial
4
+ property :name, String
5
+ is :tagger, :on => ["Article", "Picture"]
6
+ end
@@ -0,0 +1,289 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ #DataObjects::Sqlite3.logger = DataObjects::Logger.new(STDOUT, 0)
5
+ DataMapper.auto_migrate!
6
+
7
+ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
8
+ describe 'DataMapper::Is::Taggable' do
9
+ before(:all) do
10
+ @user1 = User.create(:name => "user1")
11
+ @user2 = User.create(:name => "user2")\
12
+
13
+ @bot1 = Bot.create(:name => "bot1")
14
+ @bot2 = Bot.create(:name => "bot2")
15
+
16
+ @picture1 = Picture.create
17
+ @picture1.tag(:by => @user1, :with => "tag1, tag2, tag3")
18
+ @picture1.tag(:by => @user2, :with => "tag10, tag2, tag3")
19
+
20
+ @picture2 = Picture.create
21
+ @user2.tag(:on=>@picture2, :with => ["tag1", "tag4", "tag5"])
22
+
23
+ @picture1.tag(:by => @bot1, :with => ["tag1, tag3, tag_by_bot"])
24
+
25
+ @article = Article.create
26
+ @article.tag(:by =>@user1, :with => ["tag1", "tag4", "tag5"])
27
+ end
28
+
29
+ it "should be able to tag with taglist" do
30
+ picture = Picture.new
31
+ picture.taglist = "tag1, tag2, tag3"
32
+ picture.save.should == true
33
+ picture.tags.count.should == 3
34
+ picture.taglist.should == "tag1, tag2, tag3"
35
+ picture.destroy
36
+ end
37
+
38
+ it "should be able to tag with taglist with user scope" do
39
+ picture = Picture.new
40
+ user = User.create(:name => "me")
41
+
42
+ Tag.as(user) do
43
+ picture.taglist = "tag1, tag2, tag3"
44
+ picture.save.should == true
45
+ end
46
+ picture.tags.count.should == 3
47
+ Tag.by(user).on(picture).sort.should == [Tag.get("tag1"), Tag.get("tag2"), Tag.get("tag3")].sort
48
+ picture.destroy
49
+ end
50
+
51
+ it "should be able to update tags with taglist" do
52
+ picture = Picture.new
53
+ picture.taglist = "tag1, tag2, tag3"
54
+ picture.save
55
+
56
+ picture.taglist = "tag1, tag3, tag4, tagme"
57
+ picture.tags.count.should == 4
58
+ picture.taglist.should == "tag1, tag3, tag4, tagme"
59
+
60
+ picture.destroy
61
+ end
62
+
63
+ it "should setup to tagger_classes and taggable_classes accessors for taggables and taggers" do
64
+ Picture.respond_to?(:tagger_classes).should be_true
65
+ User.respond_to?(:taggable_classes).should be_true
66
+ end
67
+
68
+ it "should be able to tag by taggers" do
69
+ picture = Picture.new
70
+ user = User.new(:name => "me")
71
+ user.save.should == true
72
+ picture.save.should == true
73
+
74
+ picture.tag(:by => user, :with =>["tagme", "tagtag", "tagtagtag"])
75
+ user.tag(:on =>picture, :with => ["tag3", "tag4", "tag5"])
76
+
77
+ picture.taggings.count.should == 6
78
+ picture.tags.count.should == 6
79
+
80
+ user.destroy
81
+ picture.destroy
82
+ end
83
+
84
+ it "should be able to tag anonymously" do
85
+ picture = Picture.new
86
+ picture.save.should == true
87
+
88
+ picture.tag(:with => ["tagme", "tagtag", "tagtagtag"])
89
+ picture.tags.count.should == 3
90
+
91
+ picture.tags.include?(Tag.get("tagme")).should be_true
92
+ picture.tags.include?(Tag.get("tagtag")).should be_true
93
+ picture.tags.include?(Tag.get("tagtagtag")).should be_true
94
+
95
+ picture.taggings.each do |tag|
96
+ tag.tagger_type.should be_nil
97
+ tag.tagger_id.should be_nil
98
+ end
99
+
100
+ picture.destroy
101
+ end
102
+
103
+ it "should be able to retrieve Picture by with_any_tags" do
104
+ Picture.find( :match => :any ,:with => ["tag2", "tag5"]).size.should == 2
105
+ Picture.find( :match => :any ,:with => ["tag2", "tag5"]).include?(@picture1).should be_true
106
+ Picture.find( :match => :any ,:with => ["tag2", "tag5"]).include?(@picture2).should be_true
107
+
108
+ Picture.find( :match => :any ,:by => User, :with => ["tag2", "tag5"]).size.should == 2
109
+ Picture.find( :match => :any ,:by => User, :with => ["tag2", "tag5"]).include?(@picture1).should be_true
110
+ Picture.find( :match => :any ,:by => User, :with => [ "tag2", "tag5"]).include?(@picture2).should be_true
111
+
112
+ Picture.find( :match => :any ,:by => Bot, :with => ["tag_by_bot", "tag5"]).size.should == 1
113
+ Picture.find( :match => :any ,:by => Bot, :with => ["tag_by_bot", "tag5"]).include?(@picture1).should be_true
114
+ end
115
+
116
+ it "should be able to retrieve Picture by find" do
117
+ Picture.find(:with =>"tag1").size.should == 2
118
+ Picture.find(:with =>"tag1").include?(@picture1).should be_true
119
+ Picture.find(:with =>"tag1").include?(@picture2).should be_true
120
+
121
+ Picture.find(:by =>User, :with =>"tag1").size.should == 2
122
+ Picture.find(:by =>User,:with => "tag1").include?(@picture1).should be_true
123
+ Picture.find(:by =>User, :with =>"tag1").include?(@picture2).should be_true
124
+
125
+ Picture.find(:by =>Bot,:with => "tag1").size.should == 1
126
+ Picture.find(:by =>Bot, :with =>"tag1").include?(@picture1).should be_true
127
+
128
+ Picture.find(:with =>"tag2").should == [@picture1]
129
+
130
+ Picture.find(:with =>["tag1", "tag2"]).should == [@picture1]
131
+ Picture.find(:with =>"non existing tag").should == []
132
+ end
133
+
134
+
135
+ it "should be able to retrieve all tags" do
136
+ # ALL taggers
137
+ all_tags = @picture1.tags
138
+ all_tags.size.should == 5
139
+ all_tags.include?(Tag.get("tag1")).should be_true
140
+ all_tags.include?(Tag.get("tag2")).should be_true
141
+ all_tags.include?(Tag.get("tag3")).should be_true
142
+ all_tags.include?(Tag.get("tag_by_bot")).should be_true
143
+ all_tags.include?(Tag.get("tag10")).should be_true
144
+ # Users
145
+ all_tags = @picture1.tags_by_users
146
+ all_tags.size.should == 4
147
+ all_tags.include?(Tag.get("tag1")).should be_true
148
+ all_tags.include?(Tag.get("tag2")).should be_true
149
+ all_tags.include?(Tag.get("tag3")).should be_true
150
+ all_tags.include?(Tag.get("tag10")).should be_true
151
+
152
+ # Bots
153
+ all_tags = @picture1.tags_by_bots
154
+ all_tags.size.should == 3
155
+ all_tags.include?(Tag.get("tag1")).should be_true
156
+ all_tags.include?(Tag.get("tag3")).should be_true
157
+ all_tags.include?(Tag.get("tag_by_bot")).should be_true
158
+ end
159
+
160
+ it "should handle scoped tag creation" do
161
+ picture = Picture.new
162
+ user = User.new(:name => "me")
163
+ user.save.should == true
164
+ picture.save.should == true
165
+
166
+ Tag.as(user) do
167
+ picture.tag(:with => "scoped_tag")
168
+ end
169
+ Picture.find(:with => "scoped_tag").size.should == 1
170
+ Picture.find("scoped_tag").include?(picture).should be_true
171
+
172
+ user.destroy
173
+ picture.destroy
174
+ end
175
+
176
+ it "should handle scoped tag retrieval" do
177
+ Tag.as(Bot) do
178
+ Picture.find( :match => :any , :with => "tag_by_bot").size.should == 1
179
+ Picture.find( :match => :any ,:with => "tag_by_bot").include?(@picture1).should be_true
180
+ end
181
+
182
+ Tag.as(User) do
183
+ Picture.find( :match => :any , :with => "tag_by_bot").should be_empty
184
+ Picture.find("tag1, tag2, tag3").size.should == 1
185
+ Picture.find("tag1, tag2, tag3").include?(@picture1).should be_true
186
+
187
+ Picture.find( :match => :any ,:with => "tag1").size.should == 2
188
+ Picture.find("tag1").include?(@picture1).should be_true
189
+ Picture.find("tag1").include?(@picture2).should be_true
190
+ end
191
+ end
192
+
193
+ it "should be able to retrieve picture tags count" do
194
+ # This requires a dm-aggration and the patch that enables unique count
195
+ # Note: @picture1.tags_by_users.size also works, but less optimized. this uses COUNT in sql
196
+ @picture1.count_tags_by_users.should == 4
197
+ @picture1.count_tags_by_bots.should == 3
198
+ @picture1.count_tags.should == 5
199
+ end
200
+
201
+ it "should be able to retrieve amount of times tag has been used" do
202
+ # picture1 picture2 article1
203
+ Tag.get("tag1").tagged_count.should == 3
204
+ # picture1 picture2 article1
205
+ Tag.get("tag1").tagged_count(:by => "User").should == 3
206
+ # picture1
207
+ Tag.get("tag1").tagged_count(:by => Bot).should == 1
208
+ # article1 and picture1
209
+ Tag.get("tag1").tagged_count(:by => @user1).should == 2
210
+
211
+ Tag.get("tag1").tagged_count(:by =>@user1, :on => Picture) == 1
212
+ end
213
+
214
+ it "should be able to retrieve tags by the specified relation object" do
215
+ Tag.by(@user1).sort.should == [Tag.get("tag1"), Tag.get("tag2"), Tag.get("tag3"), Tag.get("tag4"), Tag.get("tag5")].sort
216
+ Tag.by(User).sort.should == [Tag.get("tag1"), Tag.get("tag2"), Tag.get("tag3"), Tag.get("tag4"), Tag.get("tag5"), Tag.get("tag10")].sort
217
+ Tag.on(@article).sort.should == [Tag.get("tag1"), Tag.get("tag4"), Tag.get("tag5")].sort
218
+ Tag.on(@picture1).by(@user2).sort.should == [Tag.get("tag2"), Tag.get("tag3"), Tag.get("tag10")].sort
219
+ end
220
+
221
+ it "should be able to retrieve specified tags by the specified relation object" do
222
+ Picture.find(:with =>"tag1", :by => @user1).should == [@picture1]
223
+ Picture.find(:with =>"tag2", :by => @user2).should == [@picture1]
224
+ Picture.find(:with => ["tag1", "tag2"], :by => @bot1, :match => :any).should == [@picture1]
225
+ end
226
+
227
+ it "should be able to retrieve all tags by the user" do
228
+ @user1.tags.size.should == 5
229
+ @user1.tags.include?(Tag.get("tag1")).should be_true
230
+ @user1.tags.include?(Tag.get("tag2")).should be_true
231
+ @user1.tags.include?(Tag.get("tag3")).should be_true
232
+ @user1.tags.include?(Tag.get("tag4")).should be_true
233
+ @user1.tags.include?(Tag.get("tag5")).should be_true
234
+ end
235
+
236
+ it "should be able to retrieve all objects tagged by the user" do
237
+ @user1.find_taggables(:with =>["tag1", "tag4"], :match => :any).should == [@article, @picture1]
238
+ @user1.find_taggables(:with =>["tag1", "tag4"], :match => :all).should == [@article]
239
+ end
240
+
241
+ it "should be able to retrieve all objects tagged with certain tag" do
242
+ Tag.find_taggables(:with => ["tag1", "tag4"]).should == [@article, @picture2]
243
+ Tag.find_taggables(:with => ["tag1", "tag4"], :match => :any).should == [@article, @picture1, @picture2]
244
+ end
245
+
246
+ it "should be able to retrieve taggable_objects of user with specified tags" do
247
+ @user2.find_taggables(:with => "tag1").should == [@picture2]
248
+ end
249
+
250
+ it "should be able to retrieve how many times the user used the tag" do
251
+ Tag.tagged_count(:by => @user1, :on => @article, :with => "tag1").should == 1
252
+ Tag.tagged_count(:by => Bot, :with => "tag1").should == 1
253
+ Tag.tagged_count(:by => @user1, :with => "tag1").should == 2
254
+ Tag.tagged_count(:by => @user1).should == 2
255
+ Tag.tagged_count(:by => User).should == 3
256
+ Tag.tagged_count.should == 3
257
+ end
258
+
259
+ it "should be able to retrieve the most association (in this case user) popular by tags for a certain tag" do
260
+ # This returns a list of taggers with descending order of tag count
261
+ Tag.get("tag1").popular_by_tags.should == [@user1, @user2, @bot1] # should return array and calculate this based upon the usage of the tag
262
+ end
263
+
264
+ it "should be able to retrieve related tags that where used in the same set" do
265
+ related_tags = Tag.get("tag3").related
266
+ related_tags.size.should == 2
267
+ related_tags.include?([2,Tag.get("tag1")]).should be_true
268
+ related_tags.include?([2,Tag.get("tag2")]).should be_true
269
+
270
+ related_tags = Tag.get("tag1").related
271
+ related_tags.size.should == 4
272
+ related_tags.include?([2,Tag.get("tag2")]).should be_true
273
+ related_tags.include?([3,Tag.get("tag3")]).should be_true
274
+ related_tags.include?([2,Tag.get("tag4")]).should be_true
275
+ related_tags.include?([2,Tag.get("tag5")]).should be_true
276
+ end
277
+
278
+ it "should be able to retrieve the times that tags where used in the same set" do
279
+ # tag1 and tag3 are tagged together 2 times by user1 and bot1
280
+
281
+ # I think you just want to find the counts on related tags...
282
+ # So what I did was to include the number of counts on Tags#related
283
+ related_tags = Tag.get("tag3").related
284
+ related_tags.size.should == 2
285
+ related_tags.include?([2,Tag.get("tag1")]).should be_true
286
+ related_tags.include?([2,Tag.get("tag2")]).should be_true
287
+ end
288
+ end
289
+ end
@@ -0,0 +1,40 @@
1
+ require 'pathname'
2
+ require Pathname(__FILE__).dirname.expand_path.parent + 'spec_helper'
3
+
4
+ if HAS_SQLITE3 || HAS_MYSQL || HAS_POSTGRES
5
+ describe 'DataMapper::Is::Taggable' do
6
+ before(:all) do
7
+ DataMapper.auto_migrate!
8
+ @user1 = User.create(:name => "user1")
9
+ @user2 = User.create(:name => "user2")
10
+ @user3 = User.create(:name => "user3")
11
+ @user4 = User.create(:name => "user4")
12
+
13
+ @picture1 = Picture.create
14
+ @picture1.tag(:by => @user1, :with => "tag1, tag2, tag3, tag4")
15
+ @picture1.tag(:by => @user2, :with => "tag1, tag2, tag3")
16
+ @picture1.tag(:by => @user4, :with => "weird")
17
+
18
+ @picture2 = Picture.create
19
+ @user2.tag(:on=>@picture2, :with => ["tag1", "tag2", "tag4", "tag5", "tag6", "tag7", "tag8"])
20
+ @user3.tag(:on => @picture2, :with => ["tag4", "tag5", "tag6", "tag7", "tag8"])
21
+ end
22
+
23
+ it "should be able to retrieve similar users with same kind of tagging behavior sorted on similarity" do
24
+ # user1 and user2 are sharing tag1, tag2, tag3 and tag4 (4 tags total)
25
+ # user1 and user3 are sharing tag4 (1 tag total)
26
+ @user1.all_similar_by_tags.should == [[4, @user2], [1, @user3]]
27
+
28
+ # user2 and user3 are sharing tag4, tag5, tag6, tag7 and tag8 (5 tags total)
29
+ # user2 and user1 are sharing tag1, tag2, tag3 and tag4 (4 tags total)
30
+ @user2.all_similar_by_tags.should == [[5, @user3], [4, @user1]]
31
+
32
+ # user3 and user2 are sharing tag4, tag5, tag6, tag7 and tag8 (5 tags total)
33
+ # user3 and user1 are sharing tag4 (1 tag total)
34
+ @user3.all_similar_by_tags.should == [[5, @user2], [1, @user1]]
35
+
36
+ # check if user4 is alone in the dark
37
+ @user4.all_similar_by_tags.should be_empty
38
+ end
39
+ end
40
+ end
data/spec/spec.opts ADDED
@@ -0,0 +1,2 @@
1
+ --format specdoc
2
+ --colour
@@ -0,0 +1,36 @@
1
+ require 'rubygems'
2
+ gem 'rspec', '>=1.1.3'
3
+ require 'spec'
4
+ require 'pathname'
5
+ require Pathname(__FILE__).dirname.expand_path.parent + 'lib/dm-is-taggable'
6
+
7
+ def load_driver(name, default_uri)
8
+ return false if ENV['ADAPTER'] != name.to_s
9
+
10
+ lib = "do_#{name}"
11
+
12
+ begin
13
+ gem lib, '>=0.9.5'
14
+ require lib
15
+ DataMapper.setup(name, ENV["#{name.to_s.upcase}_SPEC_URI"] || default_uri)
16
+ DataMapper::Repository.adapters[:default] = DataMapper::Repository.adapters[name]
17
+ true
18
+ rescue Gem::LoadError => e
19
+ warn "Could not load #{lib}: #{e}"
20
+ false
21
+ end
22
+ end
23
+
24
+ ENV['ADAPTER'] ||= 'mysql'
25
+
26
+ HAS_SQLITE3 = load_driver(:sqlite3, 'sqlite3::memory:')
27
+ HAS_MYSQL = load_driver(:mysql, 'mysql://root@localhost/dm_is_taggable_test')
28
+ HAS_POSTGRES = load_driver(:postgres, 'postgres://maxime@localhost/dm_is_taggable_test')
29
+
30
+ require "dm-types"
31
+ require "dm-aggregates"
32
+
33
+ require Pathname(__FILE__).dirname.expand_path / 'data' / 'bot'
34
+ require Pathname(__FILE__).dirname.expand_path / 'data' / 'user'
35
+ require Pathname(__FILE__).dirname.expand_path / 'data' / 'picture'
36
+ require Pathname(__FILE__).dirname.expand_path / 'data' / 'article'
metadata ADDED
@@ -0,0 +1,110 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: genki-dm-is-taggable
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Aaron Qian, Maxime Guilbot
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-04-25 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: dm-core
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - "="
22
+ - !ruby/object:Gem::Version
23
+ version: 0.9.6
24
+ version:
25
+ - !ruby/object:Gem::Dependency
26
+ name: dm-aggregates
27
+ type: :runtime
28
+ version_requirement:
29
+ version_requirements: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "="
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.6
34
+ version:
35
+ - !ruby/object:Gem::Dependency
36
+ name: hoe
37
+ type: :development
38
+ version_requirement:
39
+ version_requirements: !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ">="
42
+ - !ruby/object:Gem::Version
43
+ version: 1.12.1
44
+ version:
45
+ description: Tagging implementation for DataMapper
46
+ email:
47
+ - team [a] ekohe [d] com
48
+ executables: []
49
+
50
+ extensions: []
51
+
52
+ extra_rdoc_files:
53
+ - README.textile
54
+ - LICENSE
55
+ - TODO
56
+ files:
57
+ - History.txt
58
+ - LICENSE
59
+ - Manifest.txt
60
+ - README.textile
61
+ - Rakefile
62
+ - TODO
63
+ - lib/dm-is-taggable.rb
64
+ - lib/dm-is-taggable/aggregate_patch.rb
65
+ - lib/dm-is-taggable/tag.rb
66
+ - lib/dm-is-taggable/tagging.rb
67
+ - lib/dm-is-taggable/tag_list.rb
68
+ - lib/dm-is-taggable/is/taggable.rb
69
+ - lib/dm-is-taggable/is/version.rb
70
+ - lib/dm-is-taggable/is/shared.rb
71
+ - lib/dm-is-taggable/is/tag.rb
72
+ - lib/dm-is-taggable/is/tagging.rb
73
+ - lib/dm-is-taggable/is/tagger.rb
74
+ - spec/integration/taggable_spec.rb
75
+ - spec/integration/tagger_similarity_spec.rb
76
+ - spec/data/article.rb
77
+ - spec/data/picture.rb
78
+ - spec/data/bot.rb
79
+ - spec/data/user.rb
80
+ - spec/spec.opts
81
+ - spec/spec_helper.rb
82
+ has_rdoc: false
83
+ homepage: http://github.com/aq1018/dm-is-taggable
84
+ post_install_message:
85
+ rdoc_options:
86
+ - --main
87
+ - README.txt
88
+ require_paths:
89
+ - lib
90
+ required_ruby_version: !ruby/object:Gem::Requirement
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ version: "0"
95
+ version:
96
+ required_rubygems_version: !ruby/object:Gem::Requirement
97
+ requirements:
98
+ - - ">="
99
+ - !ruby/object:Gem::Version
100
+ version: "0"
101
+ version:
102
+ requirements: []
103
+
104
+ rubyforge_project: dm-is-taggable
105
+ rubygems_version: 1.2.0
106
+ signing_key:
107
+ specification_version: 2
108
+ summary: Tagging implementation for DataMapper
109
+ test_files: []
110
+