rocket_tag 0.2.0 → 0.3.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.
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"