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 +35 -0
- data/VERSION +1 -1
- data/lib/rocket_tag/taggable.rb +37 -6
- data/rocket_tag.gemspec +2 -2
- data/spec/rocket_tag/taggable_spec.rb +43 -4
- metadata +3 -3
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.
|
1
|
+
0.3.1
|
data/lib/rocket_tag/taggable.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
95
|
-
|
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.
|
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-
|
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
|
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.
|
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-
|
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:
|
147
|
+
hash: 2545152122915663382
|
148
148
|
segments:
|
149
149
|
- 0
|
150
150
|
version: "0"
|