acts-as-taggable-on 2.0.6 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/.gitignore +10 -0
  2. data/.rspec +2 -0
  3. data/.travis.yml +9 -0
  4. data/CHANGELOG +10 -0
  5. data/Gemfile +2 -9
  6. data/Guardfile +5 -0
  7. data/README.rdoc +89 -66
  8. data/Rakefile +9 -55
  9. data/acts-as-taggable-on.gemspec +28 -0
  10. data/lib/acts-as-taggable-on/version.rb +4 -0
  11. data/lib/acts-as-taggable-on.rb +33 -4
  12. data/lib/acts_as_taggable_on/acts_as_taggable_on/cache.rb +4 -4
  13. data/lib/acts_as_taggable_on/acts_as_taggable_on/collection.rb +38 -43
  14. data/lib/acts_as_taggable_on/acts_as_taggable_on/core.rb +146 -38
  15. data/lib/acts_as_taggable_on/acts_as_taggable_on/dirty.rb +37 -0
  16. data/lib/acts_as_taggable_on/acts_as_taggable_on/ownership.rb +36 -11
  17. data/lib/acts_as_taggable_on/acts_as_taggable_on/related.rb +23 -15
  18. data/lib/acts_as_taggable_on/tag.rb +16 -13
  19. data/lib/acts_as_taggable_on/tag_list.rb +13 -12
  20. data/lib/acts_as_taggable_on/taggable.rb +102 -0
  21. data/lib/acts_as_taggable_on/{acts_as_tagger.rb → tagger.rb} +3 -3
  22. data/lib/acts_as_taggable_on/tagging.rb +12 -2
  23. data/lib/acts_as_taggable_on/tags_helper.rb +2 -2
  24. data/lib/acts_as_taggable_on/utils.rb +34 -0
  25. data/lib/generators/acts_as_taggable_on/migration/migration_generator.rb +9 -2
  26. data/lib/generators/acts_as_taggable_on/migration/templates/active_record/migration.rb +3 -1
  27. data/spec/acts_as_taggable_on/acts_as_taggable_on_spec.rb +300 -54
  28. data/spec/acts_as_taggable_on/tag_list_spec.rb +84 -61
  29. data/spec/acts_as_taggable_on/tag_spec.rb +51 -13
  30. data/spec/acts_as_taggable_on/taggable_spec.rb +261 -34
  31. data/spec/acts_as_taggable_on/tagger_spec.rb +36 -15
  32. data/spec/acts_as_taggable_on/tagging_spec.rb +2 -5
  33. data/spec/acts_as_taggable_on/tags_helper_spec.rb +16 -0
  34. data/spec/acts_as_taggable_on/utils_spec.rb +21 -0
  35. data/spec/database.yml.sample +4 -2
  36. data/spec/generators/acts_as_taggable_on/migration/migration_generator_spec.rb +22 -0
  37. data/spec/models.rb +19 -1
  38. data/spec/schema.rb +18 -0
  39. data/spec/spec_helper.rb +30 -7
  40. data/uninstall.rb +1 -0
  41. metadata +137 -51
  42. data/VERSION +0 -1
  43. data/generators/acts_as_taggable_on_migration/acts_as_taggable_on_migration_generator.rb +0 -7
  44. data/generators/acts_as_taggable_on_migration/templates/migration.rb +0 -29
  45. data/lib/acts_as_taggable_on/acts_as_taggable_on.rb +0 -53
  46. data/lib/acts_as_taggable_on/compatibility/Gemfile +0 -8
  47. data/lib/acts_as_taggable_on/compatibility/active_record_backports.rb +0 -17
  48. data/lib/acts_as_taggable_on/compatibility/postgresql.rb +0 -44
  49. data/spec/database.yml +0 -17
@@ -0,0 +1,102 @@
1
+ module ActsAsTaggableOn
2
+ module Taggable
3
+ def taggable?
4
+ false
5
+ end
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
14
+ def acts_as_taggable
15
+ acts_as_taggable_on :tags
16
+ end
17
+
18
+ ##
19
+ # This is an alias for calling <tt>acts_as_ordered_taggable_on :tags</tt>.
20
+ #
21
+ # Example:
22
+ # class Book < ActiveRecord::Base
23
+ # acts_as_ordered_taggable
24
+ # end
25
+ def acts_as_ordered_taggable
26
+ acts_as_ordered_taggable_on :tags
27
+ end
28
+
29
+ ##
30
+ # Make a model taggable on specified contexts.
31
+ #
32
+ # @param [Array] tag_types An array of taggable contexts
33
+ #
34
+ # Example:
35
+ # class User < ActiveRecord::Base
36
+ # acts_as_taggable_on :languages, :skills
37
+ # end
38
+ def acts_as_taggable_on(*tag_types)
39
+ taggable_on(false, tag_types)
40
+ end
41
+
42
+
43
+ ##
44
+ # Make a model taggable on specified contexts
45
+ # and preserves the order in which tags are created
46
+ #
47
+ # @param [Array] tag_types An array of taggable contexts
48
+ #
49
+ # Example:
50
+ # class User < ActiveRecord::Base
51
+ # acts_as_ordered_taggable_on :languages, :skills
52
+ # end
53
+ def acts_as_ordered_taggable_on(*tag_types)
54
+ taggable_on(true, tag_types)
55
+ end
56
+
57
+ private
58
+
59
+ # Make a model taggable on specified contexts
60
+ # and optionally preserves the order in which tags are created
61
+ #
62
+ # Seperate methods used above for backwards compatibility
63
+ # so that the original acts_as_taggable_on method is unaffected
64
+ # as it's not possible to add another arguement to the method
65
+ # without the tag_types being enclosed in square brackets
66
+ #
67
+ # NB: method overridden in core module in order to create tag type
68
+ # associations and methods after this logic has executed
69
+ #
70
+ def taggable_on(preserve_tag_order, *tag_types)
71
+ tag_types = tag_types.to_a.flatten.compact.map(&:to_sym)
72
+
73
+ if taggable?
74
+ self.tag_types = (self.tag_types + tag_types).uniq
75
+ self.preserve_tag_order = preserve_tag_order
76
+ else
77
+ class_attribute :tag_types
78
+ self.tag_types = tag_types
79
+ class_attribute :preserve_tag_order
80
+ self.preserve_tag_order = preserve_tag_order
81
+
82
+ class_eval do
83
+ has_many :taggings, :as => :taggable, :dependent => :destroy, :include => :tag, :class_name => "ActsAsTaggableOn::Tagging"
84
+ has_many :base_tags, :through => :taggings, :source => :tag, :class_name => "ActsAsTaggableOn::Tag"
85
+
86
+ def self.taggable?
87
+ true
88
+ end
89
+
90
+ include ActsAsTaggableOn::Utils
91
+ include ActsAsTaggableOn::Taggable::Core
92
+ include ActsAsTaggableOn::Taggable::Collection
93
+ include ActsAsTaggableOn::Taggable::Cache
94
+ include ActsAsTaggableOn::Taggable::Ownership
95
+ include ActsAsTaggableOn::Taggable::Related
96
+ include ActsAsTaggableOn::Taggable::Dirty
97
+ end
98
+ end
99
+ end
100
+
101
+ end
102
+ end
@@ -31,7 +31,7 @@ module ActsAsTaggableOn
31
31
 
32
32
  module InstanceMethods
33
33
  ##
34
- # Tag a taggable model with tags that are owned by the tagger.
34
+ # Tag a taggable model with tags that are owned by the tagger.
35
35
  #
36
36
  # @param taggable The object that will be tagged
37
37
  # @param [Hash] options An hash with options. Available options are:
@@ -42,7 +42,7 @@ module ActsAsTaggableOn
42
42
  # @user.tag(@photo, :with => "paris, normandy", :on => :locations)
43
43
  def tag(taggable, opts={})
44
44
  opts.reverse_merge!(:force => true)
45
-
45
+ skip_save = opts.delete(:skip_save)
46
46
  return false unless taggable.respond_to?(:is_taggable?) && taggable.is_taggable?
47
47
 
48
48
  raise "You need to specify a tag context using :on" unless opts.has_key?(:on)
@@ -50,7 +50,7 @@ module ActsAsTaggableOn
50
50
  raise "No context :#{opts[:on]} defined in #{taggable.class.to_s}" unless (opts[:force] || taggable.tag_types.include?(opts[:on]))
51
51
 
52
52
  taggable.set_owner_tag_list_on(self, opts[:on].to_s, opts[:with])
53
- taggable.save
53
+ taggable.save unless skip_save
54
54
  end
55
55
 
56
56
  def is_tagger?
@@ -1,7 +1,5 @@
1
1
  module ActsAsTaggableOn
2
2
  class Tagging < ::ActiveRecord::Base #:nodoc:
3
- include ActsAsTaggableOn::ActiveRecord::Backports if ::ActiveRecord::VERSION::MAJOR < 3
4
-
5
3
  attr_accessible :tag,
6
4
  :tag_id,
7
5
  :context,
@@ -20,5 +18,17 @@ module ActsAsTaggableOn
20
18
  validates_presence_of :tag_id
21
19
 
22
20
  validates_uniqueness_of :tag_id, :scope => [ :taggable_type, :taggable_id, :context, :tagger_id, :tagger_type ]
21
+
22
+ after_destroy :remove_unused_tags
23
+
24
+ private
25
+
26
+ def remove_unused_tags
27
+ if ActsAsTaggableOn.remove_unused_tags
28
+ if tag.taggings.count.zero?
29
+ tag.destroy
30
+ end
31
+ end
32
+ end
23
33
  end
24
34
  end
@@ -9,8 +9,8 @@ module ActsAsTaggableOn
9
9
  max_count = tags.sort_by(&:count).last.count.to_f
10
10
 
11
11
  tags.each do |tag|
12
- index = ((tag.count / max_count) * (classes.size - 1)).round
13
- yield tag, classes[index]
12
+ index = ((tag.count / max_count) * (classes.size - 1))
13
+ yield tag, classes[index.nan? ? 0 : index.round]
14
14
  end
15
15
  end
16
16
  end
@@ -0,0 +1,34 @@
1
+ module ActsAsTaggableOn
2
+ module Utils
3
+ def self.included(base)
4
+
5
+ base.send :include, ActsAsTaggableOn::Utils::OverallMethods
6
+ base.extend ActsAsTaggableOn::Utils::OverallMethods
7
+ end
8
+
9
+ module OverallMethods
10
+ def using_postgresql?
11
+ ::ActiveRecord::Base.connection && ::ActiveRecord::Base.connection.adapter_name == 'PostgreSQL'
12
+ end
13
+
14
+ def using_sqlite?
15
+ ::ActiveRecord::Base.connection && ::ActiveRecord::Base.connection.adapter_name == 'SQLite'
16
+ end
17
+
18
+ def sha_prefix(string)
19
+ Digest::SHA1.hexdigest("#{string}#{rand}")[0..6]
20
+ end
21
+
22
+ private
23
+ def like_operator
24
+ using_postgresql? ? 'ILIKE' : 'LIKE'
25
+ end
26
+
27
+ # escape _ and % characters in strings, since these are wildcards in SQL.
28
+ def escape_like(str)
29
+ str.gsub(/[!%_]/){ |x| '!' + x }
30
+ end
31
+ end
32
+
33
+ end
34
+ end
@@ -1,3 +1,4 @@
1
+ require 'rails/generators'
1
2
  require 'rails/generators/migration'
2
3
 
3
4
  module ActsAsTaggableOn
@@ -18,8 +19,14 @@ module ActsAsTaggableOn
18
19
  [:active_record].include? orm
19
20
  end
20
21
 
21
- def self.next_migration_number(path)
22
- Time.now.utc.strftime("%Y%m%d%H%M%S")
22
+ def self.next_migration_number(dirname)
23
+ if ActiveRecord::Base.timestamped_migrations
24
+ migration_number = Time.now.utc.strftime("%Y%m%d%H%M%S").to_i
25
+ migration_number += 1
26
+ migration_number.to_s
27
+ else
28
+ "%.3d" % (current_migration_number(dirname) + 1)
29
+ end
23
30
  end
24
31
 
25
32
  def create_migration_file
@@ -12,7 +12,9 @@ class ActsAsTaggableOnMigration < ActiveRecord::Migration
12
12
  t.references :taggable, :polymorphic => true
13
13
  t.references :tagger, :polymorphic => true
14
14
 
15
- t.string :context
15
+ # limit is created to prevent mysql error o index lenght for myisam table type.
16
+ # http://bit.ly/vgW2Ql
17
+ t.string :context, :limit => 128
16
18
 
17
19
  t.datetime :created_at
18
20
  end