acts-as-taggable-on 2.0.0.rc2 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -71,7 +71,9 @@ rake spec:plugins
71
71
  = Usage
72
72
 
73
73
  class User < ActiveRecord::Base
74
- acts_as_taggable_on :tags, :skills, :interests
74
+ # Alias for <tt>acts_as_taggable_on :tags</tt>:
75
+ acts_as_taggable
76
+ acts_as_taggable_on :skills, :interests
75
77
  end
76
78
 
77
79
  @user = User.new(:name => "Bobby")
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2.0.0.rc2
1
+ 2.0.0
@@ -4,20 +4,32 @@ module ActsAsTaggableOn
4
4
  false
5
5
  end
6
6
 
7
+ ##
8
+ # This is an alias for calling <tt>acts_as_taggable_on :tags</tt>.
9
+ #
10
+ # Example:
11
+ # class Book < ActiveRecord::Base
12
+ # acts_as_taggable
13
+ # end
7
14
  def acts_as_taggable
8
15
  acts_as_taggable_on :tags
9
16
  end
10
17
 
18
+ ##
19
+ # Make a model taggable on specified contexts.
20
+ #
21
+ # @param [Array] tag_types An array of taggable contexts
22
+ #
23
+ # Example:
24
+ # class User < ActiveRecord::Base
25
+ # acts_as_taggable_on :languages, :skills
26
+ # end
11
27
  def acts_as_taggable_on(*tag_types)
12
28
  tag_types = tag_types.to_a.flatten.compact.map(&:to_sym)
13
29
 
14
30
  if taggable?
15
31
  write_inheritable_attribute(:tag_types, (self.tag_types + tag_types).uniq)
16
32
  else
17
- if ::ActiveRecord::VERSION::MAJOR < 3
18
- include ActsAsTaggableOn::ActiveRecord::Backports
19
- end
20
-
21
33
  write_inheritable_attribute(:tag_types, tag_types)
22
34
  class_inheritable_reader(:tag_types)
23
35
 
@@ -38,17 +38,18 @@ module ActsAsTaggableOn::Taggable
38
38
  all_tag_counts(options.merge({:on => context.to_s}))
39
39
  end
40
40
 
41
+ ##
41
42
  # Calculate the tag counts for all tags.
42
43
  #
43
- # Options:
44
- # :start_at - Restrict the tags to those created after a certain time
45
- # :end_at - Restrict the tags to those created before a certain time
46
- # :conditions - A piece of SQL conditions to add to the query
47
- # :limit - The maximum number of tags to return
48
- # :order - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'
49
- # :at_least - Exclude tags with a frequency less than the given value
50
- # :at_most - Exclude tags with a frequency greater than the given value
51
- # :on - Scope the find to only include a certain context
44
+ # @param [Hash] options Options:
45
+ # * :start_at - Restrict the tags to those created after a certain time
46
+ # * :end_at - Restrict the tags to those created before a certain time
47
+ # * :conditions - A piece of SQL conditions to add to the query
48
+ # * :limit - The maximum number of tags to return
49
+ # * :order - A piece of SQL to order by. Eg 'tags.count desc' or 'taggings.created_at desc'
50
+ # * :at_least - Exclude tags with a frequency less than the given value
51
+ # * :at_most - Exclude tags with a frequency greater than the given value
52
+ # * :on - Scope the find to only include a certain context
52
53
  def all_tag_counts(options = {})
53
54
  options.assert_valid_keys :start_at, :end_at, :conditions, :at_least, :at_most, :order, :limit, :on, :id
54
55
 
@@ -51,6 +51,20 @@ module ActsAsTaggableOn::Taggable
51
51
  object.column_names.map { |column| "#{object.table_name}.#{column}" }.join(", ")
52
52
  end
53
53
 
54
+ ##
55
+ # Return a scope of objects that are tagged with the specified tags.
56
+ #
57
+ # @param tags The tags that we want to query for
58
+ # @param [Hash] options A hash of options to alter you query:
59
+ # * <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags
60
+ # * <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags
61
+ # * <tt>:match_all</tt> - if set to true, return objects that are *ONLY* tagged with the specified tags
62
+ #
63
+ # Example:
64
+ # User.tagged_with("awesome", "cool") # Users that are tagged with awesome and cool
65
+ # User.tagged_with("awesome", "cool", :exclude => true) # Users that are not tagged with awesome or cool
66
+ # User.tagged_with("awesome", "cool", :any => true) # Users that are tagged with awesome or cool
67
+ # User.tagged_with("awesome", "cool", :match_all => true) # Users that are tagged with just awesome and cool
54
68
  def tagged_with(tags, options = {})
55
69
  tag_list = TagList.from(tags)
56
70
 
@@ -100,7 +114,10 @@ module ActsAsTaggableOn::Taggable
100
114
  end
101
115
 
102
116
 
103
- joins(joins.join(" ")).group(group).where(conditions.join(" AND ")).readonly(false)
117
+ scoped(:joins => joins.join(" "),
118
+ :group => group,
119
+ :conditions => conditions.join(" AND "),
120
+ :readonly => false)
104
121
  end
105
122
 
106
123
  def is_taggable?
@@ -42,10 +42,10 @@ module ActsAsTaggableOn::Taggable
42
42
  exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
43
43
 
44
44
  klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
45
- :from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
46
- :conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?) AND #{Tagging.table_name}.context = ?", tags_to_find, result_context],
47
- :group => grouped_column_names_for(klass),
48
- :order => "count DESC" }.update(options))
45
+ :from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
46
+ :conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?) AND #{Tagging.table_name}.context = ?", tags_to_find, result_context],
47
+ :group => grouped_column_names_for(klass),
48
+ :order => "count DESC" }.update(options))
49
49
  end
50
50
 
51
51
  def related_tags_for(context, klass, options = {})
@@ -54,10 +54,10 @@ module ActsAsTaggableOn::Taggable
54
54
  exclude_self = "#{klass.table_name}.id != #{id} AND" if self.class == klass
55
55
 
56
56
  klass.scoped({ :select => "#{klass.table_name}.*, COUNT(#{Tag.table_name}.id) AS count",
57
- :from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
58
- :conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?)", tags_to_find],
59
- :group => grouped_column_names_for(klass),
60
- :order => "count DESC" }.update(options))
57
+ :from => "#{klass.table_name}, #{Tag.table_name}, #{Tagging.table_name}",
58
+ :conditions => ["#{exclude_self} #{klass.table_name}.id = #{Tagging.table_name}.taggable_id AND #{Tagging.table_name}.taggable_type = '#{klass.to_s}' AND #{Tagging.table_name}.tag_id = #{Tag.table_name}.id AND #{Tag.table_name}.name IN (?)", tags_to_find],
59
+ :group => grouped_column_names_for(klass),
60
+ :order => "count DESC" }.update(options))
61
61
  end
62
62
  end
63
63
  end
@@ -5,10 +5,20 @@ module ActsAsTaggableOn
5
5
  end
6
6
 
7
7
  module ClassMethods
8
+ ##
9
+ # Make a model a tagger. This allows an instance of a model to claim ownership
10
+ # of tags.
11
+ #
12
+ # Example:
13
+ # class User < ActiveRecord::Base
14
+ # acts_as_tagger
15
+ # end
8
16
  def acts_as_tagger(opts={})
9
- has_many :owned_taggings, opts.merge(:as => :tagger, :dependent => :destroy,
10
- :include => :tag, :class_name => "Tagging")
11
- has_many :owned_tags, :through => :owned_taggings, :source => :tag, :uniq => true
17
+ class_eval do
18
+ has_many :owned_taggings, opts.merge(:as => :tagger, :dependent => :destroy,
19
+ :include => :tag, :class_name => "Tagging")
20
+ has_many :owned_tags, :through => :owned_taggings, :source => :tag, :uniq => true
21
+ end
12
22
 
13
23
  include ActsAsTaggableOn::Tagger::InstanceMethods
14
24
  extend ActsAsTaggableOn::Tagger::SingletonMethods
@@ -20,6 +30,16 @@ module ActsAsTaggableOn
20
30
  end
21
31
 
22
32
  module InstanceMethods
33
+ ##
34
+ # Tag a taggable model with tags that are owned by the tagger.
35
+ #
36
+ # @param taggable The object that will be tagged
37
+ # @param [Hash] options An hash with options. Available options are:
38
+ # * <tt>:with</tt> - The tags that you want to
39
+ # * <tt>:on</tt> - The context on which you want to tag
40
+ #
41
+ # Example:
42
+ # @user.tag(@photo, :with => "paris, normandy", :on => :locations)
23
43
  def tag(taggable, opts={})
24
44
  opts.reverse_merge!(:force => true)
25
45
 
@@ -1,21 +1,40 @@
1
1
  class TagList < Array
2
2
 
3
3
  cattr_accessor :delimiter
4
-
5
4
  self.delimiter = ','
6
5
 
6
+ attr_accessor :owner
7
+
7
8
  def initialize(*args)
8
9
  add(*args)
9
10
  end
11
+
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
+ string = string.join(", ") if string.respond_to?(:join)
10
20
 
11
- attr_accessor :owner
21
+ new.tap do |tag_list|
22
+ string = string.to_s.dup
23
+
24
+ # Parse the quoted tags
25
+ string.gsub!(/(\A|#{delimiter})\s*"(.*?)"\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
26
+ string.gsub!(/(\A|#{delimiter})\s*'(.*?)'\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
12
27
 
28
+ tag_list.add(string.split(delimiter))
29
+ end
30
+ end
31
+
32
+ ##
13
33
  # Add tags to the tag_list. Duplicate or blank tags will be ignored.
14
- #
15
- # tag_list.add("Fun", "Happy")
16
- #
17
34
  # Use the <tt>:parse</tt> option to add an unparsed tag string.
18
35
  #
36
+ # Example:
37
+ # tag_list.add("Fun", "Happy")
19
38
  # tag_list.add("Fun, Happy", :parse => true)
20
39
  def add(*names)
21
40
  extract_and_apply_options!(names)
@@ -24,12 +43,12 @@ class TagList < Array
24
43
  self
25
44
  end
26
45
 
46
+ ##
27
47
  # Remove specific tags from the tag_list.
48
+ # Use the <tt>:parse</tt> option to add an unparsed tag string.
28
49
  #
50
+ # Example:
29
51
  # tag_list.remove("Sad", "Lonely")
30
- #
31
- # Like #add, the <tt>:parse</tt> option can be used to remove multiple tags in a string.
32
- #
33
52
  # tag_list.remove("Sad, Lonely", :parse => true)
34
53
  def remove(*names)
35
54
  extract_and_apply_options!(names)
@@ -37,9 +56,11 @@ class TagList < Array
37
56
  self
38
57
  end
39
58
 
59
+ ##
40
60
  # Transform the tag_list into a tag string suitable for edting in a form.
41
61
  # The tags are joined with <tt>TagList.delimiter</tt> and quoted if necessary.
42
62
  #
63
+ # Example:
43
64
  # tag_list = TagList.new("Round", "Square,Cube")
44
65
  # tag_list.to_s # 'Round, "Square,Cube"'
45
66
  def to_s
@@ -51,7 +72,8 @@ class TagList < Array
51
72
  end.join(delimiter.ends_with?(" ") ? delimiter : "#{delimiter} ")
52
73
  end
53
74
 
54
- private
75
+ private
76
+
55
77
  # Remove whitespace, duplicates, and blanks.
56
78
  def clean!
57
79
  reject!(&:blank?)
@@ -70,26 +92,4 @@ class TagList < Array
70
92
  args.flatten!
71
93
  end
72
94
 
73
- class << self
74
-
75
- # Returns a new TagList using the given tag string.
76
- #
77
- # tag_list = TagList.from("One , Two, Three")
78
- # tag_list # ["One", "Two", "Three"]
79
- def from(string)
80
- string = string.join(", ") if string.respond_to?(:join)
81
-
82
- new.tap do |tag_list|
83
- string = string.to_s.dup
84
-
85
- # Parse the quoted tags
86
- string.gsub!(/(\A|#{delimiter})\s*"(.*?)"\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
87
- string.gsub!(/(\A|#{delimiter})\s*'(.*?)'\s*(#{delimiter}\s*|\z)/) { tag_list << $2; $3 }
88
-
89
- tag_list.add(string.split(delimiter))
90
- end
91
- end
92
-
93
- end
94
-
95
95
  end
metadata CHANGED
@@ -1,13 +1,12 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts-as-taggable-on
3
3
  version: !ruby/object:Gem::Version
4
- prerelease: true
4
+ prerelease: false
5
5
  segments:
6
6
  - 2
7
7
  - 0
8
8
  - 0
9
- - rc2
10
- version: 2.0.0.rc2
9
+ version: 2.0.0
11
10
  platform: ruby
12
11
  authors:
13
12
  - Michael Bleigh
@@ -84,13 +83,11 @@ required_ruby_version: !ruby/object:Gem::Requirement
84
83
  version: "0"
85
84
  required_rubygems_version: !ruby/object:Gem::Requirement
86
85
  requirements:
87
- - - ">"
86
+ - - ">="
88
87
  - !ruby/object:Gem::Version
89
88
  segments:
90
- - 1
91
- - 3
92
- - 1
93
- version: 1.3.1
89
+ - 0
90
+ version: "0"
94
91
  requirements: []
95
92
 
96
93
  rubyforge_project: