tagtical 1.3.1 → 1.4.0
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/VERSION +1 -1
- data/lib/tagtical/tag.rb +13 -0
- data/lib/tagtical/taggable/core.rb +37 -26
- data/lib/tagtical/taggable/ownership.rb +2 -1
- data/lib/tagtical/tagging.rb +13 -5
- data/spec/tagtical/taggable_spec.rb +19 -0
- data/spec/tagtical/tagging_spec.rb +13 -2
- metadata +13 -13
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.4.0
|
data/lib/tagtical/tag.rb
CHANGED
@@ -141,6 +141,11 @@ module Tagtical
|
|
141
141
|
!!tag_types_for_questioner_method(method_id) || super
|
142
142
|
end
|
143
143
|
|
144
|
+
# Carried over from tagging.
|
145
|
+
def has_tagger?
|
146
|
+
!self[:tagger_id].nil?
|
147
|
+
end
|
148
|
+
|
144
149
|
private
|
145
150
|
|
146
151
|
def tag_types_for_questioner_method(method_name)
|
@@ -297,6 +302,14 @@ module Tagtical
|
|
297
302
|
"@#{tag_list_name(*args)}"
|
298
303
|
end
|
299
304
|
|
305
|
+
def all_tag_list_ivar
|
306
|
+
tag_list_ivar(:all)
|
307
|
+
end
|
308
|
+
|
309
|
+
def scope_ivar
|
310
|
+
"@#{scope_name}"
|
311
|
+
end
|
312
|
+
|
300
313
|
# Returns the level from which it extends from Tagtical::Tag
|
301
314
|
def active_record_sti_level
|
302
315
|
@active_record_sti_level ||= begin
|
@@ -15,7 +15,7 @@ module Tagtical::Taggable
|
|
15
15
|
def initialize_tagtical_core
|
16
16
|
has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "Tagtical::Tagging"
|
17
17
|
has_many :tags, :through => :taggings, :source => :tag, :class_name => "Tagtical::Tag",
|
18
|
-
:select => "#{Tagtical::Tag.table_name}.*, #{Tagtical::Tagging.table_name}.relevance" # include the relevance on the tags
|
18
|
+
:select => "#{Tagtical::Tag.table_name}.*, #{Tagtical::Tagging.table_name}.relevance, #{Tagtical::Tagging.table_name}.tagger_id" # include the relevance on the tags
|
19
19
|
|
20
20
|
tag_types.each do |tag_type| # has_many :tags gets created here
|
21
21
|
|
@@ -67,18 +67,21 @@ module Tagtical::Taggable
|
|
67
67
|
define_method("tags_with_finder_type_options") do |*args|
|
68
68
|
bool = args.shift if [true, false].include?(args.first)
|
69
69
|
tags = tags_without_finder_type_options(bool)
|
70
|
-
args.empty? ? tags :
|
70
|
+
args.empty? ? tags : tags_with_type_scoping(tag_type, *args)
|
71
71
|
end
|
72
72
|
alias_method_chain :tags, :finder_type_options
|
73
|
-
else
|
74
|
-
define_method(tag_type.
|
75
|
-
|
76
|
-
|
77
|
-
(
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
73
|
+
else # handle the Tagtical::Tag subclasses
|
74
|
+
define_method(tag_type.scope_name) do |*args|
|
75
|
+
if args.empty?
|
76
|
+
instance_variable_get(tag_type.scope_ivar) || instance_variable_set(tag_type.scope_ivar,
|
77
|
+
tags.scoped.merge(tag_type.scoping).tap do |scope|
|
78
|
+
if (loaded_parent_scope = tag_type.expand_tag_types(:parents).map { |t| tag_scope(t) }.detect(&:loaded?))
|
79
|
+
scope.instance_variable_set(:@loaded, true)
|
80
|
+
scope.instance_variable_set(:@records, loaded_parent_scope.select { |t| t.class <= tag_type.klass })
|
81
|
+
end
|
82
|
+
end)
|
83
|
+
else
|
84
|
+
tags_with_type_scoping(tag_type, *args)
|
82
85
|
end
|
83
86
|
end
|
84
87
|
end
|
@@ -249,16 +252,17 @@ module Tagtical::Taggable
|
|
249
252
|
##
|
250
253
|
# Returns all tags that aren't owned.
|
251
254
|
def tags_on(context, *args)
|
252
|
-
tag_scope(context, *args)
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
instance_variable_set(tag_type.tag_list_ivar, nil)
|
258
|
-
instance_variable_set(tag_type.tag_list_ivar(:all), nil)
|
255
|
+
scope = tag_scope(context, *args)
|
256
|
+
if args.empty?
|
257
|
+
scope.reject(&:has_tagger?)
|
258
|
+
else
|
259
|
+
scope.where("#{Tagtical::Tagging.table_name}.tagger_id IS NULL").all
|
259
260
|
end
|
261
|
+
end
|
260
262
|
|
261
|
-
|
263
|
+
def reload(*)
|
264
|
+
remove_tag_caches_on(tag_types)
|
265
|
+
super
|
262
266
|
end
|
263
267
|
|
264
268
|
def save_tags
|
@@ -279,7 +283,7 @@ module Tagtical::Taggable
|
|
279
283
|
current_tags = tags_on(tag_type, :types => expanded_tag_types, :scope => :parents) # add in the parents because we need them later on down.
|
280
284
|
old_tags = current_tags - tags
|
281
285
|
new_tags = tags - current_tags
|
282
|
-
|
286
|
+
|
283
287
|
unowned_taggings = taggings.where(:tagger_id => nil)
|
284
288
|
|
285
289
|
# If relevances are specified on current tags, make sure to update those
|
@@ -303,7 +307,7 @@ module Tagtical::Taggable
|
|
303
307
|
taggings.create!(:tag_id => tag.id, :taggable => self, :relevance => tag_value_lookup[tag].relevance) # Create new taggings:
|
304
308
|
end
|
305
309
|
end
|
306
|
-
|
310
|
+
|
307
311
|
# Force tag lists to reload to integrate any new tags from inheritance.
|
308
312
|
remove_tag_caches_on(tag_type)
|
309
313
|
end
|
@@ -313,15 +317,17 @@ module Tagtical::Taggable
|
|
313
317
|
|
314
318
|
private
|
315
319
|
|
316
|
-
def remove_tag_caches_on(
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
+
def remove_tag_caches_on(tag_types)
|
321
|
+
Array(tag_types).each do |tag_type|
|
322
|
+
[:all_tag_list_ivar, :tag_list_ivar, :scope_ivar].each do |ivar_method|
|
323
|
+
ivar = tag_type.send(ivar_method)
|
324
|
+
remove_instance_variable(ivar) if instance_variable_defined?(ivar)
|
325
|
+
end
|
320
326
|
end
|
321
327
|
end
|
322
328
|
|
323
329
|
def tag_scope(input, *args)
|
324
|
-
|
330
|
+
send(find_tag_type!(input).scope_name, *args)
|
325
331
|
end
|
326
332
|
|
327
333
|
def find_tag_type!(input)
|
@@ -332,6 +338,11 @@ module Tagtical::Taggable
|
|
332
338
|
(@expand_tag_types ||= {})[[input, args]] ||= find_tag_type!(input).expand_tag_types(*args)
|
333
339
|
end
|
334
340
|
|
341
|
+
|
342
|
+
def tags_with_type_scoping(tag_type, *args)
|
343
|
+
tags.scoped.merge(tag_type.scoping(*args))
|
344
|
+
end
|
345
|
+
|
335
346
|
# Lets say tag class A inherits from B and B has a tag with value "foo". If we tag A with value "foo",
|
336
347
|
# we want B to have only one instance of "foo" and that tag should be an instance of A (a subclass of B).
|
337
348
|
def update_tagging_with_inherited_tag!(tagging, tags, tag_value_lookup)
|
@@ -57,7 +57,8 @@ module Tagtical::Taggable
|
|
57
57
|
|
58
58
|
def reload(*args)
|
59
59
|
tag_types.each do |tag_type|
|
60
|
-
|
60
|
+
ivar = tag_type.tag_list_ivar(:owned)
|
61
|
+
remove_instance_variable(ivar) if instance_variable_defined?(ivar)
|
61
62
|
end
|
62
63
|
|
63
64
|
super(*args)
|
data/lib/tagtical/tagging.rb
CHANGED
@@ -22,13 +22,12 @@ module Tagtical
|
|
22
22
|
belongs_to :tagger, :polymorphic => true
|
23
23
|
else
|
24
24
|
belongs_to :tagger, case Tagtical.config.tagger
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
when Hash then Tagtical.config.tagger
|
26
|
+
when true then {:class_name => "User"} # default to using User class.
|
27
|
+
when String then {:class_name => Tagtical.config.tagger}
|
28
|
+
end
|
29
29
|
end
|
30
30
|
|
31
|
-
|
32
31
|
before_create { |record| record.relevance ||= default_relevance }
|
33
32
|
|
34
33
|
class_attribute :default_relevance, :instance_writer => false
|
@@ -38,5 +37,14 @@ module Tagtical
|
|
38
37
|
relevance <=> tagging.relevance
|
39
38
|
end
|
40
39
|
|
40
|
+
def set_tag_target_with_relevance(tag)
|
41
|
+
if tag
|
42
|
+
tag.relevance = relevance
|
43
|
+
tag[:tagger_id] = tagger_id
|
44
|
+
end
|
45
|
+
set_tag_target_without_relevance(tag)
|
46
|
+
end
|
47
|
+
alias_method_chain :set_tag_target, :relevance
|
48
|
+
|
41
49
|
end
|
42
50
|
end
|
@@ -187,6 +187,25 @@ describe Tagtical::Taggable do
|
|
187
187
|
end
|
188
188
|
end
|
189
189
|
|
190
|
+
describe "Eager Loading Tags" do
|
191
|
+
before do
|
192
|
+
@taggable.update_attributes!(:craft_list => "foo:0.9, bar, car")
|
193
|
+
|
194
|
+
@taggables = TaggableModel.all(:include => :tags)
|
195
|
+
end
|
196
|
+
|
197
|
+
it "should leverage eager loaded tags for tag_list" do
|
198
|
+
ActiveRecord::Base.connection.expects(:execute).never
|
199
|
+
@taggables[0].tag_list
|
200
|
+
@taggables[0].craft_list
|
201
|
+
@taggables[0].skill_list
|
202
|
+
end
|
203
|
+
|
204
|
+
it "should populate relevance on tags" do
|
205
|
+
@taggables[0].craft_list.find("foo").relevance==0.9
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
190
209
|
describe "tag_list scoping behavior" do
|
191
210
|
before do
|
192
211
|
@taggables[0].tag_list = "bob"
|
@@ -4,7 +4,7 @@ describe Tagtical::Tagging do
|
|
4
4
|
before(:each) do
|
5
5
|
clean_database!
|
6
6
|
@klass = Tagtical::Tagging
|
7
|
-
@tagging = @klass.new
|
7
|
+
@tagging = @klass.new(:relevance => 4.0)
|
8
8
|
end
|
9
9
|
subject { @tagging }
|
10
10
|
|
@@ -48,5 +48,16 @@ describe Tagtical::Tagging do
|
|
48
48
|
2.times { @klass.create(:taggable => @taggable, :tag => @tag, :context => 'tags') }
|
49
49
|
}.should change(@klass, :count).by(1)
|
50
50
|
end
|
51
|
-
|
51
|
+
|
52
|
+
describe "#set_tag_target" do
|
53
|
+
before do
|
54
|
+
@tag = Tagtical::Tag.new(:value => "foo")
|
55
|
+
@tagging.set_tag_target(@tag)
|
56
|
+
end
|
57
|
+
|
58
|
+
it "should set relevance on tag" do
|
59
|
+
@tag.relevance.should==4.0
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
52
63
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tagtical
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.4.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -13,7 +13,7 @@ date: 2011-07-24 00:00:00.000000000Z
|
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: rails
|
16
|
-
requirement: &
|
16
|
+
requirement: &2152083200 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - <=
|
@@ -21,10 +21,10 @@ dependencies:
|
|
21
21
|
version: 3.0.5
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *2152083200
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: rspec
|
27
|
-
requirement: &
|
27
|
+
requirement: &2152082720 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - <=
|
@@ -32,10 +32,10 @@ dependencies:
|
|
32
32
|
version: 2.6.0
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *2152082720
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: sqlite3-ruby
|
38
|
-
requirement: &
|
38
|
+
requirement: &2152082240 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ! '>='
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '0'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *2152082240
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: mysql
|
49
|
-
requirement: &
|
49
|
+
requirement: &2152081760 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ! '>='
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: '0'
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *2152081760
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: jeweler
|
60
|
-
requirement: &
|
60
|
+
requirement: &2152081280 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: '0'
|
66
66
|
type: :runtime
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *2152081280
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rcov
|
71
|
-
requirement: &
|
71
|
+
requirement: &2152080800 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ! '>='
|
@@ -76,7 +76,7 @@ dependencies:
|
|
76
76
|
version: '0'
|
77
77
|
type: :runtime
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *2152080800
|
80
80
|
description: Tagtical allows you do create subclasses for Tag and add additional functionality
|
81
81
|
in an STI fashion. For example. You could do Tag::Color.find_by_name('blue').to_rgb.
|
82
82
|
It also supports storing weights or relevance on the taggings.
|