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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/.rspec +2 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +35 -0
- data/Gemfile +2 -9
- data/Guardfile +5 -0
- data/{MIT-LICENSE → MIT-LICENSE.md} +1 -1
- data/README.md +297 -0
- data/Rakefile +9 -55
- data/UPGRADING +14 -0
- data/acts-as-taggable-on.gemspec +32 -0
- data/lib/acts-as-taggable-on/version.rb +4 -0
- data/lib/acts-as-taggable-on.rb +37 -4
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +6 -6
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +99 -45
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +162 -45
- 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 +40 -15
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +28 -18
- data/lib/acts_as_taggable_on/tag.rb +41 -16
- data/lib/acts_as_taggable_on/tag_list.rb +19 -14
- data/lib/acts_as_taggable_on/taggable.rb +102 -0
- data/lib/acts_as_taggable_on/{acts_as_tagger.rb → tagger.rb} +3 -3
- data/lib/acts_as_taggable_on/tagging.rb +12 -2
- data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
- data/lib/acts_as_taggable_on/utils.rb +34 -0
- data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +9 -2
- data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +3 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +333 -54
- data/spec/acts_as_taggable_on/tag_list_spec.rb +117 -61
- data/spec/acts_as_taggable_on/tag_spec.rb +111 -14
- data/spec/acts_as_taggable_on/taggable_spec.rb +330 -34
- data/spec/acts_as_taggable_on/tagger_spec.rb +62 -15
- data/spec/acts_as_taggable_on/tagging_spec.rb +2 -5
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +16 -0
- data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
- data/spec/database.yml.sample +4 -2
- data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +22 -0
- data/spec/models.rb +28 -1
- data/spec/schema.rb +18 -0
- data/spec/spec_helper.rb +30 -7
- data/uninstall.rb +1 -0
- metadata +174 -57
- data/CHANGELOG +0 -25
- data/README.rdoc +0 -221
- data/VERSION +0 -1
- data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +0 -7
- data/generators/acts_as_taggable_on_migration/templates/migration.rb +0 -29
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +0 -53
- data/lib/acts_as_taggable_on/compatibility/Gemfile +0 -8
- data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +0 -17
- data/lib/acts_as_taggable_on/compatibility/postgresql.rb +0 -44
- 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
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
it "should
|
9
|
-
|
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
|
-
|
47
|
-
|
48
|
-
|
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
|
-
|
52
|
-
|
53
|
-
|
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
|
-
|
57
|
-
|
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
|
-
|
61
|
-
|
62
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
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
|
-
|
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
|