acts-as-taggable-on-mongoid 6.0.1.5 → 6.1.1.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (40) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -1
  3. data/.rubocop.yml +8 -10
  4. data/.ruby-version +1 -1
  5. data/Gemfile.lock +76 -82
  6. data/README.md +102 -28
  7. data/acts-as-taggable-on-mongoid.gemspec +3 -4
  8. data/lib/acts-as-taggable-on-mongoid.rb +9 -3
  9. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_associations.rb +12 -0
  10. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_fields.rb +4 -1
  11. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_methods.rb +21 -12
  12. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_migration.rb +46 -0
  13. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_scopes.rb +3 -2
  14. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_validations.rb +1 -1
  15. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_associations.rb +13 -1
  16. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_fields.rb +4 -2
  17. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_methods.rb +2 -2
  18. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_migration.rb +46 -0
  19. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_scopes.rb +7 -5
  20. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_validations.rb +2 -6
  21. data/lib/acts_as_taggable_on_mongoid/tag_list.rb +91 -4
  22. data/lib/acts_as_taggable_on_mongoid/taggable.rb +13 -1
  23. data/lib/acts_as_taggable_on_mongoid/taggable/changeable.rb +5 -4
  24. data/lib/acts_as_taggable_on_mongoid/taggable/core.rb +156 -34
  25. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition.rb +29 -50
  26. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/attributes.rb +57 -6
  27. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/changeable.rb +52 -39
  28. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/list_methods.rb +77 -0
  29. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/names.rb +12 -0
  30. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/all_tags_query.rb +1 -1
  31. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/any_tags_query.rb +1 -1
  32. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/exclude_tags_query.rb +1 -1
  33. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/match_all_tags_query.rb +1 -1
  34. data/lib/acts_as_taggable_on_mongoid/taggable/tagger_relation.rb +53 -0
  35. data/lib/acts_as_taggable_on_mongoid/taggable/utils/tag_list_diff.rb +9 -7
  36. data/lib/acts_as_taggable_on_mongoid/tagger.rb +67 -0
  37. data/lib/acts_as_taggable_on_mongoid/tagger/tag_methods.rb +74 -0
  38. data/lib/acts_as_taggable_on_mongoid/tagger_tag_list.rb +171 -0
  39. data/lib/acts_as_taggable_on_mongoid/version.rb +1 -1
  40. metadata +18 -26
@@ -31,10 +31,9 @@ Gem::Specification.new do |spec|
31
31
  spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
32
  spec.require_paths = ["lib"]
33
33
 
34
- spec.add_dependency "activesupport", "~> 4.2"
35
- spec.add_dependency "mongoid", ">= 5.2", "<= 7.0.2"
34
+ spec.add_dependency "activesupport", ">= 5.0"
35
+ spec.add_dependency "mongoid", ">= 6.1.1", "<= 7.0.2"
36
36
 
37
- spec.add_development_dependency "bundler", "~> 1.16"
38
37
  spec.add_development_dependency "codecov", "~> 0.1", "~> 0.1.0"
39
38
  spec.add_development_dependency "cornucopia"
40
39
  spec.add_development_dependency "database_cleaner"
@@ -45,7 +44,7 @@ Gem::Specification.new do |spec|
45
44
  spec.add_development_dependency "pronto-rails_best_practices"
46
45
  spec.add_development_dependency "pronto-reek"
47
46
  spec.add_development_dependency "pronto-rubocop"
48
- spec.add_development_dependency "rake", "~> 12.3"
47
+ spec.add_development_dependency "rake", "~> 13.0"
49
48
  spec.add_development_dependency "rspec", "~> 3.0"
50
49
  spec.add_development_dependency "rspec_junit_formatter", "~> 0.4.1"
51
50
  spec.add_development_dependency "rubocop"
@@ -11,11 +11,13 @@ module ActsAsTaggableOnMongoid
11
11
  eager_autoload do
12
12
  autoload :Configuration
13
13
  autoload :TagList
14
+ autoload :TaggerTagList
14
15
  autoload :GenericParser
15
16
  autoload :DefaultParser
16
17
  # autoload :TagsHelper
17
18
 
18
19
  autoload_under "taggable/tag_type_definition" do
20
+ autoload :ListMethods
19
21
  autoload :Attributes
20
22
  autoload "Changeable"
21
23
  autoload :Names
@@ -42,11 +44,16 @@ module ActsAsTaggableOnMongoid
42
44
  autoload :ListTags
43
45
  autoload :TaggedWith
44
46
  autoload :TaggedWithQuery
45
- # autoload :Ownership
47
+ autoload :TaggerRelation
46
48
  # autoload :Related
47
49
  end
48
50
 
51
+ autoload_under :Tagger do
52
+ autoload "TagMethods"
53
+ end
54
+
49
55
  autoload :Taggable
56
+ autoload :Tagger
50
57
 
51
58
  autoload_under "models/concerns" do
52
59
  autoload :TagFields
@@ -67,7 +74,6 @@ module ActsAsTaggableOnMongoid
67
74
  autoload_under :Models do
68
75
  autoload :Tag
69
76
  autoload :Tagging
70
- # autoload :Tagger
71
77
  end
72
78
 
73
79
  autoload_under :Errors do
@@ -102,5 +108,5 @@ end
102
108
 
103
109
  ::ActiveSupport.on_load(:mongoid) do
104
110
  include ActsAsTaggableOnMongoid::Taggable
105
- # include ActsAsTaggableOn::Tagger
111
+ include ActsAsTaggableOnMongoid::Tagger
106
112
  end
@@ -10,6 +10,18 @@ module ActsAsTaggableOnMongoid
10
10
  ### ASSOCIATIONS:
11
11
 
12
12
  has_many :taggings, dependent: :destroy, class_name: "ActsAsTaggableOnMongoid::Models::Tagging"
13
+ belongs_to :owner, polymorphic: true, optional: true, index: true
14
+
15
+ after_save :atom_unset_blank_owner
16
+ end
17
+
18
+ private
19
+
20
+ def atom_unset_blank_owner
21
+ return if !attributes.key?("owner_id") && !attributes.key?("owner_type")
22
+ return if owner_id.present? && owner_type.present?
23
+
24
+ unset(:owner_id, :owner_type)
13
25
  end
14
26
  end
15
27
  end
@@ -17,7 +17,10 @@ module ActsAsTaggableOnMongoid
17
17
 
18
18
  # field :type, type: String
19
19
 
20
- index({ name: 1, taggable_type: 1, context: 1 }, unique: true)
20
+ index({ name: 1, context: 1, taggable_type: 1, owner_id: 1, owner_type: 1 },
21
+ unique: true,
22
+ name: "name_taggable_type_context_owner")
23
+ index(owner_id: 1, owner_type: 1)
21
24
  end
22
25
  end
23
26
  end
@@ -10,7 +10,13 @@ module ActsAsTaggableOnMongoid
10
10
 
11
11
  # rubocop:disable Metrics/BlockLength
12
12
  class_methods do
13
- def find_or_create_all_with_like_by_name(tag_definition, *list)
13
+ def find_or_create_tagger_list_with_like_by_name(tag_definition, tagger_list)
14
+ tagger_list.each_with_object([]) do |(tagger, tag_list), array|
15
+ array.concat find_or_create_all_with_like_by_name_owner tag_definition, tagger, tag_list
16
+ end
17
+ end
18
+
19
+ def find_or_create_all_with_like_by_name_owner(tag_definition, owner, *list)
14
20
  list = ActsAsTaggableOnMongoid::TagList.new(tag_definition, *Array.wrap(list).flatten)
15
21
 
16
22
  return [] if list.empty?
@@ -19,9 +25,7 @@ module ActsAsTaggableOnMongoid
19
25
  begin
20
26
  tries ||= 3
21
27
 
22
- existing_tag = tag_definition.tags_table.for_tag(tag_definition).named(tag_name).first
23
-
24
- existing_tag || create_tag(tag_definition, tag_name)
28
+ find_or_create_tag(tag_name, tag_definition, owner)
25
29
  rescue Mongoid::Errors::Validations
26
30
  # :nocov:
27
31
  if (tries -= 1).positive?
@@ -34,21 +38,26 @@ module ActsAsTaggableOnMongoid
34
38
  end
35
39
  end
36
40
 
37
- def create_tag(tag_definition, name)
41
+ # :reek:UtilityFunction
42
+ def create_tag(tag_definition, owner, name)
38
43
  tag_definition.tags_table.create!(name: name,
44
+ owner: owner,
39
45
  context: tag_definition.tag_type,
40
46
  taggable_type: tag_definition.owner.name)
41
47
  end
42
48
 
43
49
  def as_8bit_ascii(string)
44
50
  string = string.to_s
45
- if defined?(Encoding)
46
- string.dup.force_encoding("BINARY")
47
- else
48
- # :nocov:
49
- string.mb_chars
50
- # :nocov:
51
- end
51
+
52
+ string.mb_chars
53
+ end
54
+
55
+ private
56
+
57
+ def find_or_create_tag(tag_name, tag_definition, owner)
58
+ existing_tag = tag_definition.tags_table.for_tag(tag_definition).named(tag_name).owned_by(owner).first
59
+
60
+ existing_tag || create_tag(tag_definition, owner, tag_name)
52
61
  end
53
62
  end
54
63
 
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Models
5
+ module Concerns
6
+ # A module that defines methods to migrate a Tag model.
7
+ #
8
+ # Mongoid does not have a standardized migration scheme, but migrations of one kind or another
9
+ # are often a fact of life, and are in this situation because of the need to change an existing
10
+ # index.
11
+ #
12
+ # Using whatever migration methodology you prefer, you need to run the appropriate migration method
13
+ # or methods on the Tag module used by your project.
14
+ #
15
+ # The migrations are named for the ActsAsTaggableMongoid versions upon which they need to be run.
16
+ # Run the correct migration(s) for the version of ActsAsTaggableOnMongoid you are currently using
17
+ # This module does not and cannot verify the version you are migrating from nor if the migration
18
+ # has been run before. Doing so is assumed to be the responsibility of your chosen
19
+ # Migration methodology.
20
+ #
21
+ # Example:
22
+ #
23
+ # # When a migration is needed, the method "up" is called:
24
+ # def up
25
+ # TagModel.include ActsAsTaggableOnMongoid::Models::Concerns::TagMigration
26
+ # TagModel.atom_migrate_up_6_0_1_to_6_1_1
27
+ # end
28
+ #
29
+ # The migration methods should only be run once if possible, but every reasonable effort is made to
30
+ # ensure that the migration methods are safe to re-run.
31
+ module TagMigration
32
+ extend ActiveSupport::Concern
33
+
34
+ class_methods do
35
+ # :reek:UncommunicativeMethodName - The name indicates what gem versions the migration is from/to
36
+ def atom_migrate_up_6_0_1_to_6_1_1
37
+ indexes = collection.indexes
38
+ indexes.drop_one "name_1_taggable_type_1_context_1" if indexes.get "name_1_taggable_type_1_context_1"
39
+
40
+ create_indexes
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -15,9 +15,10 @@ module ActsAsTaggableOnMongoid
15
15
  scope :named_any, ->(*names) { where(:name.in => names.map { |name| as_8bit_ascii(name) }) }
16
16
  scope :named_like, ->(name) { where(name: /#{as_8bit_ascii(name)}/i) }
17
17
  scope :named_like_any, ->(*names) { where(:name.in => names.map { |name| /#{as_8bit_ascii(name)}/i }) }
18
- scope :for_context, ->(context) { where(context: context) }
18
+ scope :owned_by, ->(owner) { owner ? where(owner: owner) : where(:owner_id.exists => false) }
19
+ scope :for_tag_type, ->(context) { where(context: context) }
19
20
  scope :for_taggable_class, ->(taggable_type) { where(taggable_type: taggable_type.name) }
20
- scope :for_tag, ->(tag_definition) { for_taggable_class(tag_definition.owner).for_context(tag_definition.tag_type) }
21
+ scope :for_tag, ->(tag_definition) { for_taggable_class(tag_definition.owner).for_tag_type(tag_definition.tag_type) }
21
22
  end
22
23
  end
23
24
  end
@@ -12,7 +12,7 @@ module ActsAsTaggableOnMongoid
12
12
  validates :name, presence: true
13
13
  validates :context, presence: true
14
14
  validates :taggable_type, presence: true
15
- validates :name, uniqueness: { scope: %i[context taggable_type] }
15
+ validates :name, uniqueness: { scope: %i[context taggable_type owner] }
16
16
  end
17
17
  end
18
18
  end
@@ -7,9 +7,21 @@ module ActsAsTaggableOnMongoid
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
+ ### ASSOCIATIONS:
11
+
10
12
  belongs_to :tag, counter_cache: true, inverse_of: :taggings
13
+ belongs_to :tagger, polymorphic: true, optional: true
11
14
  belongs_to :taggable, polymorphic: true
12
- # belongs_to :tagger, { polymorphic: true, optional: true }
15
+
16
+ before_validation :atom_unset_blank_owner
17
+ end
18
+
19
+ private
20
+
21
+ def atom_unset_blank_owner
22
+ return if tagger_id.present? && tagger_type.present?
23
+
24
+ unset(:tagger_id, :tagger_type)
13
25
  end
14
26
  end
15
27
  end
@@ -13,10 +13,12 @@ module ActsAsTaggableOnMongoid
13
13
  field :tag_name, type: String
14
14
  field :context, type: String
15
15
 
16
- # If/when adding the concept of a tagger, this index will need to be changed.
17
- index({ taggable_id: 1, taggable_type: 1, context: 1, tag_name: 1 }, unique: true, name: "tagging_taggable_context_tag_name")
16
+ index({ taggable_id: 1, taggable_type: 1, context: 1, tagger_id: 1, tagger_type: 1, tag_name: 1 },
17
+ unique: true,
18
+ name: "tagging_taggable_tagger_context_tag_name")
18
19
  index(tag_name: 1)
19
20
  index(tag_id: 1, tag_type: 1)
21
+ index(tagger_id: 1, tagger_type: 1)
20
22
  end
21
23
  end
22
24
  end
@@ -32,7 +32,7 @@ module ActsAsTaggableOnMongoid
32
32
 
33
33
  return unless tag_definition
34
34
 
35
- tag_list = taggable.public_send(tag_definition.tag_list_name)
35
+ tag_list = taggable.public_send(tag_definition.tagger_tag_lists_name)[tagger]
36
36
  tag_list.add_tagging(self)
37
37
  end
38
38
 
@@ -45,7 +45,7 @@ module ActsAsTaggableOnMongoid
45
45
 
46
46
  return unless tag_definition
47
47
 
48
- taggable_was.public_send(tag_definition.tag_list_name).remove(tag_name_was)
48
+ taggable_was.public_send(tag_definition.tagger_tag_lists_name)[tagger].remove(tag_name_was)
49
49
  end
50
50
  end
51
51
  end
@@ -0,0 +1,46 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Models
5
+ module Concerns
6
+ # A module that defines methods to migrate a Tag model.
7
+ #
8
+ # Mongoid does not have a standardized migration scheme, but migrations of one kind or another
9
+ # are often a fact of life, and are in this situation because of the need to change an existing
10
+ # index.
11
+ #
12
+ # Using whatever migration methodology you prefer, you need to run the appropriate migration method
13
+ # or methods on the Tag module used by your project.
14
+ #
15
+ # The migrations are named for the ActsAsTaggableMongoid versions upon which they need to be run.
16
+ # Run the correct migration(s) for the version of ActsAsTaggableOnMongoid you are currently using
17
+ # This module does not and cannot verify the version you are migrating from nor if the migration
18
+ # has been run before. Doing so is assumed to be the responsibility of your chosen
19
+ # Migration methodology.
20
+ #
21
+ # Example:
22
+ #
23
+ # # When a migration is needed, the method "up" is called:
24
+ # def up
25
+ # TaggingModel.include ActsAsTaggableOnMongoid::Models::Concerns::TaggingMigration
26
+ # TaggingModel.atom_migrate_up_6_0_1_to_6_1_1
27
+ # end
28
+ #
29
+ # The migration methods should only be run once if possible, but every reasonable effort is made to
30
+ # ensure that the migration methods are safe to re-run.
31
+ module TaggingMigration
32
+ extend ActiveSupport::Concern
33
+
34
+ class_methods do
35
+ # :reek:UncommunicativeMethodName - The name indicates what gem versions the migration is from/to
36
+ def atom_migrate_up_6_0_1_to_6_1_1
37
+ indexes = collection.indexes
38
+ indexes.drop_one "tagging_taggable_context_tag_name" if indexes.get "tagging_taggable_context_tag_name"
39
+
40
+ create_indexes
41
+ end
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
@@ -10,12 +10,14 @@ module ActsAsTaggableOnMongoid
10
10
  DEFAULT_CONTEXT = "tags"
11
11
 
12
12
  included do
13
- # scope :owned_by, ->(owner) { where(tagger: owner) }
14
- # scope :not_owned, -> { where(tagger_id: nil, tagger_type: nil) }
13
+ # aliased scopes from ActsAsTaggable
14
+ scope :owned_by, ->(tagger) { tagged_by(tagger) }
15
+ scope :not_owned, -> { tagged_by(nil) }
15
16
 
16
- scope :by_contexts, ->(*contexts) { where(:context.in => Array.wrap(contexts.presence || DEFAULT_CONTEXT)) }
17
- scope :by_context, ->(context = DEFAULT_CONTEXT) { by_contexts(context.to_s) }
18
- scope :for_tag, ->(tag_definition) { where(taggable_type: tag_definition.owner.name).by_context(tag_definition.tag_type) }
17
+ scope :by_tag_types, ->(*tag_types) { where(:context.in => Array.wrap(tag_types.presence || DEFAULT_CONTEXT)) }
18
+ scope :by_tag_type, ->(tag_type = DEFAULT_CONTEXT) { by_tag_types(tag_type.to_s) }
19
+ scope :tagged_by, ->(tagger) { tagger ? where(tagger: tagger) : where(:tagger_id.exists => false) }
20
+ scope :for_tag, ->(tag_definition) { where(taggable_type: tag_definition.owner.name).by_tag_type(tag_definition.tag_type) }
19
21
  end
20
22
  end
21
23
  end
@@ -10,13 +10,9 @@ module ActsAsTaggableOnMongoid
10
10
  included do
11
11
  validates :tag_name, presence: true
12
12
  validates :context, presence: true
13
- validates :tag, presence: true
14
- validates :taggable, presence: true
15
13
 
16
- # validates :tag_id, uniqueness: {scope: [:taggable_type, :taggable_id, :context, :tagger_id, :tagger_type]}
17
- validates :tag_name, uniqueness: { scope: %i[taggable_type taggable_id context] }
18
- # validates :tag_id, uniqueness: {scope: [:taggable_type, :taggable_id, :context, :tagger_id, :tagger_type]}
19
- validates :tag_id, uniqueness: { scope: %i[taggable_type taggable_id context] }
14
+ validates :tag_name, uniqueness: { scope: %i[taggable_id taggable_type context tagger_id tagger_type] }
15
+ validates :tag_id, uniqueness: { scope: %i[taggable_id taggable_type context tagger_id tagger_type] }
20
16
  end
21
17
  end
22
18
  end
@@ -12,6 +12,16 @@ module ActsAsTaggableOnMongoid
12
12
  #
13
13
  # If the input value(s) are to be parsed, then all values passed in are parsed.
14
14
  #
15
+ # Options:
16
+ # parse - True/False - indicates if all of the strings that are passed in are to be parsed
17
+ # to split them into an array of strings.
18
+ # Please note - if the passed in value is an array of strings, every string in the array
19
+ # will be parsed. If it is a single array, then just that string is parsed.
20
+ # parser - Class - A class that is used to parse the passed in strings.
21
+ # If this parameter is supplied, parse is assumed to be truthy even if it is not passed in.
22
+ # tagger - object - An object that is to be used as the Tagger for the Taggable object.
23
+ # This parameter is ignored if the tag does not support Taggers.
24
+ #
15
25
  # Examples:
16
26
  # TagList.new(tag_definition, "value 1", "value 2")
17
27
  # # > TagList<> ["value 1", "value 2"]
@@ -38,6 +48,40 @@ module ActsAsTaggableOnMongoid
38
48
  add(*args)
39
49
  end
40
50
 
51
+ class << self
52
+ def new_taggable_list(tag_definition, taggable)
53
+ list = ActsAsTaggableOnMongoid::TagList.new(tag_definition)
54
+
55
+ list.taggable = taggable
56
+
57
+ list
58
+ end
59
+ end
60
+
61
+ def dup
62
+ list = ActsAsTaggableOnMongoid::TagList.new(tag_definition, *self)
63
+ list.tagger = instance_variable_get(:@tagger) if instance_variable_defined?(:@tagger)
64
+ list.taggable = taggable
65
+
66
+ list
67
+ end
68
+
69
+ def tagger=(value)
70
+ return unless tag_definition.tagger?
71
+
72
+ instance_variable_set(:@tagger, value)
73
+ end
74
+
75
+ def tagger
76
+ return nil unless tag_definition.tagger?
77
+ return tag_definition.default_tagger(taggable) unless instance_variable_defined?(:@tagger)
78
+
79
+ tagger = instance_variable_get(:@tagger)
80
+ tagger = taggable&.public_send(tagger) if tagger.is_a?(Symbol)
81
+
82
+ instance_variable_set(:@tagger, tagger)
83
+ end
84
+
41
85
  ##
42
86
  # Add tags to the tag_list. Duplicate or blank tags will be ignored.
43
87
  # Use the <tt>:parse</tt> option to add an unparsed tag string.
@@ -53,6 +97,17 @@ module ActsAsTaggableOnMongoid
53
97
  self
54
98
  end
55
99
 
100
+ ##
101
+ # Replaces the tags with the tags passed in.
102
+ #
103
+ # Example:
104
+ # tag_list.set("Fun", "Happy")
105
+ # tag_list.set("Fun, Happy", :parse => true)
106
+ def set(*names)
107
+ clear
108
+ add(*names)
109
+ end
110
+
56
111
  # Append---Add the tag to the tag_list. This
57
112
  # expression returns the tag_list itself, so several appends
58
113
  # may be chained together.
@@ -63,7 +118,13 @@ module ActsAsTaggableOnMongoid
63
118
  # Concatenation --- Returns a new tag list built by concatenating the
64
119
  # two tag lists together to produce a third tag list.
65
120
  def +(other)
66
- TagList.new(tag_definition).add(*self).add(other)
121
+ dup.add(other)
122
+ end
123
+
124
+ # Removal --- Returns a new tag list built by removing the
125
+ # passed in tag list to produce a third tag list.
126
+ def -(other)
127
+ dup.remove(other)
67
128
  end
68
129
 
69
130
  # Appends the elements of +other_tag_list+ to +self+.
@@ -75,6 +136,27 @@ module ActsAsTaggableOnMongoid
75
136
  self
76
137
  end
77
138
 
139
+ # Appends the elements of +other_tag_list+ to +self+.
140
+ def clear
141
+ notify_will_change
142
+
143
+ super
144
+
145
+ self
146
+ end
147
+
148
+ # Appends the elements of +other_tag_list+ to +self+.
149
+ def silent_concat(other_tag_list)
150
+ temp_taggable = taggable
151
+ self.taggable = nil
152
+
153
+ concat(other_tag_list)
154
+
155
+ self.taggable = temp_taggable
156
+
157
+ self
158
+ end
159
+
78
160
  ##
79
161
  # Remove specific tags from the tag_list.
80
162
  # Use the <tt>:parse</tt> option to add an unparsed tag string.
@@ -151,13 +233,18 @@ module ActsAsTaggableOnMongoid
151
233
  self
152
234
  end
153
235
 
154
- # :reek:FeatureEnvy
155
- # :reek:DuplicateMethodCall
156
236
  def extract_and_apply_options!(args)
157
237
  dup_args = args.dup
158
238
  options = dup_args.extract_options!.dup
159
- options.assert_valid_keys :parse, :parser
160
239
 
240
+ options.assert_valid_keys :parse, :parser, :tagger
241
+
242
+ instance_variable_set(:@tagger, options[:tagger]) if options.key?(:tagger) && tag_definition.tagger?
243
+
244
+ parse_args_values(dup_args, options)
245
+ end
246
+
247
+ def parse_args_values(dup_args, options)
161
248
  options_parser = options[:parser]
162
249
  run_parser = options_parser || tag_definition.parser
163
250