acts-as-taggable-on 2.0.6 → 2.4.0
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 +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
|