acts-as-taggable-on 2.0.0 → 2.0.6
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.
- data/Gemfile +7 -3
- data/README.rdoc +14 -14
- data/VERSION +1 -1
- data/lib/acts-as-taggable-on.rb +1 -1
- data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +3 -3
- data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +56 -22
- data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +26 -22
- data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +12 -12
- data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +7 -6
- data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +2 -2
- data/lib/acts_as_taggable_on/acts_as_tagger.rb +2 -2
- data/lib/acts_as_taggable_on/compatibility/Gemfile +3 -1
- data/lib/acts_as_taggable_on/compatibility/postgresql.rb +44 -0
- data/lib/acts_as_taggable_on/tag.rb +53 -44
- data/lib/acts_as_taggable_on/tag_list.rb +79 -78
- data/lib/acts_as_taggable_on/tagging.rb +19 -18
- data/lib/acts_as_taggable_on/tags_helper.rb +12 -12
- data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +2 -1
- data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +4 -2
- data/spec/acts_as_taggable_on/acts_as_tagger_spec.rb +3 -3
- data/spec/acts_as_taggable_on/tag_list_spec.rb +3 -3
- data/spec/acts_as_taggable_on/tag_spec.rb +21 -21
- data/spec/acts_as_taggable_on/taggable_spec.rb +37 -12
- data/spec/acts_as_taggable_on/tagger_spec.rb +5 -5
- data/spec/acts_as_taggable_on/tagging_spec.rb +7 -7
- data/spec/acts_as_taggable_on/tags_helper_spec.rb +3 -3
- data/spec/database.yml +17 -0
- data/spec/database.yml.sample +17 -0
- data/spec/models.rb +1 -0
- data/spec/spec_helper.rb +40 -33
- metadata +6 -4
- data/spec/spec.opts +0 -2
|
@@ -1,65 +1,74 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
module ActsAsTaggableOn
|
|
2
|
+
class Tag < ::ActiveRecord::Base
|
|
3
|
+
include ActsAsTaggableOn::ActiveRecord::Backports if ::ActiveRecord::VERSION::MAJOR < 3
|
|
3
4
|
|
|
4
|
-
|
|
5
|
+
attr_accessible :name
|
|
5
6
|
|
|
6
|
-
|
|
7
|
+
### ASSOCIATIONS:
|
|
7
8
|
|
|
8
|
-
|
|
9
|
+
has_many :taggings, :dependent => :destroy, :class_name => 'ActsAsTaggableOn::Tagging'
|
|
9
10
|
|
|
10
|
-
|
|
11
|
+
### VALIDATIONS:
|
|
11
12
|
|
|
12
|
-
|
|
13
|
-
|
|
13
|
+
validates_presence_of :name
|
|
14
|
+
validates_uniqueness_of :name
|
|
14
15
|
|
|
15
|
-
|
|
16
|
+
### SCOPES:
|
|
16
17
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
def self.named(name)
|
|
19
|
+
where(["name #{like_operator} ?", name])
|
|
20
|
+
end
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
22
|
+
def self.named_any(list)
|
|
23
|
+
where(list.map { |tag| sanitize_sql(["name #{like_operator} ?", tag.to_s]) }.join(" OR "))
|
|
24
|
+
end
|
|
24
25
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
26
|
+
def self.named_like(name)
|
|
27
|
+
where(["name #{like_operator} ?", "%#{name}%"])
|
|
28
|
+
end
|
|
28
29
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
def self.named_like_any(list)
|
|
31
|
+
where(list.map { |tag| sanitize_sql(["name #{like_operator} ?", "%#{tag.to_s}%"]) }.join(" OR "))
|
|
32
|
+
end
|
|
32
33
|
|
|
33
|
-
|
|
34
|
+
### CLASS METHODS:
|
|
34
35
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
def self.find_or_create_with_like_by_name(name)
|
|
37
|
+
named_like(name).first || create(:name => name)
|
|
38
|
+
end
|
|
38
39
|
|
|
39
|
-
|
|
40
|
-
|
|
40
|
+
def self.find_or_create_all_with_like_by_name(*list)
|
|
41
|
+
list = [list].flatten
|
|
41
42
|
|
|
42
|
-
|
|
43
|
+
return [] if list.empty?
|
|
43
44
|
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
existing_tags = Tag.named_any(list).all
|
|
46
|
+
new_tag_names = list.reject { |name| existing_tags.any? { |tag| tag.name.mb_chars.downcase == name.mb_chars.downcase } }
|
|
47
|
+
created_tags = new_tag_names.map { |name| Tag.create(:name => name) }
|
|
47
48
|
|
|
48
|
-
|
|
49
|
-
|
|
49
|
+
existing_tags + created_tags
|
|
50
|
+
end
|
|
50
51
|
|
|
51
|
-
|
|
52
|
+
### INSTANCE METHODS:
|
|
52
53
|
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
54
|
+
def ==(object)
|
|
55
|
+
super || (object.is_a?(Tag) && name == object.name)
|
|
56
|
+
end
|
|
56
57
|
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
58
|
+
def to_s
|
|
59
|
+
name
|
|
60
|
+
end
|
|
60
61
|
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
62
|
+
def count
|
|
63
|
+
read_attribute(:count).to_i
|
|
64
|
+
end
|
|
64
65
|
|
|
65
|
-
|
|
66
|
+
class << self
|
|
67
|
+
private
|
|
68
|
+
def like_operator
|
|
69
|
+
connection.adapter_name == 'PostgreSQL' ? 'ILIKE' : 'LIKE'
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
74
|
+
end
|
|
@@ -1,95 +1,96 @@
|
|
|
1
|
-
|
|
1
|
+
module ActsAsTaggableOn
|
|
2
|
+
class TagList < Array
|
|
3
|
+
cattr_accessor :delimiter
|
|
4
|
+
self.delimiter = ','
|
|
2
5
|
|
|
3
|
-
|
|
4
|
-
self.delimiter = ','
|
|
6
|
+
attr_accessor :owner
|
|
5
7
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
add(*args)
|
|
10
|
-
end
|
|
8
|
+
def initialize(*args)
|
|
9
|
+
add(*args)
|
|
10
|
+
end
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
##
|
|
13
|
+
# Returns a new TagList using the given tag string.
|
|
14
|
+
#
|
|
15
|
+
# Example:
|
|
16
|
+
# tag_list = TagList.from("One , Two, Three")
|
|
17
|
+
# tag_list # ["One", "Two", "Three"]
|
|
18
|
+
def self.from(string)
|
|
19
|
+
glue = delimiter.ends_with?(" ") ? delimiter : "#{delimiter} "
|
|
20
|
+
string = string.join(glue) if string.respond_to?(:join)
|
|
20
21
|
|
|
21
|
-
|
|
22
|
-
|
|
22
|
+
new.tap do |tag_list|
|
|
23
|
+
string = string.to_s.dup
|
|
23
24
|
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
25
|
+
# Parse the quoted tags
|
|
26
|
+
string.gsub!(/(\A|#{delimiter})\s*"(.*?)"\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
|
|
27
|
+
string.gsub!(/(\A|#{delimiter})\s*'(.*?)'\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
|
|
27
28
|
|
|
28
|
-
|
|
29
|
+
tag_list.add(string.split(delimiter))
|
|
30
|
+
end
|
|
29
31
|
end
|
|
30
|
-
end
|
|
31
32
|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
33
|
+
##
|
|
34
|
+
# Add tags to the tag_list. Duplicate or blank tags will be ignored.
|
|
35
|
+
# Use the <tt>:parse</tt> option to add an unparsed tag string.
|
|
36
|
+
#
|
|
37
|
+
# Example:
|
|
38
|
+
# tag_list.add("Fun", "Happy")
|
|
39
|
+
# tag_list.add("Fun, Happy", :parse => true)
|
|
40
|
+
def add(*names)
|
|
41
|
+
extract_and_apply_options!(names)
|
|
42
|
+
concat(names)
|
|
43
|
+
clean!
|
|
44
|
+
self
|
|
45
|
+
end
|
|
45
46
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
47
|
+
##
|
|
48
|
+
# Remove specific tags from the tag_list.
|
|
49
|
+
# Use the <tt>:parse</tt> option to add an unparsed tag string.
|
|
50
|
+
#
|
|
51
|
+
# Example:
|
|
52
|
+
# tag_list.remove("Sad", "Lonely")
|
|
53
|
+
# tag_list.remove("Sad, Lonely", :parse => true)
|
|
54
|
+
def remove(*names)
|
|
55
|
+
extract_and_apply_options!(names)
|
|
56
|
+
delete_if { |name| names.include?(name) }
|
|
57
|
+
self
|
|
58
|
+
end
|
|
58
59
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
60
|
+
##
|
|
61
|
+
# Transform the tag_list into a tag string suitable for edting in a form.
|
|
62
|
+
# The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary.
|
|
63
|
+
#
|
|
64
|
+
# Example:
|
|
65
|
+
# tag_list = TagList.new("Round", "Square,Cube")
|
|
66
|
+
# tag_list.to_s # 'Round, "Square,Cube"'
|
|
67
|
+
def to_s
|
|
68
|
+
tags = frozen? ? self.dup : self
|
|
69
|
+
tags.send(:clean!)
|
|
69
70
|
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
71
|
+
tags.map do |name|
|
|
72
|
+
name.include?(delimiter) ? "\"#{name}\"" : name
|
|
73
|
+
end.join(delimiter.ends_with?(" ") ? delimiter : "#{delimiter} ")
|
|
74
|
+
end
|
|
74
75
|
|
|
75
|
-
|
|
76
|
+
private
|
|
76
77
|
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
78
|
+
# Remove whitespace, duplicates, and blanks.
|
|
79
|
+
def clean!
|
|
80
|
+
reject!(&:blank?)
|
|
81
|
+
map!(&:strip)
|
|
82
|
+
uniq!
|
|
83
|
+
end
|
|
83
84
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
85
|
+
def extract_and_apply_options!(args)
|
|
86
|
+
options = args.last.is_a?(Hash) ? args.pop : {}
|
|
87
|
+
options.assert_valid_keys :parse
|
|
87
88
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
89
|
+
if options[:parse]
|
|
90
|
+
args.map! { |a| self.class.from(a) }
|
|
91
|
+
end
|
|
91
92
|
|
|
92
|
-
|
|
93
|
+
args.flatten!
|
|
94
|
+
end
|
|
93
95
|
end
|
|
94
|
-
|
|
95
|
-
end
|
|
96
|
+
end
|
|
@@ -1,23 +1,24 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
1
|
+
module ActsAsTaggableOn
|
|
2
|
+
class Tagging < ::ActiveRecord::Base #:nodoc:
|
|
3
|
+
include ActsAsTaggableOn::ActiveRecord::Backports if ::ActiveRecord::VERSION::MAJOR < 3
|
|
3
4
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
5
|
+
attr_accessible :tag,
|
|
6
|
+
:tag_id,
|
|
7
|
+
:context,
|
|
8
|
+
:taggable,
|
|
9
|
+
:taggable_type,
|
|
10
|
+
:taggable_id,
|
|
11
|
+
:tagger,
|
|
12
|
+
:tagger_type,
|
|
13
|
+
:tagger_id
|
|
13
14
|
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
belongs_to :tag, :class_name => 'ActsAsTaggableOn::Tag'
|
|
16
|
+
belongs_to :taggable, :polymorphic => true
|
|
17
|
+
belongs_to :tagger, :polymorphic => true
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
validates_uniqueness_of :tag_id, :scope => [ :taggable_type, :taggable_id, :context, :tagger_id, :tagger_type ]
|
|
19
|
+
validates_presence_of :context
|
|
20
|
+
validates_presence_of :tag_id
|
|
22
21
|
|
|
22
|
+
validates_uniqueness_of :tag_id, :scope => [ :taggable_type, :taggable_id, :context, :tagger_id, :tagger_type ]
|
|
23
|
+
end
|
|
23
24
|
end
|
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
module
|
|
1
|
+
module ActsAsTaggableOn
|
|
2
|
+
module TagsHelper
|
|
3
|
+
# See the README for an example using tag_cloud.
|
|
4
|
+
def tag_cloud(tags, classes)
|
|
5
|
+
tags = tags.all if tags.respond_to?(:all)
|
|
2
6
|
|
|
3
|
-
|
|
4
|
-
def tag_cloud(tags, classes)
|
|
5
|
-
tags = tags.all if tags.respond_to?(:all)
|
|
7
|
+
return [] if tags.empty?
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
max_count = tags.sort_by(&:count).last.count.to_f
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
yield tag, classes[index]
|
|
11
|
+
tags.each do |tag|
|
|
12
|
+
index = ((tag.count / max_count) * (classes.size - 1)).round
|
|
13
|
+
yield tag, classes[index]
|
|
14
|
+
end
|
|
14
15
|
end
|
|
15
16
|
end
|
|
16
|
-
|
|
17
|
-
end
|
|
17
|
+
end
|
|
@@ -11,7 +11,7 @@ module ActsAsTaggableOn
|
|
|
11
11
|
end
|
|
12
12
|
|
|
13
13
|
def self.source_root
|
|
14
|
-
File.join(File.dirname(__FILE__), 'templates', orm)
|
|
14
|
+
File.join(File.dirname(__FILE__), 'templates', (orm.to_s unless orm.class.eql?(String)) )
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
def self.orm_has_migration?
|
|
@@ -29,3 +29,4 @@ module ActsAsTaggableOn
|
|
|
29
29
|
end
|
|
30
30
|
end
|
|
31
31
|
end
|
|
32
|
+
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require File.
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
|
2
2
|
|
|
3
3
|
describe "Acts As Taggable On" do
|
|
4
4
|
before(:each) do
|
|
@@ -11,7 +11,9 @@ describe "Acts As Taggable On" do
|
|
|
11
11
|
|
|
12
12
|
describe "Taggable Method Generation" do
|
|
13
13
|
before(:each) do
|
|
14
|
-
|
|
14
|
+
clean_database!
|
|
15
|
+
TaggableModel.write_inheritable_attribute(:tag_types, [])
|
|
16
|
+
TaggableModel.acts_as_taggable_on(:tags, :languages, :skills, :needs, :offerings)
|
|
15
17
|
@taggable = TaggableModel.new(:name => "Bob Jones")
|
|
16
18
|
end
|
|
17
19
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
require File.
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
|
2
2
|
|
|
3
3
|
describe "acts_as_tagger" do
|
|
4
4
|
before(:each) do
|
|
5
5
|
clean_database!
|
|
6
6
|
end
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
describe "Tagger Method Generation" do
|
|
9
9
|
before(:each) do
|
|
10
10
|
@tagger = TaggableUser.new()
|
|
11
11
|
end
|
|
@@ -84,7 +84,7 @@ describe "acts_as_tagger" do
|
|
|
84
84
|
end
|
|
85
85
|
end
|
|
86
86
|
|
|
87
|
-
|
|
87
|
+
describe "when called by multiple tagger's" do
|
|
88
88
|
before(:each) do
|
|
89
89
|
@user_x = TaggableUser.create(:name => "User X")
|
|
90
90
|
@user_y = TaggableUser.create(:name => "User Y")
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
require File.
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
|
2
2
|
|
|
3
|
-
describe TagList do
|
|
3
|
+
describe ActsAsTaggableOn::TagList do
|
|
4
4
|
before(:each) do
|
|
5
|
-
@tag_list = TagList.new("awesome","radical")
|
|
5
|
+
@tag_list = ActsAsTaggableOn::TagList.new("awesome","radical")
|
|
6
6
|
end
|
|
7
7
|
|
|
8
8
|
it "should be an array" do
|
|
@@ -1,20 +1,20 @@
|
|
|
1
|
-
require File.
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
|
2
2
|
|
|
3
|
-
describe Tag do
|
|
3
|
+
describe ActsAsTaggableOn::Tag do
|
|
4
4
|
before(:each) do
|
|
5
5
|
clean_database!
|
|
6
|
-
@tag = Tag.new
|
|
6
|
+
@tag = ActsAsTaggableOn::Tag.new
|
|
7
7
|
@user = TaggableModel.create(:name => "Pablo")
|
|
8
8
|
end
|
|
9
9
|
|
|
10
10
|
describe "named like any" do
|
|
11
11
|
before(:each) do
|
|
12
|
-
Tag.create(:name => "awesome")
|
|
13
|
-
Tag.create(:name => "epic")
|
|
12
|
+
ActsAsTaggableOn::Tag.create(:name => "awesome")
|
|
13
|
+
ActsAsTaggableOn::Tag.create(:name => "epic")
|
|
14
14
|
end
|
|
15
15
|
|
|
16
16
|
it "should find both tags" do
|
|
17
|
-
Tag.named_like_any(["awesome", "epic"]).should have(2).items
|
|
17
|
+
ActsAsTaggableOn::Tag.named_like_any(["awesome", "epic"]).should have(2).items
|
|
18
18
|
end
|
|
19
19
|
end
|
|
20
20
|
|
|
@@ -25,17 +25,17 @@ describe Tag do
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
it "should find by name" do
|
|
28
|
-
Tag.find_or_create_with_like_by_name("awesome").should == @tag
|
|
28
|
+
ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("awesome").should == @tag
|
|
29
29
|
end
|
|
30
30
|
|
|
31
31
|
it "should find by name case insensitive" do
|
|
32
|
-
Tag.find_or_create_with_like_by_name("AWESOME").should == @tag
|
|
32
|
+
ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("AWESOME").should == @tag
|
|
33
33
|
end
|
|
34
34
|
|
|
35
35
|
it "should create by name" do
|
|
36
36
|
lambda {
|
|
37
|
-
Tag.find_or_create_with_like_by_name("epic")
|
|
38
|
-
}.should change(Tag, :count).by(1)
|
|
37
|
+
ActsAsTaggableOn::Tag.find_or_create_with_like_by_name("epic")
|
|
38
|
+
}.should change(ActsAsTaggableOn::Tag, :count).by(1)
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
@@ -46,27 +46,27 @@ describe Tag do
|
|
|
46
46
|
end
|
|
47
47
|
|
|
48
48
|
it "should find by name" do
|
|
49
|
-
Tag.find_or_create_all_with_like_by_name("awesome").should == [@tag]
|
|
49
|
+
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("awesome").should == [@tag]
|
|
50
50
|
end
|
|
51
51
|
|
|
52
52
|
it "should find by name case insensitive" do
|
|
53
|
-
Tag.find_or_create_all_with_like_by_name("AWESOME").should == [@tag]
|
|
53
|
+
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("AWESOME").should == [@tag]
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
it "should create by name" do
|
|
57
57
|
lambda {
|
|
58
|
-
Tag.find_or_create_all_with_like_by_name("epic")
|
|
59
|
-
}.should change(Tag, :count).by(1)
|
|
58
|
+
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("epic")
|
|
59
|
+
}.should change(ActsAsTaggableOn::Tag, :count).by(1)
|
|
60
60
|
end
|
|
61
61
|
|
|
62
62
|
it "should find or create by name" do
|
|
63
63
|
lambda {
|
|
64
|
-
Tag.find_or_create_all_with_like_by_name("awesome", "epic").map(&:name).should == ["awesome", "epic"]
|
|
65
|
-
}.should change(Tag, :count).by(1)
|
|
64
|
+
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name("awesome", "epic").map(&:name).should == ["awesome", "epic"]
|
|
65
|
+
}.should change(ActsAsTaggableOn::Tag, :count).by(1)
|
|
66
66
|
end
|
|
67
67
|
|
|
68
68
|
it "should return an empty array if no tags are specified" do
|
|
69
|
-
Tag.find_or_create_all_with_like_by_name([]).should == []
|
|
69
|
+
ActsAsTaggableOn::Tag.find_or_create_all_with_like_by_name([]).should == []
|
|
70
70
|
end
|
|
71
71
|
end
|
|
72
72
|
|
|
@@ -91,7 +91,7 @@ describe Tag do
|
|
|
91
91
|
|
|
92
92
|
it "should equal a tag with the same name" do
|
|
93
93
|
@tag.name = "awesome"
|
|
94
|
-
new_tag = Tag.new(:name => "awesome")
|
|
94
|
+
new_tag = ActsAsTaggableOn::Tag.new(:name => "awesome")
|
|
95
95
|
new_tag.should == @tag
|
|
96
96
|
end
|
|
97
97
|
|
|
@@ -103,13 +103,13 @@ describe Tag do
|
|
|
103
103
|
it "have named_scope named(something)" do
|
|
104
104
|
@tag.name = "cool"
|
|
105
105
|
@tag.save!
|
|
106
|
-
Tag.named('cool').should include(@tag)
|
|
106
|
+
ActsAsTaggableOn::Tag.named('cool').should include(@tag)
|
|
107
107
|
end
|
|
108
108
|
|
|
109
109
|
it "have named_scope named_like(something)" do
|
|
110
110
|
@tag.name = "cool"
|
|
111
111
|
@tag.save!
|
|
112
|
-
@another_tag = Tag.create!(:name => "coolip")
|
|
113
|
-
Tag.named_like('cool').should include(@tag, @another_tag)
|
|
112
|
+
@another_tag = ActsAsTaggableOn::Tag.create!(:name => "coolip")
|
|
113
|
+
ActsAsTaggableOn::Tag.named_like('cool').should include(@tag, @another_tag)
|
|
114
114
|
end
|
|
115
115
|
end
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
require File.
|
|
1
|
+
require File.expand_path('../../spec_helper', __FILE__)
|
|
2
2
|
|
|
3
3
|
describe "Taggable" do
|
|
4
4
|
before(:each) do
|
|
@@ -26,11 +26,11 @@ describe "Taggable" do
|
|
|
26
26
|
|
|
27
27
|
it "should be able to create tags" do
|
|
28
28
|
@taggable.skill_list = "ruby, rails, css"
|
|
29
|
-
@taggable.instance_variable_get("@skill_list").instance_of?(TagList).should be_true
|
|
29
|
+
@taggable.instance_variable_get("@skill_list").instance_of?(ActsAsTaggableOn::TagList).should be_true
|
|
30
30
|
|
|
31
31
|
lambda {
|
|
32
32
|
@taggable.save
|
|
33
|
-
}.should change(Tag, :count).by(3)
|
|
33
|
+
}.should change(ActsAsTaggableOn::Tag, :count).by(3)
|
|
34
34
|
|
|
35
35
|
@taggable.reload
|
|
36
36
|
@taggable.skill_list.sort.should == %w(ruby rails css).sort
|
|
@@ -90,7 +90,7 @@ describe "Taggable" do
|
|
|
90
90
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby")
|
|
91
91
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "Ruby")
|
|
92
92
|
|
|
93
|
-
Tag.find(:all).size.should == 1
|
|
93
|
+
ActsAsTaggableOn::Tag.find(:all).size.should == 1
|
|
94
94
|
TaggableModel.tagged_with("ruby").to_a.should == TaggableModel.tagged_with("Ruby").to_a
|
|
95
95
|
end
|
|
96
96
|
|
|
@@ -108,7 +108,7 @@ describe "Taggable" do
|
|
|
108
108
|
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
|
109
109
|
|
|
110
110
|
TaggableModel.all_tag_counts.all.should_not be_empty
|
|
111
|
-
TaggableModel.all_tag_counts.first.count.should == 3 # ruby
|
|
111
|
+
TaggableModel.all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
|
|
112
112
|
end
|
|
113
113
|
|
|
114
114
|
if ActiveRecord::VERSION::MAJOR >= 3
|
|
@@ -132,7 +132,7 @@ describe "Taggable" do
|
|
|
132
132
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
|
133
133
|
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
|
134
134
|
|
|
135
|
-
TaggableModel.tagged_with("ruby").tag_counts.first.count.should == 2 # ruby
|
|
135
|
+
TaggableModel.tagged_with("ruby").tag_counts(:order => 'tags.id').first.count.should == 2 # ruby
|
|
136
136
|
TaggableModel.tagged_with("ruby").skill_counts.first.count.should == 1 # ruby
|
|
137
137
|
end
|
|
138
138
|
|
|
@@ -141,7 +141,22 @@ describe "Taggable" do
|
|
|
141
141
|
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
|
142
142
|
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby")
|
|
143
143
|
|
|
144
|
-
TaggableModel.tagged_with("ruby").all_tag_counts.first.count.should == 3 # ruby
|
|
144
|
+
TaggableModel.tagged_with("ruby").all_tag_counts(:order => 'tags.id').first.count.should == 3 # ruby
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
it 'should only return tag counts for the available scope' do
|
|
148
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "ruby, rails, css")
|
|
149
|
+
frank = TaggableModel.create(:name => "Frank", :tag_list => "ruby, rails")
|
|
150
|
+
charlie = TaggableModel.create(:name => "Charlie", :skill_list => "ruby, java")
|
|
151
|
+
|
|
152
|
+
TaggableModel.tagged_with('rails').all_tag_counts.should have(3).items
|
|
153
|
+
TaggableModel.tagged_with('rails').all_tag_counts.any? { |tag| tag.name == 'java' }.should be_false
|
|
154
|
+
|
|
155
|
+
# Test specific join syntaxes:
|
|
156
|
+
frank.untaggable_models.create!
|
|
157
|
+
TaggableModel.tagged_with('rails').scoped(:joins => :untaggable_models).all_tag_counts.should have(2).items
|
|
158
|
+
TaggableModel.tagged_with('rails').scoped(:joins => { :untaggable_models => :taggable_model }).all_tag_counts.should have(2).items
|
|
159
|
+
TaggableModel.tagged_with('rails').scoped(:joins => [:untaggable_models]).all_tag_counts.should have(2).items
|
|
145
160
|
end
|
|
146
161
|
|
|
147
162
|
it "should be able to set a custom tag context list" do
|
|
@@ -162,6 +177,16 @@ describe "Taggable" do
|
|
|
162
177
|
TaggableModel.tagged_with("ruby, rails", :order => 'taggable_models.name').to_a.should == [bob, frank]
|
|
163
178
|
TaggableModel.tagged_with(["ruby", "rails"], :order => 'taggable_models.name').to_a.should == [bob, frank]
|
|
164
179
|
end
|
|
180
|
+
|
|
181
|
+
it "should be able to find tagged with quotation marks" do
|
|
182
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive, 'I love the ,comma,'")
|
|
183
|
+
TaggableModel.tagged_with("'I love the ,comma,'").should include(bob)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
it "should be able to find tagged with invalid tags" do
|
|
187
|
+
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive")
|
|
188
|
+
TaggableModel.tagged_with("sad, happier").should_not include(bob)
|
|
189
|
+
end
|
|
165
190
|
|
|
166
191
|
it "should be able to find tagged with any tag" do
|
|
167
192
|
bob = TaggableModel.create(:name => "Bob", :tag_list => "fitter, happier, more productive", :skill_list => "ruby, rails, css")
|
|
@@ -216,7 +241,7 @@ describe "Taggable" do
|
|
|
216
241
|
bob.tag_list << "happier"
|
|
217
242
|
bob.tag_list << "happier"
|
|
218
243
|
bob.save
|
|
219
|
-
}.should change(Tagging, :count).by(1)
|
|
244
|
+
}.should change(ActsAsTaggableOn::Tagging, :count).by(1)
|
|
220
245
|
end
|
|
221
246
|
|
|
222
247
|
describe "Associations" do
|
|
@@ -233,7 +258,7 @@ describe "Taggable" do
|
|
|
233
258
|
|
|
234
259
|
describe "grouped_column_names_for method" do
|
|
235
260
|
it "should return all column names joined for Tag GROUP clause" do
|
|
236
|
-
@taggable.grouped_column_names_for(Tag).should == "tags.id, tags.name"
|
|
261
|
+
@taggable.grouped_column_names_for(ActsAsTaggableOn::Tag).should == "tags.id, tags.name"
|
|
237
262
|
end
|
|
238
263
|
|
|
239
264
|
it "should return all column names joined for TaggableModel GROUP clause" do
|
|
@@ -273,9 +298,9 @@ describe "Taggable" do
|
|
|
273
298
|
@inherited_different.tag_list = "fork, spoon"
|
|
274
299
|
@inherited_different.save!
|
|
275
300
|
|
|
276
|
-
InheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso)
|
|
277
|
-
AlteredInheritingTaggableModel.tag_counts_on(:tags).map(&:name).should == %w(fork spoon)
|
|
278
|
-
TaggableModel.tag_counts_on(:tags).map(&:name).should == %w(bob kelso fork spoon)
|
|
301
|
+
InheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso)
|
|
302
|
+
AlteredInheritingTaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(fork spoon)
|
|
303
|
+
TaggableModel.tag_counts_on(:tags, :order => 'tags.id').map(&:name).should == %w(bob kelso fork spoon)
|
|
279
304
|
end
|
|
280
305
|
|
|
281
306
|
it 'should store same tag without validation conflict' do
|