acts-as-taggable-on-mongoid 6.0.1.4 → 6.1.1.11

Sign up to get free protection for your applications and to get access to all the features.
Files changed (45) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +2 -1
  3. data/.rubocop.yml +402 -38
  4. data/.ruby-version +1 -1
  5. data/Gemfile.lock +110 -110
  6. data/README.md +103 -28
  7. data/acts-as-taggable-on-mongoid.gemspec +5 -5
  8. data/lib/acts-as-taggable-on-mongoid.rb +11 -4
  9. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_associations.rb +14 -0
  10. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_fields.rb +6 -1
  11. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_hooks.rb +68 -0
  12. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_methods.rb +36 -22
  13. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_migration.rb +46 -0
  14. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_model.rb +3 -0
  15. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_scopes.rb +5 -2
  16. data/lib/acts_as_taggable_on_mongoid/models/concerns/tag_validations.rb +3 -1
  17. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_associations.rb +20 -2
  18. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_fields.rb +6 -2
  19. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_methods.rb +4 -2
  20. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_migration.rb +46 -0
  21. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_model.rb +2 -0
  22. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_scopes.rb +9 -5
  23. data/lib/acts_as_taggable_on_mongoid/models/concerns/tagging_validations.rb +4 -6
  24. data/lib/acts_as_taggable_on_mongoid/tag_list.rb +91 -4
  25. data/lib/acts_as_taggable_on_mongoid/taggable.rb +22 -3
  26. data/lib/acts_as_taggable_on_mongoid/taggable/cache.rb +30 -0
  27. data/lib/acts_as_taggable_on_mongoid/taggable/changeable.rb +5 -4
  28. data/lib/acts_as_taggable_on_mongoid/taggable/core.rb +157 -34
  29. data/lib/acts_as_taggable_on_mongoid/taggable/list_tags.rb +1 -0
  30. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition.rb +43 -50
  31. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/attributes.rb +70 -6
  32. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/changeable.rb +52 -39
  33. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/list_methods.rb +77 -0
  34. data/lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/names.rb +12 -0
  35. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/all_tags_query.rb +1 -1
  36. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/any_tags_query.rb +1 -1
  37. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/exclude_tags_query.rb +1 -1
  38. data/lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/match_all_tags_query.rb +1 -1
  39. data/lib/acts_as_taggable_on_mongoid/taggable/tagger_relation.rb +53 -0
  40. data/lib/acts_as_taggable_on_mongoid/taggable/utils/tag_list_diff.rb +9 -7
  41. data/lib/acts_as_taggable_on_mongoid/tagger.rb +67 -0
  42. data/lib/acts_as_taggable_on_mongoid/tagger/tag_methods.rb +74 -0
  43. data/lib/acts_as_taggable_on_mongoid/tagger_tag_list.rb +171 -0
  44. data/lib/acts_as_taggable_on_mongoid/version.rb +1 -1
  45. metadata +43 -29
@@ -58,6 +58,7 @@ module ActsAsTaggableOnMongoid
58
58
  self.my_tag_types = new_tag_types
59
59
  tag_definition = new_tag_types[tag_type] = ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition.new(self, tag_type, options)
60
60
 
61
+ tag_definition.define_cache_field
61
62
  tag_definition.define_base_relations
62
63
  tag_definition.define_relations
63
64
  tag_definition.add_tag_list
@@ -13,27 +13,20 @@ module ActsAsTaggableOnMongoid
13
13
  attr_reader :owner,
14
14
  :tag_type
15
15
 
16
+ include ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition::ListMethods
16
17
  include ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition::Attributes
17
18
  include ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition::Names
18
19
  include ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition::Changeable
19
20
 
20
21
  def initialize(owner, tag_type, options = {})
21
- options = options.dup
22
+ options = ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition.extract_tag_definition_options(options)
22
23
 
23
- options.assert_valid_keys(:parser,
24
- :preserve_tag_order,
25
- :cached_in_model,
26
- :force_lowercase,
27
- :force_parameterize,
28
- :remove_unused_tags,
29
- :tags_table,
30
- :taggings_table,
31
- :default)
32
-
33
- self.default_value = options.delete(:default)
24
+ default_option = options.delete(:default)
34
25
 
35
26
  save_options(options)
36
27
 
28
+ self.default_value = default_option
29
+
37
30
  @owner = owner
38
31
  @tag_type = tag_type
39
32
  end
@@ -44,11 +37,12 @@ module ActsAsTaggableOnMongoid
44
37
  cached_in_model
45
38
  force_lowercase
46
39
  force_parameterize
40
+ owner_id_field
47
41
  remove_unused_tags
48
42
  tags_table
49
43
  taggings_table].each_with_object({}) { |dup_key, opts_hash| opts_hash[dup_key] = tag_definition.public_send(dup_key) }
50
44
 
51
- dup_hash[:default] = [tag_definition.default, parse: false]
45
+ dup_hash[:default] = tag_definition.default.dup
52
46
 
53
47
  ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition.new klass,
54
48
  tag_definition.tag_type,
@@ -83,6 +77,18 @@ module ActsAsTaggableOnMongoid
83
77
  end
84
78
  end
85
79
 
80
+ def define_cache_field
81
+ tag_definition = self
82
+
83
+ return unless tag_definition.cached_in_model?
84
+
85
+ owner.class_eval do
86
+ field_type = tag_definition.cached_in_model_as_list? ? Array : String
87
+
88
+ field tag_definition.cached_in_model_field, type: field_type
89
+ end
90
+ end
91
+
86
92
  def define_base_relations
87
93
  tag_definition = self
88
94
 
@@ -155,55 +161,42 @@ module ActsAsTaggableOnMongoid
155
161
  def add_tag_list
156
162
  add_list_getter
157
163
  add_list_setter
164
+ add_tag_list_from
165
+ add_tagger_tag_list
166
+ add_tagger_tag_lists
158
167
  add_all_list_getter
159
168
  add_list_exists
169
+
170
+ add_tag_list_change_methods
171
+ end
172
+
173
+ def add_tag_list_change_methods
160
174
  add_list_change
161
175
  add_list_changed
162
176
  add_changed_from_default?
163
177
  add_will_change
164
178
  add_get_was
179
+ add_get_lists_was
180
+ add_tagger_get_was
165
181
  add_reset_list
166
182
  add_reset_to_default
167
183
  end
168
184
 
169
- def add_list_getter
170
- tag_definition = self
171
- tag_list_name = tag_definition.tag_list_name
172
-
173
- owner.taggable_mixin.module_eval do
174
- define_method(tag_list_name) do
175
- tag_list_on tag_definition
176
- end
177
-
178
- alias_method "#{tag_list_name}_before_type_cast".to_sym, tag_list_name.to_sym
179
- end
180
- end
181
-
182
- def add_list_setter
183
- tag_definition = self
184
-
185
- owner.taggable_mixin.module_eval do
186
- define_method("#{tag_definition.tag_list_name}=") do |new_tags|
187
- dup_tags = Array.wrap(new_tags).dup
188
- options = dup_tags.extract_options!.dup
189
- options[:parse] = options.fetch(:parse) { true }
190
-
191
- new_list = tag_definition.parse(*dup_tags, options)
192
-
193
- mark_tag_list_changed(new_list)
194
- tag_list_set(new_list)
195
- end
196
- end
197
- end
198
-
199
- def add_all_list_getter
200
- tag_definition = self
185
+ def self.extract_tag_definition_options(options)
186
+ options = options.dup
201
187
 
202
- owner.taggable_mixin.module_eval do
203
- define_method(tag_definition.all_tag_list_name) do
204
- all_tags_list_on tag_definition
205
- end
206
- end
188
+ options.assert_valid_keys(:parser,
189
+ :preserve_tag_order,
190
+ :cached_in_model,
191
+ :force_lowercase,
192
+ :force_parameterize,
193
+ :owner_id_field,
194
+ :remove_unused_tags,
195
+ :tags_table,
196
+ :taggings_table,
197
+ :default,
198
+ :tagger)
199
+ options
207
200
  end
208
201
 
209
202
  private
@@ -3,13 +3,10 @@
3
3
  module ActsAsTaggableOnMongoid
4
4
  module Taggable
5
5
  class TagTypeDefinition
6
- # This module extracts out the basic configuration type attributes of the tag definition.
7
- #
8
- # All attributes are based off of the Configuration class and in fact will default to
9
- # the corresponding value in the configuration if not explicitly specified/set when the
10
- # tag is defined.
6
+ # This module defines methods used to evaluate the attributes of the Tag Type Definition
11
7
  module Attributes
12
8
  attr_reader :cached_in_model,
9
+ :owner_id_field,
13
10
  :default
14
11
 
15
12
  def parser
@@ -56,20 +53,87 @@ module ActsAsTaggableOnMongoid
56
53
  end
57
54
  end
58
55
 
56
+ def cached_in_model_field
57
+ @cached_in_model_field ||= cache_hash.fetch(:field) { "cached_#{tag_list_name}" }
58
+ end
59
+
60
+ def cached_in_model_as_list?
61
+ @cached_in_model_as_list ||= cache_hash.fetch(:as_list) { true }
62
+ end
63
+
59
64
  alias preserve_tag_order? preserve_tag_order
60
65
  alias cached_in_model? cached_in_model
61
66
  alias force_lowercase? force_lowercase
62
67
  alias force_parameterize? force_parameterize
63
68
  alias remove_unused_tags? remove_unused_tags
64
69
 
70
+ def tagger?
71
+ instance_variable_defined?(:@tagger)
72
+ end
73
+
74
+ def tag_list_uses_default_tagger?
75
+ return false if !tagger? || default_tagger_method.blank?
76
+
77
+ tagger_params.fetch(:tag_list_uses_default_tagger) { false }
78
+ end
79
+
80
+ def default_tagger_method
81
+ return nil unless tagger?
82
+
83
+ tagger_params[:default_tagger]
84
+ end
85
+
86
+ # :reek:FeatureEnvy
87
+ # :reek:DuplicateMethodCall
88
+ def taggable_default(taggable)
89
+ default_list = default
90
+
91
+ return unless default_list.present?
92
+
93
+ default_list = default_list.dup
94
+ default_list.taggable = taggable
95
+ default_list.tagger = default_list.tagger
96
+
97
+ default_list
98
+ end
99
+
100
+ def default_tagger(taggable)
101
+ return nil if default_tagger_method.nil?
102
+ return nil if taggable.blank?
103
+
104
+ taggable.public_send(default_tagger_method)
105
+ end
106
+
107
+ def tag_list_default_tagger(taggable)
108
+ return nil unless tag_list_uses_default_tagger?
109
+
110
+ default_tagger(taggable)
111
+ end
112
+
65
113
  private
66
114
 
115
+ def cache_hash
116
+ @cache_hash ||= cached_in_model.is_a?(Hash) ? cached_in_model : {}
117
+ end
118
+
119
+ def tagger_params
120
+ return @tagger_params if defined?(@tagger_params)
121
+
122
+ params = instance_variable_get(:@tagger)
123
+
124
+ @tagger_params = if tagger? && params.is_a?(Hash)
125
+ params.with_indifferent_access
126
+ else
127
+ HashWithIndifferentAccess.new
128
+ end
129
+ end
130
+
67
131
  def default_value=(value)
68
132
  dup_value = Array.wrap(value).dup
69
133
  options = dup_value.extract_options!.dup
70
134
  options[:parse] = options.fetch(:parse) { true }
71
135
 
72
- @default = ActsAsTaggableOnMongoid::TagList.new self, dup_value, options
136
+ @default = ActsAsTaggableOnMongoid::TagList.new self, *dup_value, options
73
137
  end
74
138
  end
75
139
  end
@@ -11,16 +11,36 @@ module ActsAsTaggableOnMongoid
11
11
  # * tag_list_will_change!
12
12
  # * tag_list_changed_from_default?
13
13
  # * tag_list_was
14
+ # * tagger_tag_list_was
15
+ # * tag_lists_was
14
16
  # * reset_tag_list!
15
17
  # * reset_tag_list_to_default!
18
+
19
+ # :reek:FeatureEnvy
20
+ # :reek:DuplicateMethodCall
16
21
  module Changeable
22
+ def default_tagger_tag_list(taggable)
23
+ list = ActsAsTaggableOnMongoid::TaggerTagList.new(self, nil)
24
+
25
+ list_default = default.dup
26
+ list_default.taggable = taggable
27
+ list_default.tagger = list_default.tagger
28
+ list[list_default.tagger] = list_default
29
+
30
+ list.taggable = taggable
31
+
32
+ list
33
+ end
34
+
35
+ private
36
+
17
37
  def add_list_exists
18
38
  tag_definition = self
19
39
  tag_list_name = tag_definition.tag_list_name
20
40
 
21
41
  owner.taggable_mixin.module_eval do
22
42
  define_method("#{tag_list_name}?") do
23
- public_send(tag_list_name).present?
43
+ tag_list_cache_on(tag_definition).values.any?(&:present?)
24
44
  end
25
45
  end
26
46
  end
@@ -31,48 +51,29 @@ module ActsAsTaggableOnMongoid
31
51
 
32
52
  owner.taggable_mixin.module_eval do
33
53
  define_method("#{tag_list_name}_change") do
34
- return nil unless public_send("#{tag_list_name}_changed?")
35
-
36
- changed_value = public_send("#{tag_list_name}_was")
37
- current_value = public_send(tag_list_name)
38
-
39
- [changed_value, current_value] unless current_value == changed_value
54
+ get_tag_list_change(tag_definition)
40
55
  end
41
56
  end
42
57
  end
43
58
 
44
- # rubocop:disable Metrics/AbcSize
45
-
46
59
  def add_list_changed
47
60
  tag_definition = self
48
61
  tag_list_name = tag_definition.tag_list_name
49
62
 
50
63
  owner.taggable_mixin.module_eval do
51
64
  define_method("#{tag_list_name}_changed?") do
52
- return false unless changed_attributes.key?(tag_list_name)
53
-
54
- changed_value = new_record? ? tag_definition.default : changed_attributes[tag_list_name]
55
- current_value = public_send(tag_list_name)
56
-
57
- unless tag_definition.preserve_tag_order?
58
- changed_value.sort!
59
- current_value.sort!
60
- end
61
-
62
- current_value != changed_value
65
+ get_tag_list_changed(tag_definition)
63
66
  end
64
67
  end
65
68
  end
66
69
 
67
- # rubocop:enable Metrics/AbcSize
68
-
69
70
  def add_will_change
70
71
  tag_definition = self
71
72
  tag_list_name = tag_definition.tag_list_name
72
73
 
73
74
  owner.taggable_mixin.module_eval do
74
75
  define_method("#{tag_list_name}_will_change!") do
75
- attribute_wil_change! tag_list_name
76
+ attribute_will_change! tag_list_name
76
77
  end
77
78
  end
78
79
  end
@@ -83,15 +84,10 @@ module ActsAsTaggableOnMongoid
83
84
 
84
85
  owner.taggable_mixin.module_eval do
85
86
  define_method("#{tag_list_name}_changed_from_default?") do
86
- changed_value = tag_definition.default
87
- current_value = public_send(tag_list_name)
88
-
89
- unless tag_definition.preserve_tag_order?
90
- changed_value.sort!
91
- current_value.sort!
92
- end
87
+ changed_value = tag_definition.default_tagger_tag_list(self)
88
+ current_value = tag_list_cache_on(tag_definition)
93
89
 
94
- current_value != changed_value
90
+ !(changed_value <=> current_value)&.zero?
95
91
  end
96
92
  end
97
93
  end
@@ -102,13 +98,28 @@ module ActsAsTaggableOnMongoid
102
98
 
103
99
  owner.taggable_mixin.module_eval do
104
100
  define_method("#{tag_list_name}_was") do
105
- return tag_definition.default if new_record?
101
+ get_tag_list_was tag_definition
102
+ end
103
+ end
104
+ end
105
+
106
+ def add_get_lists_was
107
+ tag_definition = self
106
108
 
107
- if public_send "#{tag_list_name}_changed?"
108
- changed_attributes[tag_list_name]
109
- else
110
- public_send tag_list_name
111
- end
109
+ owner.taggable_mixin.module_eval do
110
+ define_method("#{tag_definition.tagger_tag_lists_name}_was") do
111
+ get_tag_lists_was(tag_definition)
112
+ end
113
+ end
114
+ end
115
+
116
+ def add_tagger_get_was
117
+ tag_definition = self
118
+ tag_list_name = tag_definition.tag_list_name
119
+
120
+ owner.taggable_mixin.module_eval do
121
+ define_method("tagger_#{tag_list_name}_was") do |tagger|
122
+ get_tagger_list_was(tag_definition, tagger)
112
123
  end
113
124
  end
114
125
  end
@@ -119,7 +130,9 @@ module ActsAsTaggableOnMongoid
119
130
 
120
131
  owner.taggable_mixin.module_eval do
121
132
  define_method("reset_#{tag_list_name}!") do
122
- public_send "#{tag_list_name}=", public_send("#{tag_list_name}_was")
133
+ return unless public_send("#{tag_list_name}_changed?")
134
+
135
+ tagger_tag_list_set(changed_attributes[tag_list_name].dup)
123
136
  end
124
137
  end
125
138
  end
@@ -130,7 +143,7 @@ module ActsAsTaggableOnMongoid
130
143
 
131
144
  owner.taggable_mixin.module_eval do
132
145
  define_method("reset_#{tag_list_name}_to_default!") do
133
- public_send "#{tag_list_name}=", tag_definition.default
146
+ tagger_tag_list_set(tag_definition.default_tagger_tag_list(self))
134
147
  end
135
148
  end
136
149
  end
@@ -0,0 +1,77 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ class TagTypeDefinition
6
+ # This module extracts out the methods used to add list methods to the taggable object
7
+ module ListMethods
8
+ def add_list_getter
9
+ tag_definition = self
10
+ tag_list_name = tag_definition.tag_list_name
11
+
12
+ owner.taggable_mixin.module_eval do
13
+ define_method(tag_list_name) do
14
+ tag_list_on tag_definition
15
+ end
16
+
17
+ alias_method "#{tag_list_name}_before_type_cast".to_sym, tag_list_name.to_sym
18
+ end
19
+ end
20
+
21
+ def add_list_setter
22
+ tag_definition = self
23
+
24
+ owner.taggable_mixin.module_eval do
25
+ define_method("#{tag_definition.tag_list_name}=") do |new_tags|
26
+ set_tag_list(tag_definition, new_tags)
27
+ end
28
+ end
29
+ end
30
+
31
+ def add_all_list_getter
32
+ tag_definition = self
33
+
34
+ owner.taggable_mixin.module_eval do
35
+ define_method(tag_definition.all_tag_list_name) do
36
+ all_tags_list_on tag_definition
37
+ end
38
+ end
39
+ end
40
+
41
+ def add_tagger_tag_list
42
+ tag_definition = self
43
+ tag_list_name = tag_definition.tagger_tag_list_name
44
+
45
+ owner.taggable_mixin.module_eval do
46
+ define_method(tag_list_name) do |owner|
47
+ return nil unless tag_definition.tagger?
48
+
49
+ tag_list_cache_on(tag_definition)[owner]
50
+ end
51
+ end
52
+ end
53
+
54
+ def add_tag_list_from
55
+ tag_definition = self
56
+
57
+ owner.taggable_mixin.module_eval do
58
+ define_method(tag_definition.from_list_name) do |owner|
59
+ public_send(tag_definition.tagger_tag_list_name, owner)
60
+ end
61
+ end
62
+ end
63
+
64
+ def add_tagger_tag_lists
65
+ tag_definition = self
66
+ tag_list_name = tag_definition.tagger_tag_lists_name
67
+
68
+ owner.taggable_mixin.module_eval do
69
+ define_method(tag_list_name) do
70
+ tag_list_cache_on(tag_definition)
71
+ end
72
+ end
73
+ end
74
+ end
75
+ end
76
+ end
77
+ end