rocket_tag 0.2.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -48,10 +48,45 @@ Usage
48
48
  # Match a miniumum number of tags
49
49
  TaggableModel.tagged_with ["math", "kiting", "coding", "sleeping"], :min => 2, :on => "skills"
50
50
 
51
+ # Take advantage of the tags_count synthetic column returned with every query
52
+ TaggableModel.tagged_with(["math", "kiting", "coding", "sleeping"], :on => "skills").where{tags_count>=2}
51
53
 
52
54
  # Mix with active relation
53
55
  TaggableModel.tagged_with(["forking", "kiting"]).where( ["created_at > ?", Time.zone.now.ago(5.hours)])
54
56
 
57
+ # Find similar models based on tags on a specific context and return in decending order
58
+ # of 'tags_count'
59
+ model.find_similar :on => "skills"
60
+ model.find_similar :on => "habits"
61
+
62
+ # Find similar models based on tags on every context and return in decending order
63
+ # of 'tags_count'. Note that each tag is still scoped according to it's context
64
+ model.find_similar
65
+
66
+ # For reference the SQL generated for model.find_similar when there are
67
+ # context [:skills, :languages] available is
68
+
69
+ SELECT "taggable_models".* FROM
70
+ (
71
+ SELECT COUNT("taggable_models"."id") AS tags_count,
72
+ taggable_models.*
73
+ FROM "taggable_models"
74
+ INNER JOIN "taggings"
75
+ ON "taggings"."taggable_id" = "taggable_models"."id"
76
+ AND "taggings"."taggable_type" = 'TaggableModel'
77
+ INNER JOIN "tags"
78
+ ON "tags"."id" = "taggings"."tag_id"
79
+ WHERE "taggable_models"."id" != 2
80
+ AND (( ( "tags"."name" IN ( 'german', 'french' ) AND "taggings"."context" = 'languages' )
81
+ OR ( "tags"."name" IN ( 'a', 'b', 'x' ) AND "taggings"."context" = 'skills' )
82
+ ))
83
+ GROUP BY "taggable_models"."id"
84
+ ORDER BY tags_count DESC
85
+ ) taggable_models
86
+
87
+
88
+ # Note the aliasing of the inner select to shield the GROUP BY from downstream active relation
89
+ # queries
55
90
 
56
91
  == Contributing to rocket_tag
57
92
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.1
@@ -4,7 +4,7 @@ module RocketTag
4
4
  module Taggable
5
5
  def self.included(base)
6
6
  base.extend ClassMethods
7
- base.send :include, InstanceMethods
7
+ #base.send :include, InstanceMethods
8
8
  end
9
9
 
10
10
  class Manager
@@ -80,19 +80,45 @@ module RocketTag
80
80
  @contexts ||= {}
81
81
  @contexts[context.to_sym] || []
82
82
  end
83
- end
84
83
 
85
- module InstanceMethods
86
84
  def tagged_similar options = {}
87
85
  context = options.delete :on
88
- raise Exception.new("#{context} is not a valid tag context for #{self.class}") unless self.class.rocket_tag.contexts.include? context
86
+ if context
87
+ raise Exception.new("#{context} is not a valid tag context for #{self.class}") unless self.class.rocket_tag.contexts.include? context
88
+ end
89
89
  if context
90
90
  contexts = [context]
91
91
  else
92
92
  contexts = self.class.rocket_tag.contexts
93
93
  end
94
- tags = send context.to_sym
95
- self.class.tagged_with(tags, options).where{id != my{id}}
94
+
95
+ if contexts.size > 1
96
+ contexts = contexts.delete :tag
97
+ end
98
+
99
+ contexts = contexts.reject do |c|
100
+ send(c.to_sym).size == 0
101
+ end
102
+
103
+ conditions = contexts.map do |context|
104
+ _tags = send context.to_sym
105
+ self.class.squeel do
106
+ (tags.name.in(my{_tags}) & (taggings.context == my{context}))
107
+ end
108
+ end
109
+
110
+ condition = conditions.inject do |s, t|
111
+ s | t
112
+ end
113
+
114
+ inner = self.class.select{count(~id).as(tags_count)}.
115
+ select("#{self.class.table_name}.*").
116
+ joins{tags}.where{condition}.
117
+ group{~id}.
118
+ where{~id != my{id}}.
119
+ order("tags_count DESC")
120
+
121
+ r = self.class.from("(#{inner.to_sql}) #{self.class.table_name}")
96
122
  end
97
123
  end
98
124
 
@@ -201,7 +227,12 @@ module RocketTag
201
227
  end
202
228
  end
203
229
 
230
+ @@acts_as_rocket_tag = false
204
231
  def attr_taggable *contexts
232
+ unless @@acts_as_rocket_tag
233
+ include RocketTag::Taggable::InstanceMethods
234
+ @@acts_as_rocket_tag = true
235
+ end
205
236
 
206
237
  if contexts.blank?
207
238
  contexts = [:tag]
data/rocket_tag.gemspec CHANGED
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = "rocket_tag"
8
- s.version = "0.2.0"
8
+ s.version = "0.3.1"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Brad Phelan"]
12
- s.date = "2012-01-24"
12
+ s.date = "2012-01-25"
13
13
  s.description = ""
14
14
  s.email = "bradphelan@xtargets.com"
15
15
  s.extra_rdoc_files = [
@@ -100,6 +100,7 @@ describe TaggableModel do
100
100
  @t01.languages = [ "german" , "italian"]
101
101
 
102
102
  @t10.skills = [ "a" , "c"]
103
+ @t10.languages = [ "french" , "hebrew"]
103
104
 
104
105
  @t11.skills = [ "a" , "c"]
105
106
 
@@ -165,9 +166,47 @@ describe TaggableModel do
165
166
  end
166
167
 
167
168
  describe "#tagged_similar" do
168
- it "should work" do
169
+ it "should return similar items" do
169
170
  @t00.tagged_similar(:on => :skills).count.should == 3
171
+ @t00.tagged_similar(:on => :languages).count.should == 3
172
+ @t00.tagged_similar.count.should == 4
170
173
  end
174
+
175
+ it "should return similar items in the correct order with the correct tags_count" do
176
+
177
+ # ----
178
+ similar = @t00.tagged_similar(:on => :skills).all
179
+ similar[0].id.should == @t01.id
180
+ similar[1].id.should == @t10.id
181
+ similar[2].id.should == @t11.id
182
+
183
+ similar[0].tags_count.should == 2
184
+ similar[1].tags_count.should == 1
185
+ similar[2].tags_count.should == 1
186
+
187
+ # ----
188
+ similar = @t00.tagged_similar(:on => :languages).all
189
+ similar[0].id.should == @t01.id
190
+ similar[1].id.should == @t10.id
191
+ similar[2].id.should == @t21.id
192
+
193
+ similar[0].tags_count.should == 1
194
+ similar[1].tags_count.should == 1
195
+ similar[2].tags_count.should == 1
196
+
197
+ # ----
198
+ similar = @t00.tagged_similar.all
199
+ similar[0].id.should == @t01.id
200
+ similar[1].id.should == @t10.id
201
+ similar[2].id.should == @t11.id
202
+ similar[3].id.should == @t21.id
203
+
204
+ similar[0].tags_count.should == 3
205
+ similar[1].tags_count.should == 2
206
+ similar[2].tags_count.should == 1
207
+ similar[3].tags_count.should == 1
208
+ end
209
+
171
210
  end
172
211
 
173
212
  describe "#tagged_with" do
@@ -237,8 +276,9 @@ describe TaggableModel do
237
276
  l_t[:user_id].count.as("count_all")
238
277
  ).as "foo"
239
278
 
240
- puts TaggableModel.joins("JOIN " + counts.to_sql ).to_sql
279
+ #puts TaggableModel.joins("JOIN " + counts.to_sql ).to_sql
241
280
  end
281
+
242
282
  it "should" do
243
283
  u_t = Arel::Table::new :users
244
284
  l_t = Arel::Table::new :logs
@@ -256,7 +296,7 @@ describe TaggableModel do
256
296
  eq(counts[:user_id])).
257
297
  project("*").project(counts[:count_all])
258
298
 
259
- puts users.to_sql
299
+ # puts users.to_sql
260
300
 
261
301
  end
262
302
  end
@@ -270,7 +310,6 @@ describe TaggableModel do
270
310
  x = TaggableModel.where do
271
311
  TaggableModel.tagged_with_sifter(["a", "b"]) & TaggableModel.tagged_with_sifter(["c"])
272
312
  end.to_sql
273
- puts x
274
313
 
275
314
  TaggableModel.where do
276
315
  TaggableModel.tagged_with_sifter(["a", "b"])
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: rocket_tag
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.2.0
5
+ version: 0.3.1
6
6
  platform: ruby
7
7
  authors:
8
8
  - Brad Phelan
@@ -10,7 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2012-01-24 00:00:00 Z
13
+ date: 2012-01-25 00:00:00 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -144,7 +144,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
144
144
  requirements:
145
145
  - - ">="
146
146
  - !ruby/object:Gem::Version
147
- hash: -1107478710277863404
147
+ hash: 2545152122915663382
148
148
  segments:
149
149
  - 0
150
150
  version: "0"