acts_as_taggable_on 3.0.0.rc1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +15 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +9 -0
- data/Appraisals +7 -0
- data/Gemfile +5 -0
- data/Guardfile +5 -0
- data/LICENSE.md +20 -0
- data/README.md +309 -0
- data/Rakefile +13 -0
- data/UPGRADING +7 -0
- data/acts_as_taggable_on.gemspec +35 -0
- data/db/migrate/1_acts_as_taggable_on_migration.rb +30 -0
- data/db/migrate/2_add_missing_unique_indices.rb +21 -0
- data/gemfiles/rails_3.gemfile +8 -0
- data/gemfiles/rails_4.gemfile +8 -0
- data/lib/acts_as_taggable_on.rb +61 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +82 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +187 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/compatibility.rb +34 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +394 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +37 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +135 -0
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +84 -0
- data/lib/acts_as_taggable_on/engine.rb +6 -0
- data/lib/acts_as_taggable_on/tag.rb +119 -0
- data/lib/acts_as_taggable_on/tag_list.rb +101 -0
- data/lib/acts_as_taggable_on/taggable.rb +105 -0
- data/lib/acts_as_taggable_on/tagger.rb +76 -0
- data/lib/acts_as_taggable_on/tagging.rb +34 -0
- data/lib/acts_as_taggable_on/tags_helper.rb +15 -0
- data/lib/acts_as_taggable_on/utils.rb +34 -0
- data/lib/acts_as_taggable_on/version.rb +4 -0
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +265 -0
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +114 -0
- data/spec/acts_as_taggable_on/caching_spec.rb +77 -0
- data/spec/acts_as_taggable_on/related_spec.rb +143 -0
- data/spec/acts_as_taggable_on/single_table_inheritance_spec.rb +187 -0
- data/spec/acts_as_taggable_on/tag_list_spec.rb +126 -0
- data/spec/acts_as_taggable_on/tag_spec.rb +211 -0
- data/spec/acts_as_taggable_on/taggable_spec.rb +623 -0
- data/spec/acts_as_taggable_on/tagger_spec.rb +137 -0
- data/spec/acts_as_taggable_on/tagging_spec.rb +28 -0
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +44 -0
- data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
- data/spec/bm.rb +52 -0
- data/spec/database.yml.sample +19 -0
- data/spec/models.rb +58 -0
- data/spec/schema.rb +65 -0
- data/spec/spec_helper.rb +87 -0
- metadata +248 -0
@@ -0,0 +1,105 @@
|
|
1
|
+
module ActsAsTaggableOn
|
2
|
+
module Taggable
|
3
|
+
def taggable?
|
4
|
+
false
|
5
|
+
end
|
6
|
+
|
7
|
+
##
|
8
|
+
# This is an alias for calling <tt>acts_as_taggable_on :tags</tt>.
|
9
|
+
#
|
10
|
+
# Example:
|
11
|
+
# class Book < ActiveRecord::Base
|
12
|
+
# acts_as_taggable
|
13
|
+
# end
|
14
|
+
def acts_as_taggable
|
15
|
+
acts_as_taggable_on :tags
|
16
|
+
end
|
17
|
+
|
18
|
+
##
|
19
|
+
# This is an alias for calling <tt>acts_as_ordered_taggable_on :tags</tt>.
|
20
|
+
#
|
21
|
+
# Example:
|
22
|
+
# class Book < ActiveRecord::Base
|
23
|
+
# acts_as_ordered_taggable
|
24
|
+
# end
|
25
|
+
def acts_as_ordered_taggable
|
26
|
+
acts_as_ordered_taggable_on :tags
|
27
|
+
end
|
28
|
+
|
29
|
+
##
|
30
|
+
# Make a model taggable on specified contexts.
|
31
|
+
#
|
32
|
+
# @param [Array] tag_types An array of taggable contexts
|
33
|
+
#
|
34
|
+
# Example:
|
35
|
+
# class User < ActiveRecord::Base
|
36
|
+
# acts_as_taggable_on :languages, :skills
|
37
|
+
# end
|
38
|
+
def acts_as_taggable_on(*tag_types)
|
39
|
+
taggable_on(false, tag_types)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
##
|
44
|
+
# Make a model taggable on specified contexts
|
45
|
+
# and preserves the order in which tags are created
|
46
|
+
#
|
47
|
+
# @param [Array] tag_types An array of taggable contexts
|
48
|
+
#
|
49
|
+
# Example:
|
50
|
+
# class User < ActiveRecord::Base
|
51
|
+
# acts_as_ordered_taggable_on :languages, :skills
|
52
|
+
# end
|
53
|
+
def acts_as_ordered_taggable_on(*tag_types)
|
54
|
+
taggable_on(true, tag_types)
|
55
|
+
end
|
56
|
+
|
57
|
+
private
|
58
|
+
|
59
|
+
# Make a model taggable on specified contexts
|
60
|
+
# and optionally preserves the order in which tags are created
|
61
|
+
#
|
62
|
+
# Seperate methods used above for backwards compatibility
|
63
|
+
# so that the original acts_as_taggable_on method is unaffected
|
64
|
+
# as it's not possible to add another arguement to the method
|
65
|
+
# without the tag_types being enclosed in square brackets
|
66
|
+
#
|
67
|
+
# NB: method overridden in core module in order to create tag type
|
68
|
+
# associations and methods after this logic has executed
|
69
|
+
#
|
70
|
+
def taggable_on(preserve_tag_order, *tag_types)
|
71
|
+
tag_types = tag_types.to_a.flatten.compact.map(&:to_sym)
|
72
|
+
|
73
|
+
if taggable?
|
74
|
+
self.tag_types = (self.tag_types + tag_types).uniq
|
75
|
+
self.preserve_tag_order = preserve_tag_order
|
76
|
+
else
|
77
|
+
class_attribute :tag_types
|
78
|
+
self.tag_types = tag_types
|
79
|
+
class_attribute :preserve_tag_order
|
80
|
+
self.preserve_tag_order = preserve_tag_order
|
81
|
+
|
82
|
+
class_eval do
|
83
|
+
has_many :taggings, :as => :taggable, :dependent => :destroy, :class_name => "ActsAsTaggableOn::Tagging"
|
84
|
+
has_many :base_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag"
|
85
|
+
|
86
|
+
def self.taggable?
|
87
|
+
true
|
88
|
+
end
|
89
|
+
|
90
|
+
include ActsAsTaggableOn::Utils
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# each of these add context-specific methods and must be
|
95
|
+
# called on each call of taggable_on
|
96
|
+
include ActsAsTaggableOn::Taggable::Core
|
97
|
+
include ActsAsTaggableOn::Taggable::Collection
|
98
|
+
include ActsAsTaggableOn::Taggable::Cache
|
99
|
+
include ActsAsTaggableOn::Taggable::Ownership
|
100
|
+
include ActsAsTaggableOn::Taggable::Related
|
101
|
+
include ActsAsTaggableOn::Taggable::Dirty
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module ActsAsTaggableOn
|
2
|
+
module Tagger
|
3
|
+
def self.included(base)
|
4
|
+
base.extend ClassMethods
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
##
|
9
|
+
# Make a model a tagger. This allows an instance of a model to claim ownership
|
10
|
+
# of tags.
|
11
|
+
#
|
12
|
+
# Example:
|
13
|
+
# class User < ActiveRecord::Base
|
14
|
+
# acts_as_tagger
|
15
|
+
# end
|
16
|
+
def acts_as_tagger(opts={})
|
17
|
+
class_eval do
|
18
|
+
has_many_with_compatibility :owned_taggings,
|
19
|
+
opts.merge(
|
20
|
+
:as => :tagger,
|
21
|
+
:dependent => :destroy,
|
22
|
+
:class_name => "ActsAsTaggableOn::Tagging"
|
23
|
+
)
|
24
|
+
|
25
|
+
has_many_with_compatibility :owned_tags,
|
26
|
+
:through => :owned_taggings,
|
27
|
+
:source => :tag,
|
28
|
+
:class_name => "ActsAsTaggableOn::Tag",
|
29
|
+
:uniq => true
|
30
|
+
end
|
31
|
+
|
32
|
+
include ActsAsTaggableOn::Tagger::InstanceMethods
|
33
|
+
extend ActsAsTaggableOn::Tagger::SingletonMethods
|
34
|
+
end
|
35
|
+
|
36
|
+
def is_tagger?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
module InstanceMethods
|
42
|
+
##
|
43
|
+
# Tag a taggable model with tags that are owned by the tagger.
|
44
|
+
#
|
45
|
+
# @param taggable The object that will be tagged
|
46
|
+
# @param [Hash] options An hash with options. Available options are:
|
47
|
+
# * <tt>:with</tt> - The tags that you want to
|
48
|
+
# * <tt>:on</tt> - The context on which you want to tag
|
49
|
+
#
|
50
|
+
# Example:
|
51
|
+
# @user.tag(@photo, :with => "paris, normandy", :on => :locations)
|
52
|
+
def tag(taggable, opts={})
|
53
|
+
opts.reverse_merge!(:force => true)
|
54
|
+
skip_save = opts.delete(:skip_save)
|
55
|
+
return false unless taggable.respond_to?(:is_taggable?) && taggable.is_taggable?
|
56
|
+
|
57
|
+
raise "You need to specify a tag context using :on" unless opts.has_key?(:on)
|
58
|
+
raise "You need to specify some tags using :with" unless opts.has_key?(:with)
|
59
|
+
raise "No context :#{opts[:on]} defined in #{taggable.class.to_s}" unless (opts[:force] || taggable.tag_types.include?(opts[:on]))
|
60
|
+
|
61
|
+
taggable.set_owner_tag_list_on(self, opts[:on].to_s, opts[:with])
|
62
|
+
taggable.save unless skip_save
|
63
|
+
end
|
64
|
+
|
65
|
+
def is_tagger?
|
66
|
+
self.class.is_tagger?
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
module SingletonMethods
|
71
|
+
def is_tagger?
|
72
|
+
true
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ActsAsTaggableOn
|
2
|
+
class Tagging < ::ActiveRecord::Base #:nodoc:
|
3
|
+
attr_accessible :tag,
|
4
|
+
:tag_id,
|
5
|
+
:context,
|
6
|
+
:taggable,
|
7
|
+
:taggable_type,
|
8
|
+
:taggable_id,
|
9
|
+
:tagger,
|
10
|
+
:tagger_type,
|
11
|
+
:tagger_id if defined?(ActiveModel::MassAssignmentSecurity)
|
12
|
+
|
13
|
+
belongs_to :tag, :class_name => 'ActsAsTaggableOn::Tag'
|
14
|
+
belongs_to :taggable, :polymorphic => true
|
15
|
+
belongs_to :tagger, :polymorphic => true
|
16
|
+
|
17
|
+
validates_presence_of :context
|
18
|
+
validates_presence_of :tag_id
|
19
|
+
|
20
|
+
validates_uniqueness_of :tag_id, :scope => [ :taggable_type, :taggable_id, :context, :tagger_id, :tagger_type ]
|
21
|
+
|
22
|
+
after_destroy :remove_unused_tags
|
23
|
+
|
24
|
+
private
|
25
|
+
|
26
|
+
def remove_unused_tags
|
27
|
+
if ActsAsTaggableOn.remove_unused_tags
|
28
|
+
if tag.taggings.count.zero?
|
29
|
+
tag.destroy
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module ActsAsTaggableOn
|
2
|
+
module TagsHelper
|
3
|
+
# See the README for an example using tag_cloud.
|
4
|
+
def tag_cloud(tags, classes)
|
5
|
+
return [] if tags.empty?
|
6
|
+
|
7
|
+
max_count = tags.sort_by(&:count).last.count.to_f
|
8
|
+
|
9
|
+
tags.each do |tag|
|
10
|
+
index = ((tag.count / max_count) * (classes.size - 1))
|
11
|
+
yield tag, classes[index.nan? ? 0 : index.round]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module ActsAsTaggableOn
|
2
|
+
module Utils
|
3
|
+
def self.included(base)
|
4
|
+
|
5
|
+
base.send :include, ActsAsTaggableOn::Utils::OverallMethods
|
6
|
+
base.extend ActsAsTaggableOn::Utils::OverallMethods
|
7
|
+
end
|
8
|
+
|
9
|
+
module OverallMethods
|
10
|
+
def using_postgresql?
|
11
|
+
::ActiveRecord::Base.connection && ::ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
|
12
|
+
end
|
13
|
+
|
14
|
+
def using_sqlite?
|
15
|
+
::ActiveRecord::Base.connection && ::ActiveRecord::Base.connection.adapter_name == 'SQLite'
|
16
|
+
end
|
17
|
+
|
18
|
+
def sha_prefix(string)
|
19
|
+
Digest::SHA1.hexdigest("#{string}#{rand}")[0..6]
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
def like_operator
|
24
|
+
using_postgresql? ? 'ILIKE' : 'LIKE'
|
25
|
+
end
|
26
|
+
|
27
|
+
# escape _ and % characters in strings, since these are wildcards in SQL.
|
28
|
+
def escape_like(str)
|
29
|
+
str.gsub(/[!%_]/){ |x| '!' + x }
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,265 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
require 'spec_helper'
|
3
|
+
|
4
|
+
describe "Acts As Taggable On" do
|
5
|
+
before(:each) do
|
6
|
+
clean_database!
|
7
|
+
end
|
8
|
+
|
9
|
+
it "should provide a class method 'taggable?' that is false for untaggable models" do
|
10
|
+
UntaggableModel.should_not be_taggable
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "Taggable Method Generation To Preserve Order" do
|
14
|
+
before(:each) do
|
15
|
+
clean_database!
|
16
|
+
TaggableModel.tag_types = []
|
17
|
+
TaggableModel.preserve_tag_order = false
|
18
|
+
TaggableModel.acts_as_ordered_taggable_on(:ordered_tags)
|
19
|
+
@taggable = TaggableModel.new(:name => "Bob Jones")
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should respond 'true' to preserve_tag_order?" do
|
23
|
+
@taggable.class.preserve_tag_order?.should be_true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe "Taggable Method Generation" do
|
28
|
+
before(:each) do
|
29
|
+
clean_database!
|
30
|
+
TaggableModel.tag_types = []
|
31
|
+
TaggableModel.acts_as_taggable_on(:tags, :languages, :skills, :needs, :offerings)
|
32
|
+
@taggable = TaggableModel.new(:name => "Bob Jones")
|
33
|
+
end
|
34
|
+
|
35
|
+
it "should respond 'true' to taggable?" do
|
36
|
+
@taggable.class.should be_taggable
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should create a class attribute for tag types" do
|
40
|
+
@taggable.class.should respond_to(:tag_types)
|
41
|
+
end
|
42
|
+
|
43
|
+
it "should create an instance attribute for tag types" do
|
44
|
+
@taggable.should respond_to(:tag_types)
|
45
|
+
end
|
46
|
+
|
47
|
+
it "should have all tag types" do
|
48
|
+
@taggable.tag_types.should == [:tags, :languages, :skills, :needs, :offerings]
|
49
|
+
end
|
50
|
+
|
51
|
+
it "should create a class attribute for preserve tag order" do
|
52
|
+
@taggable.class.should respond_to(:preserve_tag_order?)
|
53
|
+
end
|
54
|
+
|
55
|
+
it "should create an instance attribute for preserve tag order" do
|
56
|
+
@taggable.should respond_to(:preserve_tag_order?)
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should respond 'false' to preserve_tag_order?" do
|
60
|
+
@taggable.class.preserve_tag_order?.should be_false
|
61
|
+
end
|
62
|
+
|
63
|
+
it "should generate an association for each tag type" do
|
64
|
+
@taggable.should respond_to(:tags, :skills, :languages)
|
65
|
+
end
|
66
|
+
|
67
|
+
it "should add tagged_with and tag_counts to singleton" do
|
68
|
+
TaggableModel.should respond_to(:tagged_with, :tag_counts)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should generate a tag_list accessor/setter for each tag type" do
|
72
|
+
@taggable.should respond_to(:tag_list, :skill_list, :language_list)
|
73
|
+
@taggable.should respond_to(:tag_list=, :skill_list=, :language_list=)
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should generate a tag_list accessor, that includes owned tags, for each tag type" do
|
77
|
+
@taggable.should respond_to(:all_tags_list, :all_skills_list, :all_languages_list)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe "Reloading" do
|
82
|
+
it "should save a model instantiated by Model.find" do
|
83
|
+
taggable = TaggableModel.create!(:name => "Taggable")
|
84
|
+
found_taggable = TaggableModel.find(taggable.id)
|
85
|
+
found_taggable.save
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
describe "Matching Contexts" do
|
90
|
+
it "should find objects with tags of matching contexts" do
|
91
|
+
taggable1 = TaggableModel.create!(:name => "Taggable 1")
|
92
|
+
taggable2 = TaggableModel.create!(:name => "Taggable 2")
|
93
|
+
taggable3 = TaggableModel.create!(:name => "Taggable 3")
|
94
|
+
|
95
|
+
taggable1.offering_list = "one, two"
|
96
|
+
taggable1.save!
|
97
|
+
|
98
|
+
taggable2.need_list = "one, two"
|
99
|
+
taggable2.save!
|
100
|
+
|
101
|
+
taggable3.offering_list = "one, two"
|
102
|
+
taggable3.save!
|
103
|
+
|
104
|
+
taggable1.find_matching_contexts(:offerings, :needs).should include(taggable2)
|
105
|
+
taggable1.find_matching_contexts(:offerings, :needs).should_not include(taggable3)
|
106
|
+
end
|
107
|
+
|
108
|
+
it "should find other related objects with tags of matching contexts" do
|
109
|
+
taggable1 = TaggableModel.create!(:name => "Taggable 1")
|
110
|
+
taggable2 = OtherTaggableModel.create!(:name => "Taggable 2")
|
111
|
+
taggable3 = OtherTaggableModel.create!(:name => "Taggable 3")
|
112
|
+
|
113
|
+
taggable1.offering_list = "one, two"
|
114
|
+
taggable1.save
|
115
|
+
|
116
|
+
taggable2.need_list = "one, two"
|
117
|
+
taggable2.save
|
118
|
+
|
119
|
+
taggable3.offering_list = "one, two"
|
120
|
+
taggable3.save
|
121
|
+
|
122
|
+
taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should include(taggable2)
|
123
|
+
taggable1.find_matching_contexts_for(OtherTaggableModel, :offerings, :needs).should_not include(taggable3)
|
124
|
+
end
|
125
|
+
|
126
|
+
it "should not include the object itself in the list of related objects with tags of matching contexts" do
|
127
|
+
taggable1 = TaggableModel.create!(:name => "Taggable 1")
|
128
|
+
taggable2 = TaggableModel.create!(:name => "Taggable 2")
|
129
|
+
|
130
|
+
taggable1.offering_list = "one, two"
|
131
|
+
taggable1.need_list = "one, two"
|
132
|
+
taggable1.save
|
133
|
+
|
134
|
+
taggable2.need_list = "one, two"
|
135
|
+
taggable2.save
|
136
|
+
|
137
|
+
taggable1.find_matching_contexts_for(TaggableModel, :offerings, :needs).should include(taggable2)
|
138
|
+
taggable1.find_matching_contexts_for(TaggableModel, :offerings, :needs).should_not include(taggable1)
|
139
|
+
end
|
140
|
+
|
141
|
+
end
|
142
|
+
|
143
|
+
describe 'Tagging Contexts' do
|
144
|
+
it 'should eliminate duplicate tagging contexts ' do
|
145
|
+
TaggableModel.acts_as_taggable_on(:skills, :skills)
|
146
|
+
TaggableModel.tag_types.freq[:skills].should_not == 3
|
147
|
+
end
|
148
|
+
|
149
|
+
it "should not contain embedded/nested arrays" do
|
150
|
+
TaggableModel.acts_as_taggable_on([:array], [:array])
|
151
|
+
TaggableModel.tag_types.freq[[:array]].should == 0
|
152
|
+
end
|
153
|
+
|
154
|
+
it "should _flatten_ the content of arrays" do
|
155
|
+
TaggableModel.acts_as_taggable_on([:array], [:array])
|
156
|
+
TaggableModel.tag_types.freq[:array].should == 1
|
157
|
+
end
|
158
|
+
|
159
|
+
it "should not raise an error when passed nil" do
|
160
|
+
lambda {
|
161
|
+
TaggableModel.acts_as_taggable_on()
|
162
|
+
}.should_not raise_error
|
163
|
+
end
|
164
|
+
|
165
|
+
it "should not raise an error when passed [nil]" do
|
166
|
+
lambda {
|
167
|
+
TaggableModel.acts_as_taggable_on([nil])
|
168
|
+
}.should_not raise_error
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'when tagging context ends in an "s" when singular (ex. "status", "glass", etc.)' do
|
173
|
+
describe 'caching' do
|
174
|
+
before { @taggable = OtherCachedModel.new(:name => "John Smith") }
|
175
|
+
subject { @taggable }
|
176
|
+
|
177
|
+
it { should respond_to(:save_cached_tag_list) }
|
178
|
+
its(:cached_language_list) { should be_blank }
|
179
|
+
its(:cached_status_list) { should be_blank }
|
180
|
+
its(:cached_glass_list) { should be_blank }
|
181
|
+
|
182
|
+
context 'language taggings cache after update' do
|
183
|
+
before { @taggable.update_attributes(:language_list => 'ruby, .net') }
|
184
|
+
subject { @taggable }
|
185
|
+
|
186
|
+
its(:language_list) { should == ['ruby', '.net']}
|
187
|
+
its(:cached_language_list) { should == 'ruby, .net' } # passes
|
188
|
+
its(:instance_variables) { should include((RUBY_VERSION < '1.9' ? '@language_list' : :@language_list)) }
|
189
|
+
end
|
190
|
+
|
191
|
+
context 'status taggings cache after update' do
|
192
|
+
before { @taggable.update_attributes(:status_list => 'happy, married') }
|
193
|
+
subject { @taggable }
|
194
|
+
|
195
|
+
its(:status_list) { should == ['happy', 'married'] }
|
196
|
+
its(:cached_status_list) { should == 'happy, married' } # fails
|
197
|
+
its(:cached_status_list) { should_not == '' } # fails, is blank
|
198
|
+
its(:instance_variables) { should include((RUBY_VERSION < '1.9' ? '@status_list' : :@status_list)) }
|
199
|
+
its(:instance_variables) { should_not include((RUBY_VERSION < '1.9' ? '@statu_list' : :@statu_list)) } # fails, note: one "s"
|
200
|
+
|
201
|
+
end
|
202
|
+
|
203
|
+
context 'glass taggings cache after update' do
|
204
|
+
before do
|
205
|
+
@taggable.update_attributes(:glass_list => 'rectangle, aviator')
|
206
|
+
end
|
207
|
+
|
208
|
+
subject { @taggable }
|
209
|
+
its(:glass_list) { should == ['rectangle', 'aviator'] }
|
210
|
+
its(:cached_glass_list) { should == 'rectangle, aviator' } # fails
|
211
|
+
its(:cached_glass_list) { should_not == '' } # fails, is blank
|
212
|
+
if RUBY_VERSION < '1.9'
|
213
|
+
its(:instance_variables) { should include('@glass_list') }
|
214
|
+
its(:instance_variables) { should_not include('@glas_list') } # fails, note: one "s"
|
215
|
+
else
|
216
|
+
its(:instance_variables) { should include(:@glass_list) }
|
217
|
+
its(:instance_variables) { should_not include(:@glas_list) } # fails, note: one "s"
|
218
|
+
end
|
219
|
+
|
220
|
+
end
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
describe "taggings" do
|
225
|
+
before(:each) do
|
226
|
+
@taggable = TaggableModel.new(:name => "Art Kram")
|
227
|
+
end
|
228
|
+
|
229
|
+
it 'should return [] taggings' do
|
230
|
+
@taggable.taggings.should == []
|
231
|
+
end
|
232
|
+
end
|
233
|
+
|
234
|
+
describe "@@remove_unused_tags" do
|
235
|
+
before do
|
236
|
+
@taggable = TaggableModel.create(:name => "Bob Jones")
|
237
|
+
@tag = ActsAsTaggableOn::Tag.create(:name => "awesome")
|
238
|
+
|
239
|
+
@tagging = ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags')
|
240
|
+
end
|
241
|
+
|
242
|
+
context "if set to true" do
|
243
|
+
before do
|
244
|
+
ActsAsTaggableOn.remove_unused_tags = true
|
245
|
+
end
|
246
|
+
|
247
|
+
it "should remove unused tags after removing taggings" do
|
248
|
+
@tagging.destroy
|
249
|
+
ActsAsTaggableOn::Tag.find_by_name("awesome").should be_nil
|
250
|
+
end
|
251
|
+
end
|
252
|
+
|
253
|
+
context "if set to false" do
|
254
|
+
before do
|
255
|
+
ActsAsTaggableOn.remove_unused_tags = false
|
256
|
+
end
|
257
|
+
|
258
|
+
it "should not remove unused tags after removing taggings" do
|
259
|
+
@tagging.destroy
|
260
|
+
ActsAsTaggableOn::Tag.find_by_name("awesome").should == @tag
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
end
|