acts_as_taggable_on 3.0.0.rc1
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.
- 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
|