acts-as-taggable-on 2.0.6 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +11 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +9 -0
  5. data/CHANGELOG.md +35 -0
  6. data/Gemfile +2 -9
  7. data/Guardfile +5 -0
  8. data/{MIT-LICENSE → MIT-LICENSE.md} +1 -1
  9. data/README.md +297 -0
  10. data/Rakefile +9 -55
  11. data/UPGRADING +14 -0
  12. data/acts-as-taggable-on.gemspec +32 -0
  13. data/lib/acts-as-taggable-on/version.rb +4 -0
  14. data/lib/acts-as-taggable-on.rb +37 -4
  15. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +6 -6
  16. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +99 -45
  17. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +162 -45
  18. data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +37 -0
  19. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +40 -15
  20. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +28 -18
  21. data/lib/acts_as_taggable_on/tag.rb +41 -16
  22. data/lib/acts_as_taggable_on/tag_list.rb +19 -14
  23. data/lib/acts_as_taggable_on/taggable.rb +102 -0
  24. data/lib/acts_as_taggable_on/{acts_as_tagger.rb → tagger.rb} +3 -3
  25. data/lib/acts_as_taggable_on/tagging.rb +12 -2
  26. data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
  27. data/lib/acts_as_taggable_on/utils.rb +34 -0
  28. data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +9 -2
  29. data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +3 -1
  30. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +333 -54
  31. data/spec/acts_as_taggable_on/tag_list_spec.rb +117 -61
  32. data/spec/acts_as_taggable_on/tag_spec.rb +111 -14
  33. data/spec/acts_as_taggable_on/taggable_spec.rb +330 -34
  34. data/spec/acts_as_taggable_on/tagger_spec.rb +62 -15
  35. data/spec/acts_as_taggable_on/tagging_spec.rb +2 -5
  36. data/spec/acts_as_taggable_on/tags_helper_spec.rb +16 -0
  37. data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
  38. data/spec/database.yml.sample +4 -2
  39. data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +22 -0
  40. data/spec/models.rb +28 -1
  41. data/spec/schema.rb +18 -0
  42. data/spec/spec_helper.rb +30 -7
  43. data/uninstall.rb +1 -0
  44. metadata +174 -57
  45. data/CHANGELOG +0 -25
  46. data/README.rdoc +0 -221
  47. data/VERSION +0 -1
  48. data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +0 -7
  49. data/generators/acts_as_taggable_on_migration/templates/migration.rb +0 -29
  50. data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +0 -53
  51. data/lib/acts_as_taggable_on/compatibility/Gemfile +0 -8
  52. data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +0 -17
  53. data/lib/acts_as_taggable_on/compatibility/postgresql.rb +0 -44
  54. data/spec/database.yml +0 -17
@@ -1,70 +1,126 @@
1
+ # -*- coding: utf-8 -*-
1
2
  require File.expand_path('../../spec_helper', __FILE__)
2
3
 
3
4
  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
5
+ let(:tag_list) { ActsAsTaggableOn::TagList.new("awesome","radical") }
6
+
7
+ it { should be_kind_of Array }
8
+
9
+ it "#from should return empty array if empty array is passed" do
10
+ ActsAsTaggableOn::TagList.from([]).should be_empty
44
11
  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
12
+
13
+ describe "#add" do
14
+ it "should be able to be add a new tag word" do
15
+ tag_list.add("cool")
16
+ tag_list.include?("cool").should be_true
17
+ end
18
+
19
+ it "should be able to add delimited lists of words" do
20
+ tag_list.add("cool, wicked", :parse => true)
21
+ tag_list.should include("cool", "wicked")
22
+ end
23
+
24
+ it "should be able to add delimited list of words with quoted delimiters" do
25
+ tag_list.add("'cool, wicked', \"really cool, really wicked\"", :parse => true)
26
+ tag_list.should include("cool, wicked", "really cool, really wicked")
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.should include("john's cool car", "mary's wicked toy")
32
+ end
33
+
34
+ it "should be able to add an array of words" do
35
+ tag_list.add(["cool", "wicked"], :parse => true)
36
+ tag_list.should include("cool", "wicked")
37
+ end
38
+
39
+ it "should quote escape tags with commas in them" do
40
+ tag_list.add("cool","rad,bodacious")
41
+ tag_list.to_s.should == "awesome, radical, cool, \"rad,bodacious\""
42
+ end
43
+
49
44
  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
45
+
46
+ describe "#remove" do
47
+ it "should be able to remove words" do
48
+ tag_list.remove("awesome")
49
+ tag_list.should_not include("awesome")
50
+ end
51
+
52
+ it "should be able to remove delimited lists of words" do
53
+ tag_list.remove("awesome, radical", :parse => true)
54
+ tag_list.should be_empty
55
+ end
56
+
57
+ it "should be able to remove an array of words" do
58
+ tag_list.remove(["awesome", "radical"], :parse => true)
59
+ tag_list.should be_empty
60
+ end
54
61
  end
55
-
56
- it "should give a delimited list of words when converted to string" do
57
- @tag_list.to_s.should == "awesome, radical"
62
+
63
+ describe "#to_s" do
64
+ it "should give a delimited list of words when converted to string" do
65
+ tag_list.to_s.should == "awesome, radical"
66
+ end
67
+
68
+ it "should be able to call to_s on a frozen tag list" do
69
+ tag_list.freeze
70
+ lambda { tag_list.add("cool","rad,bodacious") }.should raise_error
71
+ lambda { tag_list.to_s }.should_not raise_error
72
+ end
58
73
  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\""
74
+
75
+ describe "cleaning" do
76
+ it "should parameterize if force_parameterize is set to true" do
77
+ ActsAsTaggableOn.force_parameterize = true
78
+ tag_list = ActsAsTaggableOn::TagList.new("awesome()","radical)(cc")
79
+
80
+ tag_list.to_s.should == "awesome, radical-cc"
81
+ ActsAsTaggableOn.force_parameterize = false
82
+ end
83
+
84
+ it "should lowercase if force_lowercase is set to true" do
85
+ ActsAsTaggableOn.force_lowercase = true
86
+
87
+ tag_list = ActsAsTaggableOn::TagList.new("aweSomE","RaDicaL","Entrée")
88
+ tag_list.to_s.should == "awesome, radical, entrée"
89
+
90
+ ActsAsTaggableOn.force_lowercase = false
91
+ end
92
+
63
93
  end
64
-
65
- it "should be able to call to_s on a frozen tag list" do
66
- @tag_list.freeze
67
- lambda { @tag_list.add("cool","rad,bodacious") }.should raise_error
68
- lambda { @tag_list.to_s }.should_not raise_error
94
+
95
+ describe "Multiple Delimiter" do
96
+ before do
97
+ @old_delimiter = ActsAsTaggableOn.delimiter
98
+ end
99
+
100
+ after do
101
+ ActsAsTaggableOn.delimiter = @old_delimiter
102
+ end
103
+
104
+ it "should separate tags by delimiters" do
105
+ ActsAsTaggableOn.delimiter = [',', ' ', '\|']
106
+ tag_list = ActsAsTaggableOn::TagList.from "cool, data|I have"
107
+ tag_list.to_s.should == 'cool, data, I, have'
108
+ end
109
+
110
+ it "should escape quote" do
111
+ ActsAsTaggableOn.delimiter = [',', ' ', '\|']
112
+ tag_list = ActsAsTaggableOn::TagList.from "'I have'|cool, data"
113
+ tag_list.to_s.should == '"I have", cool, data'
114
+
115
+ tag_list = ActsAsTaggableOn::TagList.from '"I, have"|cool, data'
116
+ tag_list.to_s.should == '"I, have", cool, data'
117
+ end
118
+
119
+ it "should work for utf8 delimiter and long delimiter" do
120
+ ActsAsTaggableOn.delimiter = [',', '的', '可能是']
121
+ tag_list = ActsAsTaggableOn::TagList.from "我的东西可能是不见了,还好有备份"
122
+ tag_list.to_s.should == "我, 东西, 不见了, 还好有备份"
123
+ end
69
124
  end
70
- end
125
+
126
+ 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
@@ -9,12 +11,13 @@ describe ActsAsTaggableOn::Tag do
9
11
 
10
12
  describe "named like any" do
11
13
  before(:each) do
14
+ ActsAsTaggableOn::Tag.create(:name => "Awesome")
12
15
  ActsAsTaggableOn::Tag.create(:name => "awesome")
13
16
  ActsAsTaggableOn::Tag.create(:name => "epic")
14
17
  end
15
18
 
16
19
  it "should find both tags" do
17
- ActsAsTaggableOn::Tag.named_like_any(["awesome", "epic"]).should have(2).items
20
+ ActsAsTaggableOn::Tag.named_like_any(["awesome", "epic"]).should have(3).items
18
21
  end
19
22
  end
20
23
 
@@ -39,6 +42,23 @@ describe ActsAsTaggableOn::Tag do
39
42
  end
40
43
  end
41
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
+
42
62
  describe "find or create all by any name" do
43
63
  before(:each) do
44
64
  @tag.name = "awesome"
@@ -72,21 +92,23 @@ describe ActsAsTaggableOn::Tag do
72
92
 
73
93
  it "should require a name" do
74
94
  @tag.valid?
75
-
76
- if ActiveRecord::VERSION::MAJOR >= 3
77
- @tag.errors[:name].should == ["can't be blank"]
78
- else
79
- @tag.errors[:name].should == "can't be blank"
80
- end
95
+
96
+ @tag.errors[:name].should == ["can't be blank"]
81
97
 
82
98
  @tag.name = "something"
83
99
  @tag.valid?
84
-
85
- if ActiveRecord::VERSION::MAJOR >= 3
86
- @tag.errors[:name].should == []
87
- else
88
- @tag.errors[:name].should be_nil
89
- end
100
+
101
+ @tag.errors[:name].should == []
102
+ end
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 == []
90
112
  end
91
113
 
92
114
  it "should equal a tag with the same name" do
@@ -112,4 +134,79 @@ describe ActsAsTaggableOn::Tag do
112
134
  @another_tag = ActsAsTaggableOn::Tag.create!(:name => "coolip")
113
135
  ActsAsTaggableOn::Tag.named_like('cool').should include(@tag, @another_tag)
114
136
  end
115
- end
137
+
138
+ describe "escape wildcard symbols in like requests" do
139
+ before(:each) do
140
+ @tag.name = "cool"
141
+ @tag.save
142
+ @another_tag = ActsAsTaggableOn::Tag.create!(:name => "coo%")
143
+ @another_tag2 = ActsAsTaggableOn::Tag.create!(:name => "coolish")
144
+ end
145
+
146
+ it "return escaped result when '%' char present in tag" do
147
+ ActsAsTaggableOn::Tag.named_like('coo%').should_not include(@tag)
148
+ ActsAsTaggableOn::Tag.named_like('coo%').should include(@another_tag)
149
+ end
150
+
151
+ end
152
+
153
+ describe "when using strict_case_match" do
154
+ before do
155
+ ActsAsTaggableOn.strict_case_match = true
156
+ @tag.name = "awesome"
157
+ @tag.save!
158
+ end
159
+
160
+ after do
161
+ ActsAsTaggableOn.strict_case_match = false
162
+ end
163
+
164
+ it "should find by name" do
165
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("awesome").should == @tag
166
+ end
167
+
168
+ it "should find by name case sensitively" do
169
+ expect {
170
+ ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("AWESOME")
171
+ }.to change(ActsAsTaggableOn::Tag, :count)
172
+
173
+ ActsAsTaggableOn::Tag.last.name.should == "AWESOME"
174
+ end
175
+
176
+ it "should have a named_scope named(something) that matches exactly" do
177
+ uppercase_tag = ActsAsTaggableOn::Tag.create(:name => "Cool")
178
+ @tag.name = "cool"
179
+ @tag.save!
180
+
181
+ ActsAsTaggableOn::Tag.named('cool').should include(@tag)
182
+ ActsAsTaggableOn::Tag.named('cool').should_not include(uppercase_tag)
183
+ end
184
+ end
185
+
186
+ describe "name uniqeness validation" do
187
+ let(:duplicate_tag) { ActsAsTaggableOn::Tag.new(:name => 'ror') }
188
+
189
+ before { ActsAsTaggableOn::Tag.create(:name => 'ror') }
190
+
191
+ context "when don't need unique names" do
192
+ it "should not run uniqueness validation" do
193
+ duplicate_tag.stub(:validates_name_uniqueness?).and_return(false)
194
+ duplicate_tag.save
195
+ duplicate_tag.should be_persisted
196
+ end
197
+ end
198
+
199
+ context "when do need unique names" do
200
+ it "should run uniqueness validation" do
201
+ duplicate_tag.should_not be_valid
202
+ end
203
+
204
+ it "add error to name" do
205
+ duplicate_tag.save
206
+
207
+ duplicate_tag.should have(1).errors
208
+ duplicate_tag.errors.messages[:name].should include('has already been taken')
209
+ end
210
+ end
211
+ end
212
+ end