acts-as-taggable-on 2.2.2 → 2.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.
@@ -15,6 +15,17 @@ module ActsAsTaggableOn
15
15
  acts_as_taggable_on :tags
16
16
  end
17
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
+
18
29
  ##
19
30
  # Make a model taggable on specified contexts.
20
31
  #
@@ -25,30 +36,67 @@ module ActsAsTaggableOn
25
36
  # acts_as_taggable_on :languages, :skills
26
37
  # end
27
38
  def acts_as_taggable_on(*tag_types)
28
- tag_types = tag_types.to_a.flatten.compact.map(&:to_sym)
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)
29
72
 
30
- if taggable?
73
+ if taggable?
31
74
  self.tag_types = (self.tag_types + tag_types).uniq
32
- else
75
+ self.preserve_tag_order = preserve_tag_order
76
+ else
33
77
  class_attribute :tag_types
34
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, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging"
84
+ has_many :base_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag"
35
85
 
36
- class_eval do
37
- has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging"
38
- has_many :base_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag"
86
+ def self.taggable?
87
+ true
88
+ end
39
89
 
40
- def self.taggable?
41
- true
90
+ include ActsAsTaggableOn::Utils
91
+ include ActsAsTaggableOn::Taggable::Core
92
+ include ActsAsTaggableOn::Taggable::Collection
93
+ include ActsAsTaggableOn::Taggable::Cache
94
+ include ActsAsTaggableOn::Taggable::Ownership
95
+ include ActsAsTaggableOn::Taggable::Related
96
+ include ActsAsTaggableOn::Taggable::Dirty
42
97
  end
43
-
44
- include ActsAsTaggableOn::Utils
45
- include ActsAsTaggableOn::Taggable::Core
46
- include ActsAsTaggableOn::Taggable::Collection
47
- include ActsAsTaggableOn::Taggable::Cache
48
- include ActsAsTaggableOn::Taggable::Ownership
49
- include ActsAsTaggableOn::Taggable::Related
50
98
  end
51
99
  end
52
- end
100
+
53
101
  end
54
102
  end
@@ -31,7 +31,7 @@ module ActsAsTaggableOn
31
31
 
32
32
  module InstanceMethods
33
33
  ##
34
- # Tag a taggable model with tags that are owned by the tagger.
34
+ # Tag a taggable model with tags that are owned by the tagger.
35
35
  #
36
36
  # @param taggable The object that will be tagged
37
37
  # @param [Hash] options An hash with options. Available options are:
@@ -42,7 +42,7 @@ module ActsAsTaggableOn
42
42
  # @user.tag(@photo, :with => "paris, normandy", :on => :locations)
43
43
  def tag(taggable, opts={})
44
44
  opts.reverse_merge!(:force => true)
45
-
45
+ skip_save = opts.delete(:skip_save)
46
46
  return false unless taggable.respond_to?(:is_taggable?) && taggable.is_taggable?
47
47
 
48
48
  raise "You need to specify a tag context using :on" unless opts.has_key?(:on)
@@ -50,7 +50,7 @@ module ActsAsTaggableOn
50
50
  raise "No context :#{opts[:on]} defined in #{taggable.class.to_s}" unless (opts[:force] || taggable.tag_types.include?(opts[:on]))
51
51
 
52
52
  taggable.set_owner_tag_list_on(self, opts[:on].to_s, opts[:with])
53
- taggable.save
53
+ taggable.save unless skip_save
54
54
  end
55
55
 
56
56
  def is_tagger?
@@ -24,7 +24,7 @@ module ActsAsTaggableOn
24
24
  private
25
25
 
26
26
  def remove_unused_tags
27
- if Tag.remove_unused
27
+ if ActsAsTaggableOn.remove_unused_tags
28
28
  if tag.taggings.count.zero?
29
29
  tag.destroy
30
30
  end
@@ -16,7 +16,7 @@ module ActsAsTaggableOn
16
16
  end
17
17
 
18
18
  def sha_prefix(string)
19
- Digest::SHA1.hexdigest(string + Time.now.to_s)[0..6]
19
+ Digest::SHA1.hexdigest("#{string}#{rand}")[0..6]
20
20
  end
21
21
 
22
22
  private
@@ -8,6 +8,20 @@ describe "Acts As Taggable On" do
8
8
  it "should provide a class method 'taggable?' that is false for untaggable models" do
9
9
  UntaggableModel.should_not be_taggable
10
10
  end
11
+
12
+ describe "Taggable Method Generation To Preserve Order" do
13
+ before(:each) do
14
+ clean_database!
15
+ TaggableModel.tag_types = []
16
+ TaggableModel.preserve_tag_order = false
17
+ TaggableModel.acts_as_ordered_taggable_on(:ordered_tags)
18
+ @taggable = TaggableModel.new(:name => "Bob Jones")
19
+ end
20
+
21
+ it "should respond 'true' to preserve_tag_order?" do
22
+ @taggable.class.preserve_tag_order?.should be_true
23
+ end
24
+ end
11
25
 
12
26
  describe "Taggable Method Generation" do
13
27
  before(:each) do
@@ -32,6 +46,18 @@ describe "Acts As Taggable On" do
32
46
  it "should have all tag types" do
33
47
  @taggable.tag_types.should == [:tags, :languages, :skills, :needs, :offerings]
34
48
  end
49
+
50
+ it "should create a class attribute for preserve tag order" do
51
+ @taggable.class.should respond_to(:preserve_tag_order?)
52
+ end
53
+
54
+ it "should create an instance attribute for preserve tag order" do
55
+ @taggable.should respond_to(:preserve_tag_order?)
56
+ end
57
+
58
+ it "should respond 'false' to preserve_tag_order?" do
59
+ @taggable.class.preserve_tag_order?.should be_false
60
+ end
35
61
 
36
62
  it "should generate an association for each tag type" do
37
63
  @taggable.should respond_to(:tags, :skills, :languages)
@@ -453,4 +479,36 @@ describe "Acts As Taggable On" do
453
479
  @taggable.taggings.should == []
454
480
  end
455
481
  end
482
+
483
+ describe "@@remove_unused_tags" do
484
+ before do
485
+ @taggable = TaggableModel.create(:name => "Bob Jones")
486
+ @tag = ActsAsTaggableOn::Tag.create(:name => "awesome")
487
+
488
+ @tagging = ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags')
489
+ end
490
+
491
+ context "if set to true" do
492
+ before do
493
+ ActsAsTaggableOn.remove_unused_tags = true
494
+ end
495
+
496
+ it "should remove unused tags after removing taggings" do
497
+ @tagging.destroy
498
+ ActsAsTaggableOn::Tag.find_by_name("awesome").should be_nil
499
+ end
500
+ end
501
+
502
+ context "if set to false" do
503
+ before do
504
+ ActsAsTaggableOn.remove_unused_tags = false
505
+ end
506
+
507
+ it "should not remove unused tags after removing taggings" do
508
+ @tagging.destroy
509
+ ActsAsTaggableOn::Tag.find_by_name("awesome").should == @tag
510
+ end
511
+ end
512
+ end
513
+
456
514
  end
@@ -1,74 +1,93 @@
1
1
  require File.expand_path('../../spec_helper', __FILE__)
2
2
 
3
3
  describe ActsAsTaggableOn::TagList do
4
- before(:each) do
5
- @tag_list = ActsAsTaggableOn::TagList.new("awesome","radical")
6
- end
7
-
8
- it "should be an array" do
9
- @tag_list.is_a?(Array).should be_true
10
- end
11
-
12
- it "should be able to be add a new tag word" do
13
- @tag_list.add("cool")
14
- @tag_list.include?("cool").should be_true
15
- end
16
-
17
- it "should be able to add delimited lists of words" do
18
- @tag_list.add("cool, wicked", :parse => true)
19
- @tag_list.include?("cool").should be_true
20
- @tag_list.include?("wicked").should be_true
21
- end
22
-
23
- it "should be able to add delimited list of words with quoted delimiters" do
24
- @tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
25
- @tag_list.include?("cool, wicked").should be_true
26
- @tag_list.include?("really cool, really wicked").should be_true
27
- end
28
-
29
- it "should be able to handle other uses of quotation marks correctly" do
30
- @tag_list.add("john's cool car, mary's wicked toy", :parse => true)
31
- @tag_list.include?("john's cool car").should be_true
32
- @tag_list.include?("mary's wicked toy").should be_true
33
- end
34
-
35
- it "should be able to add an array of words" do
36
- @tag_list.add(["cool", "wicked"], :parse => true)
37
- @tag_list.include?("cool").should be_true
38
- @tag_list.include?("wicked").should be_true
39
- end
40
-
41
- it "should be able to remove words" do
42
- @tag_list.remove("awesome")
43
- @tag_list.include?("awesome").should be_false
44
- end
45
-
46
- it "should be able to remove delimited lists of words" do
47
- @tag_list.remove("awesome, radical", :parse => true)
48
- @tag_list.should be_empty
49
- end
50
-
51
- it "should be able to remove an array of words" do
52
- @tag_list.remove(["awesome", "radical"], :parse => true)
53
- @tag_list.should be_empty
4
+ let(:tag_list) { ActsAsTaggableOn::TagList.new("awesome","radical") }
5
+
6
+ it { should be_kind_of Array }
7
+
8
+ it "#from should return empty array if empty array is passed" do
9
+ ActsAsTaggableOn::TagList.from([]).should be_empty
54
10
  end
55
-
56
- it "should give a delimited list of words when converted to string" do
57
- @tag_list.to_s.should == "awesome, radical"
11
+
12
+ describe "#add" do
13
+ it "should be able to be add a new tag word" do
14
+ tag_list.add("cool")
15
+ tag_list.include?("cool").should be_true
16
+ end
17
+
18
+ it "should be able to add delimited lists of words" do
19
+ tag_list.add("cool, wicked", :parse => true)
20
+ tag_list.should include("cool", "wicked")
21
+ end
22
+
23
+ it "should be able to add delimited list of words with quoted delimiters" do
24
+ tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
25
+ tag_list.should include("cool, wicked", "really cool, really wicked")
26
+ end
27
+
28
+ it "should be able to handle other uses of quotation marks correctly" do
29
+ tag_list.add("john's cool car, mary's wicked toy", :parse => true)
30
+ tag_list.should include("john's cool car", "mary's wicked toy")
31
+ end
32
+
33
+ it "should be able to add an array of words" do
34
+ tag_list.add(["cool", "wicked"], :parse => true)
35
+ tag_list.should include("cool", "wicked")
36
+ end
37
+
38
+ it "should quote escape tags with commas in them" do
39
+ tag_list.add("cool","rad,bodacious")
40
+ tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
41
+ end
42
+
58
43
  end
59
-
60
- it "should quote escape tags with commas in them" do
61
- @tag_list.add("cool","rad,bodacious")
62
- @tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
44
+
45
+ describe "#remove" do
46
+ it "should be able to remove words" do
47
+ tag_list.remove("awesome")
48
+ tag_list.should_not include("awesome")
49
+ end
50
+
51
+ it "should be able to remove delimited lists of words" do
52
+ tag_list.remove("awesome, radical", :parse => true)
53
+ tag_list.should be_empty
54
+ end
55
+
56
+ it "should be able to remove an array of words" do
57
+ tag_list.remove(["awesome", "radical"], :parse => true)
58
+ tag_list.should be_empty
59
+ end
63
60
  end
64
-
65
- it "#from should return empty array if empty array is passed" do
66
- ActsAsTaggableOn::TagList.from([]).should == []
61
+
62
+ describe "#to_s" do
63
+ it "should give a delimited list of words when converted to string" do
64
+ tag_list.to_s.should == "awesome, radical"
65
+ end
66
+
67
+ it "should be able to call to_s on a frozen tag list" do
68
+ tag_list.freeze
69
+ lambda { tag_list.add("cool","rad,bodacious") }.should raise_error
70
+ lambda { tag_list.to_s }.should_not raise_error
71
+ end
67
72
  end
68
-
69
- it "should be able to call to_s on a frozen tag list" do
70
- @tag_list.freeze
71
- lambda { @tag_list.add("cool","rad,bodacious") }.should raise_error
72
- lambda { @tag_list.to_s }.should_not raise_error
73
+
74
+ describe "cleaning" do
75
+ it "should parameterize if force_parameterize is set to true" do
76
+ ActsAsTaggableOn.force_parameterize = true
77
+ tag_list = ActsAsTaggableOn::TagList.new("awesome()","radical)(cc")
78
+
79
+ tag_list.to_s.should == "awesome, radical-cc"
80
+ ActsAsTaggableOn.force_parameterize = false
81
+ end
82
+
83
+ it "should lowercase if force_lowercase is set to true" do
84
+ ActsAsTaggableOn.force_lowercase = true
85
+
86
+ tag_list = ActsAsTaggableOn::TagList.new("aweSomE","RaDicaL")
87
+ tag_list.to_s.should == "awesome, radical"
88
+
89
+ ActsAsTaggableOn.force_lowercase = false
90
+ end
91
+
73
92
  end
74
93
  end
@@ -1,3 +1,5 @@
1
+ #encoding: utf-8
2
+
1
3
  require File.expand_path('../../spec_helper', __FILE__)
2
4
 
3
5
  describe ActsAsTaggableOn::Tag do
@@ -40,6 +42,23 @@ describe ActsAsTaggableOn::Tag do
40
42
  end
41
43
  end
42
44
 
45
+ unless ActsAsTaggableOn::Tag.using_sqlite?
46
+ describe "find or create by unicode name" do
47
+ before(:each) do
48
+ @tag.name = "привет"
49
+ @tag.save
50
+ end
51
+
52
+ it "should find by name" do
53
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("привет").should == @tag
54
+ end
55
+
56
+ it "should find by name case insensitive" do
57
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("ПРИВЕТ").should == @tag
58
+ end
59
+ end
60
+ end
61
+
43
62
  describe "find or create all by any name" do
44
63
  before(:each) do
45
64
  @tag.name = "awesome"
@@ -82,6 +101,16 @@ describe ActsAsTaggableOn::Tag do
82
101
  @tag.errors[:name].should == []
83
102
  end
84
103
 
104
+ it "should limit the name length to 255 or less characters" do
105
+ @tag.name = "fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxranr"
106
+ @tag.valid?
107
+ @tag.errors[:name].should == ["is too long (maximum is 255 characters)"]
108
+
109
+ @tag.name = "fgkgnkkgjymkypbuozmwwghblmzpqfsgjasflblywhgkwndnkzeifalfcpeaeqychjuuowlacmuidnnrkprgpcpybarbkrmziqihcrxirlokhnzfvmtzixgvhlxzncyywficpraxfnjptxxhkqmvicbcdcynkjvziefqzyndxkjmsjlvyvbwraklbalykyxoliqdlreeykuphdtmzfdwpphmrqvwvqffojkqhlzvinqajsxbszyvrqqyzusxran"
110
+ @tag.valid?
111
+ @tag.errors[:name].should == []
112
+ end
113
+
85
114
  it "should equal a tag with the same name" do
86
115
  @tag.name = "awesome"
87
116
  new_tag = ActsAsTaggableOn::Tag.new(:name => "awesome")
@@ -120,35 +149,5 @@ describe ActsAsTaggableOn::Tag do
120
149
  end
121
150
 
122
151
  end
123
-
124
- describe ".remove_unused" do
125
- before do
126
- @taggable = TaggableModel.create(:name => "Bob Jones")
127
- @tag = ActsAsTaggableOn::Tag.create(:name => "awesome")
128
152
 
129
- @tagging = ActsAsTaggableOn::Tagging.create(:taggable => @taggable, :tag => @tag, :context => 'tags')
130
- end
131
-
132
- context "if set to true" do
133
- before do
134
- ActsAsTaggableOn::Tag.remove_unused = true
135
- end
136
-
137
- it "should remove unused tags after removing taggings" do
138
- @tagging.destroy
139
- ActsAsTaggableOn::Tag.find_by_name("awesome").should be_nil
140
- end
141
- end
142
-
143
- context "if set to false" do
144
- before do
145
- ActsAsTaggableOn::Tag.remove_unused = false
146
- end
147
-
148
- it "should not remove unused tags after removing taggings" do
149
- @tagging.destroy
150
- ActsAsTaggableOn::Tag.find_by_name("awesome").should == @tag
151
- end
152
- end
153
- end
154
153
  end
@@ -1,5 +1,114 @@
1
1
  require File.expand_path('../../spec_helper', __FILE__)
2
2
 
3
+ describe "Taggable To Preserve Order" do
4
+ before(:each) do
5
+ clean_database!
6
+ @taggable = OrderedTaggableModel.new(:name => "Bob Jones")
7
+ end
8
+
9
+ it "should have tag types" do
10
+ [:tags, :colours].each do |type|
11
+ OrderedTaggableModel.tag_types.should include type
12
+ end
13
+
14
+ @taggable.tag_types.should == OrderedTaggableModel.tag_types
15
+ end
16
+
17
+ it "should have tag associations" do
18
+ [:tags, :colours].each do |type|
19
+ @taggable.respond_to?(type).should be_true
20
+ @taggable.respond_to?("#{type.to_s.singularize}_taggings").should be_true
21
+ end
22
+ end
23
+
24
+ it "should have tag associations ordered by id" do
25
+ [:tags, :colours].each do |type|
26
+ OrderedTaggableModel.reflect_on_association(type).options[:order].should include('id')
27
+ OrderedTaggableModel.reflect_on_association("#{type.to_s.singularize}_taggings".to_sym).options[:order].should include('id')
28
+ end
29
+ end
30
+
31
+ it "should have tag methods" do
32
+ [:tags, :colours].each do |type|
33
+ @taggable.respond_to?("#{type.to_s.singularize}_list").should be_true
34
+ @taggable.respond_to?("#{type.to_s.singularize}_list=").should be_true
35
+ @taggable.respond_to?("all_#{type.to_s}_list").should be_true
36
+ end
37
+ end
38
+
39
+ it "should return tag list in the order the tags were created" do
40
+ # create
41
+ @taggable.tag_list = "rails, ruby, css"
42
+ @taggable.instance_variable_get("@tag_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
43
+
44
+ lambda {
45
+ @taggable.save
46
+ }.should change(ActsAsTaggableOn::Tag, :count).by(3)
47
+
48
+ @taggable.reload
49
+ @taggable.tag_list.should == %w(rails ruby css)
50
+
51
+ # update
52
+ @taggable.tag_list = "pow, ruby, rails"
53
+ @taggable.save
54
+
55
+ @taggable.reload
56
+ @taggable.tag_list.should == %w(pow ruby rails)
57
+
58
+ # update with no change
59
+ @taggable.tag_list = "pow, ruby, rails"
60
+ @taggable.save
61
+
62
+ @taggable.reload
63
+ @taggable.tag_list.should == %w(pow ruby rails)
64
+
65
+ # update to clear tags
66
+ @taggable.tag_list = ""
67
+ @taggable.save
68
+
69
+ @taggable.reload
70
+ @taggable.tag_list.should == []
71
+ end
72
+
73
+ it "should return tag objects in the order the tags were created" do
74
+ # create
75
+ @taggable.tag_list = "pow, ruby, rails"
76
+ @taggable.instance_variable_get("@tag_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
77
+
78
+ lambda {
79
+ @taggable.save
80
+ }.should change(ActsAsTaggableOn::Tag, :count).by(3)
81
+
82
+ @taggable.reload
83
+ @taggable.tags.map{|t| t.name}.should == %w(pow ruby rails)
84
+
85
+ # update
86
+ @taggable.tag_list = "rails, ruby, css, pow"
87
+ @taggable.save
88
+
89
+ @taggable.reload
90
+ @taggable.tags.map{|t| t.name}.should == %w(rails ruby css pow)
91
+ end
92
+
93
+ it "should return tag objects in tagging id order" do
94
+ # create
95
+ @taggable.tag_list = "pow, ruby, rails"
96
+ @taggable.save
97
+
98
+ @taggable.reload
99
+ ids = @taggable.tags.map{|t| t.taggings.first.id}
100
+ ids.should == ids.sort
101
+
102
+ # update
103
+ @taggable.tag_list = "rails, ruby, css, pow"
104
+ @taggable.save
105
+
106
+ @taggable.reload
107
+ ids = @taggable.tags.map{|t| t.taggings.first.id}
108
+ ids.should == ids.sort
109
+ end
110
+ end
111
+
3
112
  describe "Taggable" do
4
113
  before(:each) do
5
114
  clean_database!
@@ -224,19 +333,19 @@ describe "Taggable" do
224
333
  frank = TaggableModel.create(:name => "Frank", :tag_list => "bobby, jim")
225
334
  steve = TaggableModel.create(:name => "Steve", :tag_list => "john, patricia")
226
335
  jim = TaggableModel.create(:name => "Jim", :tag_list => "jim, steve")
227
-
228
-
229
- TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :any => true).to_a.should == [bob, frank, steve]
230
- TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :exclude => true).to_a.should == [jim]
336
+
337
+
338
+ TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :any => true).to_a.sort_by{|o| o.id}.should == [bob, frank, steve]
339
+ TaggableModel.tagged_with(["bob", "tricia"], :wild => true, :exclude => true).to_a.should == [jim]
231
340
  end
232
341
  end
233
-
342
+
234
343
  it "should be able to find tagged on a custom tag context" do
235
344
  bob = TaggableModel.create(:name => "Bob")
236
345
  bob.set_tag_list_on(:rotors, "spinning, jumping")
237
346
  bob.tag_list_on(:rotors).should == ["spinning","jumping"]
238
347
  bob.save
239
-
348
+
240
349
  TaggableModel.tagged_with("spinning", :on => :rotors).to_a.should == [bob]
241
350
  end
242
351
 
@@ -407,6 +516,28 @@ describe "Taggable" do
407
516
  @taggable.tag_list_on(:test).should == ["hello"]
408
517
  end
409
518
  end
519
+
520
+ describe "Dirty Objects" do
521
+ before(:each) do
522
+ @taggable = TaggableModel.create(:tag_list => "awesome, epic")
523
+ end
524
+
525
+ it 'should show changes of dirty object' do
526
+ @taggable.changes.should == {}
527
+ @taggable.tag_list = 'one'
528
+ @taggable.changes.should == {"tag_list"=>["awesome, epic", ["one"]]}
529
+
530
+ @taggable.tag_list_changed?.should be_true
531
+ @taggable.tag_list_was.should == "awesome, epic"
532
+ @taggable.tag_list_change.should == ["awesome, epic", ["one"]]
533
+ end
534
+
535
+ it 'should show no changes if the same tag_list' do
536
+ @taggable.tag_list = "awesome, epic"
537
+ @taggable.tag_list_changed?.should be_false
538
+ @taggable.changes.should == {}
539
+ end
540
+ end
410
541
  end
411
542
 
412
543