acts-as-taggable-on-mongoid 6.0.1.1 → 6.0.1.2

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1f6ce2d51035fb3fb89a0fb231fed320cf3e2cad
4
- data.tar.gz: 97b5143f687988711ee7899914bd34524ead070c
3
+ metadata.gz: 8d93a7c1beb5fbe71abb708118e35b734203691f
4
+ data.tar.gz: 6ae2ad0b0060b5265c879338aa26d4684d551a26
5
5
  SHA512:
6
- metadata.gz: 1a2f8d3abef2f906dc49195efb0220f3bc90edd0f10ff35296efaf365f113bbad7f0533bf14506b883a7b327a4d627b2169af6078df91402bbdcfa8c4b67409a
7
- data.tar.gz: e26e1cc6db0bc21dc6341362e6789621410f651a61feb6e2ee34fe9550041ad8cf568ffd230e953f2dc03369d779d3300e04931717334fccd4e4a9d6ab515289
6
+ metadata.gz: e5ac3c342c801316fb57ace4fc70f143db77c1204ace3cc3ee7a192de608e64dd5d2737afa9bd6284a355719dda04d34d474105410ee3b07947df895d61de2cb
7
+ data.tar.gz: 13f2f14dd4cda732d427f4e0c71f3eaf8efacbaa9a8bc74417fbf7ad68edb1a0b9e72523ee9d3e26552682d9ed7c1045f63548e0b790384c658e03d9c8267658
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- acts-as-taggable-on-mongoid (6.0.1.1)
4
+ acts-as-taggable-on-mongoid (6.0.1.2)
5
5
  activesupport (~> 4.2)
6
6
  mongoid (~> 5.2)
7
7
 
@@ -165,6 +165,7 @@ GEM
165
165
  unicode-display_width (~> 1.1, >= 1.1.1)
166
166
  thor (0.19.4)
167
167
  thread_safe (0.3.6)
168
+ timecop (0.9.1)
168
169
  tzinfo (1.2.5)
169
170
  thread_safe (~> 0.1)
170
171
  unicode-display_width (1.4.0)
@@ -198,6 +199,7 @@ DEPENDENCIES
198
199
  rubocop
199
200
  simplecov
200
201
  simplecov-rcov
202
+ timecop
201
203
 
202
204
  BUNDLED WITH
203
205
  1.16.4
@@ -51,4 +51,5 @@ Gem::Specification.new do |spec|
51
51
  spec.add_development_dependency "rubocop"
52
52
  spec.add_development_dependency "simplecov"
53
53
  spec.add_development_dependency "simplecov-rcov"
54
+ spec.add_development_dependency "timecop"
54
55
  end
@@ -25,6 +25,14 @@ module ActsAsTaggableOnMongoid
25
25
  autoload :TagListDiff
26
26
  end
27
27
 
28
+ autoload_under "taggable/tagged_with_query" do
29
+ autoload :Base
30
+ autoload :AllTagsQuery
31
+ autoload :AnyTagsQuery
32
+ autoload :ExcludeTagsQuery
33
+ autoload :MatchAllTagsQuery
34
+ end
35
+
28
36
  autoload_under :Taggable do
29
37
  # autoload :Cache
30
38
  # autoload :Collection
@@ -32,6 +40,8 @@ module ActsAsTaggableOnMongoid
32
40
  autoload :Changeable
33
41
  autoload :TagTypeDefinition
34
42
  autoload :ListTags
43
+ autoload :TaggedWith
44
+ autoload :TaggedWithQuery
35
45
  # autoload :Ownership
36
46
  # autoload :Related
37
47
  end
@@ -46,7 +46,7 @@ module ActsAsTaggableOnMongoid
46
46
  # tag_list.add("Fun", "Happy")
47
47
  # tag_list.add("Fun, Happy", :parse => true)
48
48
  def add(*names)
49
- extract_and_apply_options!(names)
49
+ names = extract_and_apply_options!(names)
50
50
  concat(names)
51
51
  clean!
52
52
 
@@ -154,16 +154,18 @@ module ActsAsTaggableOnMongoid
154
154
  # :reek:FeatureEnvy
155
155
  # :reek:DuplicateMethodCall
156
156
  def extract_and_apply_options!(args)
157
- options = args.extract_options!
157
+ dup_args = args.dup
158
+ options = dup_args.extract_options!.dup
158
159
  options.assert_valid_keys :parse, :parser
159
160
 
160
161
  options_parser = options[:parser]
161
162
  run_parser = options_parser || tag_definition.parser
162
163
 
163
- args.flatten!
164
- args.map! { |argument| run_parser.new(argument).parse } if options[:parse] || options_parser
164
+ dup_args.flatten!
165
+ dup_args.map! { |argument| run_parser.new(argument).parse } if options[:parse] || options_parser
165
166
 
166
- args.flatten!
167
+ dup_args.flatten!
168
+ dup_args
167
169
  end
168
170
  end
169
171
  end
@@ -83,9 +83,10 @@ module ActsAsTaggableOnMongoid
83
83
  # acts_as_ordered_taggable_on :languages, :skills
84
84
  # end
85
85
  def acts_as_ordered_taggable_on(*tag_types)
86
- options = tag_types.extract_options!
86
+ dup_tag_types = tag_types.dup
87
+ options = dup_tag_types.extract_options!.dup
87
88
 
88
- taggable_on(*tag_types, options.merge(preserve_tag_order: true))
89
+ taggable_on(*dup_tag_types, options.merge(preserve_tag_order: true))
89
90
  end
90
91
 
91
92
  private
@@ -107,6 +108,7 @@ module ActsAsTaggableOnMongoid
107
108
  # and add hooks/callbacks that aren't needed without tags.
108
109
  [ActsAsTaggableOnMongoid::Taggable::Core,
109
110
  ActsAsTaggableOnMongoid::Taggable::Changeable,
111
+ ActsAsTaggableOnMongoid::Taggable::TaggedWith,
110
112
  # include Collection - not sure we will need as done here. Need to think more on this one.
111
113
  # include Cache - TODO: Add this.
112
114
  # include Ownership - TODO: Add this.
@@ -115,10 +117,11 @@ module ActsAsTaggableOnMongoid
115
117
  include include_module unless included_modules.include?(include_module)
116
118
  end
117
119
 
118
- options = tag_types.extract_options!
119
- tag_types.flatten!
120
+ dup_tag_types = tag_types.dup
121
+ options = dup_tag_types.extract_options!.dup
122
+ dup_tag_types.flatten!
120
123
 
121
- tag_types.each do |tag_type|
124
+ dup_tag_types.each do |tag_type|
122
125
  next if tag_type.blank?
123
126
 
124
127
  define_tag tag_type, options
@@ -138,6 +138,7 @@ module ActsAsTaggableOnMongoid
138
138
  next if public_send(tag_list_name).present?
139
139
 
140
140
  public_send("#{tag_list_name}=", default)
141
+ changed_attributes.delete tag_list_name
141
142
  end
142
143
  end
143
144
 
@@ -7,9 +7,17 @@ module ActsAsTaggableOnMongoid
7
7
  extend ActiveSupport::Concern
8
8
 
9
9
  included do
10
- class_attribute :tag_types
10
+ class_attribute :my_tag_types
11
11
 
12
- self.tag_types ||= {}.with_indifferent_access
12
+ self.my_tag_types ||= {}.with_indifferent_access
13
+ end
14
+
15
+ def tag_types
16
+ klass = self.class
17
+
18
+ self.my_tag_types = klass.cleanup_tag_types(my_tag_types, klass)
19
+
20
+ my_tag_types
13
21
  end
14
22
 
15
23
  def tag_definition(tag_type)
@@ -19,6 +27,21 @@ module ActsAsTaggableOnMongoid
19
27
  end
20
28
 
21
29
  class_methods do
30
+ def tag_types
31
+ self.my_tag_types = cleanup_tag_types(my_tag_types, self)
32
+
33
+ my_tag_types
34
+ end
35
+
36
+ # :reek:UtilityFunction
37
+ def cleanup_tag_types(tag_types, klass)
38
+ return tag_types if tag_types.values.all? { |tag_definition| tag_definition.owner == klass }
39
+
40
+ tag_types.each_with_object({}.with_indifferent_access) do |(key, tag_definition), hash|
41
+ hash[key] = ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition.copy_from(klass, tag_definition)
42
+ end
43
+ end
44
+
22
45
  # In order to allow dynamic tags, return a default tag_definition for any missing tag_type.
23
46
  # This means that any dynamic tag necessarily is created with the current defaults
24
47
  def define_tag(tag_type, options = {})
@@ -31,9 +54,9 @@ module ActsAsTaggableOnMongoid
31
54
  # tag_types is a class_attribute
32
55
  # As such, we have to replace it each time with a new array so that inherited classes and instances
33
56
  # are able to maintain separate lists if need be.
34
- new_tag_types = {}.with_indifferent_access.merge!(self.tag_types || {})
35
- self.tag_types = new_tag_types
36
- tag_definition = new_tag_types[tag_type] = ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition.new(self, tag_type, options)
57
+ new_tag_types = {}.with_indifferent_access.merge!(tag_types || {})
58
+ self.my_tag_types = new_tag_types
59
+ tag_definition = new_tag_types[tag_type] = ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition.new(self, tag_type, options)
37
60
 
38
61
  tag_definition.define_base_relations
39
62
  tag_definition.define_relations
@@ -18,6 +18,8 @@ module ActsAsTaggableOnMongoid
18
18
  include ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition::Changeable
19
19
 
20
20
  def initialize(owner, tag_type, options = {})
21
+ options = options.dup
22
+
21
23
  options.assert_valid_keys(:parser,
22
24
  :preserve_tag_order,
23
25
  :cached_in_model,
@@ -30,15 +32,35 @@ module ActsAsTaggableOnMongoid
30
32
 
31
33
  self.default_value = options.delete(:default)
32
34
 
33
- options.each do |key, value|
34
- instance_variable_set("@#{key}", value)
35
- end
35
+ save_options(options)
36
36
 
37
37
  @owner = owner
38
38
  @tag_type = tag_type
39
39
  end
40
40
 
41
- # rubocop:disable Layout/SpaceAroundOperators
41
+ def self.copy_from(klass, tag_definition)
42
+ dup_hash = %i[parser
43
+ preserve_tag_order
44
+ cached_in_model
45
+ force_lowercase
46
+ force_parameterize
47
+ remove_unused_tags
48
+ tags_table
49
+ taggings_table].each_with_object({}) { |dup_key, opts_hash| opts_hash[dup_key] = tag_definition.public_send(dup_key) }
50
+
51
+ dup_hash[:default] = [tag_definition.default, parse: false]
52
+
53
+ ActsAsTaggableOnMongoid::Taggable::TagTypeDefinition.new klass,
54
+ tag_definition.tag_type,
55
+ dup_hash
56
+ end
57
+
58
+ def conflicts_with?(tag_definition)
59
+ %i[parser preserve_tag_order force_lowercase force_parameterize taggings_table].any? do |setting_name|
60
+ public_send(setting_name) != tag_definition.public_send(setting_name)
61
+ end
62
+ end
63
+
42
64
  # :reek:FeatureEnvy
43
65
 
44
66
  # I've defined the parser as being required to return an array of strings.
@@ -46,14 +68,13 @@ module ActsAsTaggableOnMongoid
46
68
  # to apply the rules to that list (like case sensitivity and parameterization, etc.) to get the final
47
69
  # list.
48
70
  def parse(*tag_list)
49
- options = tag_list.extract_options!
50
- options[:parser] ||= parser if options.key?(:parse) || options.key?(:parser)
71
+ dup_tag_list = tag_list.dup
72
+ options = dup_tag_list.extract_options!.dup
73
+ options[:parser] ||= parser if options[:parse] || options.key?(:parser)
51
74
 
52
- ActsAsTaggableOnMongoid::TagList.new(self, *tag_list, options)
75
+ ActsAsTaggableOnMongoid::TagList.new(self, *dup_tag_list, options)
53
76
  end
54
77
 
55
- # rubocop:enable Layout/SpaceAroundOperators
56
-
57
78
  def taggings_order
58
79
  @taggings_order = if preserve_tag_order?
59
80
  [:created_at.asc, :id.asc]
@@ -163,11 +184,11 @@ module ActsAsTaggableOnMongoid
163
184
 
164
185
  owner.taggable_mixin.module_eval do
165
186
  define_method("#{tag_definition.tag_list_name}=") do |new_tags|
166
- new_tags = Array.wrap(new_tags)
167
- options = new_tags.extract_options!
168
- options[:parse] = true unless options.key?(:parse)
187
+ dup_tags = Array.wrap(new_tags).dup
188
+ options = dup_tags.extract_options!.dup
189
+ options[:parse] = options.fetch(:parse) { true }
169
190
 
170
- new_list = tag_definition.parse(*new_tags, options)
191
+ new_list = tag_definition.parse(*dup_tags, options)
171
192
 
172
193
  mark_tag_list_changed(new_list)
173
194
  tag_list_set(new_list)
@@ -184,6 +205,14 @@ module ActsAsTaggableOnMongoid
184
205
  end
185
206
  end
186
207
  end
208
+
209
+ private
210
+
211
+ def save_options(options)
212
+ options.each do |key, value|
213
+ instance_variable_set("@#{key}", value)
214
+ end
215
+ end
187
216
  end
188
217
  end
189
218
  end
@@ -65,11 +65,11 @@ module ActsAsTaggableOnMongoid
65
65
  private
66
66
 
67
67
  def default_value=(value)
68
- value = Array.wrap(value)
69
- options = value.extract_options!
70
- options[:parse] = true unless options.key?(:parse)
68
+ dup_value = Array.wrap(value).dup
69
+ options = dup_value.extract_options!.dup
70
+ options[:parse] = options.fetch(:parse) { true }
71
71
 
72
- @default = ActsAsTaggableOnMongoid::TagList.new self, value, options
72
+ @default = ActsAsTaggableOnMongoid::TagList.new self, dup_value, options
73
73
  end
74
74
  end
75
75
  end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ # Include methods and scopes to a Taggable class to allow searching for Taggable objects.
6
+ module TaggedWith
7
+ extend ActiveSupport::Concern
8
+
9
+ included do
10
+ ##
11
+ # Return a scope of objects that are tagged within the given context with the specified tags.
12
+ #
13
+ # @param tags The tags that we want to query for
14
+ # @param [Hash] options A hash of options to alter you query:
15
+ # * <tt>:on</tt> - The context to filter the query by. (default - all contexts)
16
+ # To allow broader compatibility with `ActsAsTaggableOn`, context can be an array of values
17
+ # for a set of tags that are equivalent enough (the parsing of the list is the same
18
+ # and they use the same taggings table.)
19
+ #
20
+ # If you are trying to find values for a tag that downcases and one that doesn't, the
21
+ # code is unsure how to handle this and raises an exception.
22
+ # * <tt>:exclude</tt> - if set to true, return objects that are *NOT* tagged with the specified tags
23
+ # * <tt>:any</tt> - if set to true, return objects that are tagged with *ANY* of the specified tags
24
+ # * <tt>:match_all</tt> - if set to true, return objects that are tagged with *ONLY* the specified tags
25
+ # * <tt>:all</tt> - if set to true, return objects that are tagged with *ALL* of the specified tags
26
+ # If none of :any, :eclude, or :all are set, :all is the default.
27
+ # * <tt>:start_at</tt> - Restrict the tags to those created on or after a certain time
28
+ # * <tt>:end_at</tt> - Restrict the tags to those created before a certain time
29
+ # * <tt>:wild</tt> - Match all passed in tags as a regex of /%tag%/
30
+ # * <tt>:parse</tt> - Indicates if the tags should be parsed or not.
31
+ # * <tt>:parser</tt> - The parser to be used to parse the tags.
32
+ #
33
+ # The following options are not currently supported yet:
34
+ # * <tt>:order_by_matching_tag_count</tt> - if set to true and used with :any, sort by objects matching the most tags,
35
+ # descending
36
+ # * <tt>:owned_by</tt> - return objects that are *ONLY* owned by the owner
37
+ # * <tt>:order</tt> - Not supported because you cannot sort the results by
38
+ # the taggings in this implementation and an order on the taggable
39
+ # can easily be added by the consumer as needed.
40
+ #
41
+ # Example:
42
+ # User.tagged_with("awesome", "cool", on: tags) # Users that are tagged with awesome and cool
43
+ # User.tagged_with("awesome", "cool", on: tags, :exclude => true) # Users that are not tagged with awesome or cool
44
+ # User.tagged_with("awesome", "cool", on: tags, :any => true) # Users that are tagged with awesome or cool
45
+ # User.tagged_with("awesome", "cool", on: tags, :any => true, :order_by_matching_tag_count => true) # Sort by users who match the most
46
+ # tags, descending
47
+ # User.tagged_with("awesome", "cool", on: tags, :match_all => true) # Users that are tagged with just awesome and cool
48
+ # User.tagged_with("awesome", "cool", on: tags, :owned_by => foo ) # Users that are tagged with just awesome and cool by 'foo'
49
+ # User.tagged_with("awesome", "cool", on: tags, :owned_by => foo, :start_at => Date.today ) # Users that are tagged with just awesome,
50
+ # cool by 'foo' and starting today
51
+
52
+ scope :tagged_with, (->(*tags) { where ::ActsAsTaggableOnMongoid::Taggable::TaggedWithQuery.new(self, *tags).build })
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,96 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ # A class finding all Taggable objects for the passed in tags based on the passed in parameters.
6
+ # Details for how the query will work are in the TaggedWith module.
7
+ class TaggedWithQuery
8
+ attr_reader :taggable_class,
9
+ :tags,
10
+ :options,
11
+ :tag_definition
12
+
13
+ def initialize(taggable_class, *tags)
14
+ new_tags = tags.dup
15
+ @taggable_class = taggable_class
16
+ @options = new_tags.extract_options!.dup
17
+ @tags = new_tags
18
+
19
+ cleanup_options
20
+
21
+ context = on_context(*options[:on])
22
+ @tag_definition = taggable_class.tag_types[context]
23
+ end
24
+
25
+ def build
26
+ klass = if options[:exclude].present?
27
+ ExcludeTagsQuery
28
+ elsif options[:any].present?
29
+ AnyTagsQuery
30
+ elsif options[:match_all]
31
+ MatchAllTagsQuery
32
+ else
33
+ AllTagsQuery
34
+ end
35
+
36
+ klass.new(tag_definition, tag_list, options).build
37
+ end
38
+
39
+ private
40
+
41
+ def cleanup_options
42
+ options[:on] = Array.wrap(options[:on] || options.delete(:context))
43
+ options[:parse] = options.fetch(:parse) { true } || options.key?(:parser)
44
+
45
+ validate_options
46
+ end
47
+
48
+ def validate_options
49
+ options.assert_valid_keys :parse,
50
+ :parser,
51
+ :wild,
52
+ :exclude,
53
+ :match_all,
54
+ :all,
55
+ :any,
56
+ :on,
57
+ :start_at,
58
+ :end_at
59
+ end
60
+
61
+ def on_context(*contexts)
62
+ test_contexts = (contexts.presence || taggable_class.tag_types.keys).flatten
63
+ primary_context = test_contexts.first
64
+
65
+ test_contexts.each do |context|
66
+ raise "conflicting context definitions" if conflicting_context?(primary_context, context)
67
+ end
68
+
69
+ primary_context
70
+ end
71
+
72
+ # :reek:FeatureEnvy
73
+
74
+ def conflicting_context?(left, right)
75
+ return false if left == right
76
+
77
+ tag_types = taggable_class.tag_types
78
+
79
+ tag_types[left].conflicts_with? tag_types[right]
80
+ end
81
+
82
+ def tag_list
83
+ @tag_list ||= build_tag_list
84
+ end
85
+
86
+ def build_tag_list
87
+ return [] if tag_definition.blank?
88
+
89
+ tag_list = ActsAsTaggableOnMongoid::TagList.new(tag_definition, *tags, options.slice(:parse, :parser))
90
+ tag_list = tag_list.map { |tag| /#{tag}/ } if options[:wild]
91
+
92
+ tag_list
93
+ end
94
+ end
95
+ end
96
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ class TaggedWithQuery
6
+ # A class finding all Taggable objects which include all of the passed in tags (may include other tags as well).
7
+ class AllTagsQuery < ActsAsTaggableOnMongoid::Taggable::TaggedWithQuery::Base
8
+ def build
9
+ { :id.in => included_ids }
10
+ end
11
+
12
+ def included_ids
13
+ selector = Origin::Selector.new
14
+ selector[:count] = tag_list.count
15
+
16
+ build_ids_from(selector)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ class TaggedWithQuery
6
+ # A class finding all Taggable objects which include any of the passed in tags.
7
+ class AnyTagsQuery < ActsAsTaggableOnMongoid::Taggable::TaggedWithQuery::Base
8
+ def build
9
+ { :id.in => included_ids }
10
+ end
11
+
12
+ def included_ids
13
+ selector = Origin::Selector.new
14
+ selector[:count] = { "$gt" => 0 }
15
+
16
+ build_ids_from(selector)
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,68 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ class TaggedWithQuery
6
+ # A base class with shared code for match queries.
7
+ class Base
8
+ attr_reader :taggable_model,
9
+ :tag_definition,
10
+ :tag_list,
11
+ :options
12
+
13
+ def initialize(tag_definition, tag_list, options)
14
+ @tag_definition = tag_definition
15
+ @tag_list = tag_list
16
+ @options = options
17
+ end
18
+
19
+ private
20
+
21
+ # Any is relatively simple, but All and exclude are a bit more complicated. To make the code simpler
22
+ # I'm treating all of them the same.
23
+ # We build an aggregation of all of the matching taggables whose key_name is in the list of tags with the
24
+ # count of the matching key names. We then filter on that count.
25
+ #
26
+ # * All - count == tag_list count
27
+ # * Any - count > 0
28
+ # * Exclude - count > 0 (but anything that isn't in that count)
29
+ def build_ids_from(count_selector)
30
+ where_query = tagging_query.where(:tag_name.in => tag_list)
31
+ build_ids_from_query(where_query, count_selector)
32
+ end
33
+
34
+ def build_tagless_ids_from(count_selector)
35
+ build_ids_from_query(tagging_query, count_selector)
36
+ end
37
+
38
+ def build_ids_from_query(where_query, count_selector)
39
+ pipeline = where_query.
40
+ group(_id: { taggable_id: "$taggable_id", tag_name: "$tag_name" }).
41
+ group(_id: "$_id.taggable_id", :count.sum => 1).
42
+ pipeline.
43
+ concat(count_selector.to_pipeline)
44
+
45
+ tag_definition.taggings_table.collection.aggregate(pipeline).to_a.map { |counts| counts[:_id] }
46
+ end
47
+
48
+ def tagging_query
49
+ context = options[:on]
50
+ tagging_query = tag_definition.taggings_table.where(taggable_type: tag_definition.owner.name)
51
+ tagging_query = tagging_query.where(:context.in => context) if context.present?
52
+
53
+ time_constraints tagging_query
54
+ end
55
+
56
+ def time_constraints(tagging_query)
57
+ start_at = options[:start_at]
58
+ end_at = options[:end_at]
59
+
60
+ tagging_query = tagging_query.where(:created_at.gte => start_at) if start_at.present?
61
+ tagging_query = tagging_query.where(:created_at.lt => end_at) if end_at.present?
62
+
63
+ tagging_query
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ class TaggedWithQuery
6
+ # A class finding all Taggable objects which exclude all of the passed in tags.
7
+ class ExcludeTagsQuery < ActsAsTaggableOnMongoid::Taggable::TaggedWithQuery::Base
8
+ def build
9
+ { :id.in => included_ids }
10
+ end
11
+
12
+ def included_ids
13
+ selector = Origin::Selector.new
14
+ selector[:count] = { "$gt" => 0 }
15
+
16
+ ids = build_ids_from(selector)
17
+ build_tagless_ids_from(selector) - ids
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActsAsTaggableOnMongoid
4
+ module Taggable
5
+ class TaggedWithQuery
6
+ # A class finding all Taggable objects which include all and only all of the passed in tags.
7
+ class MatchAllTagsQuery < ActsAsTaggableOnMongoid::Taggable::TaggedWithQuery::Base
8
+ def build
9
+ { :id.in => included_ids }
10
+ end
11
+
12
+ def included_ids
13
+ selector = Origin::Selector.new
14
+ selector[:count] = { "$ne" => tag_list.count }
15
+
16
+ AllTagsQuery.new(tag_definition, tag_list, options).included_ids -
17
+ build_tagless_ids_from(selector)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module ActsAsTaggableOnMongoid
4
- VERSION = "6.0.1.1"
4
+ VERSION = "6.0.1.2"
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: acts-as-taggable-on-mongoid
3
3
  version: !ruby/object:Gem::Version
4
- version: 6.0.1.1
4
+ version: 6.0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - RealNobody
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-09-12 00:00:00.000000000 Z
11
+ date: 2018-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -282,6 +282,20 @@ dependencies:
282
282
  - - ">="
283
283
  - !ruby/object:Gem::Version
284
284
  version: '0'
285
+ - !ruby/object:Gem::Dependency
286
+ name: timecop
287
+ requirement: !ruby/object:Gem::Requirement
288
+ requirements:
289
+ - - ">="
290
+ - !ruby/object:Gem::Version
291
+ version: '0'
292
+ type: :development
293
+ prerelease: false
294
+ version_requirements: !ruby/object:Gem::Requirement
295
+ requirements:
296
+ - - ">="
297
+ - !ruby/object:Gem::Version
298
+ version: '0'
285
299
  description: A partial mongoid implementation of tagging based on/inspired by acts-as-taggable-on.
286
300
  email:
287
301
  - admin@cardtapp.com
@@ -323,6 +337,13 @@ files:
323
337
  - lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/attributes.rb
324
338
  - lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/changeable.rb
325
339
  - lib/acts_as_taggable_on_mongoid/taggable/tag_type_definition/names.rb
340
+ - lib/acts_as_taggable_on_mongoid/taggable/tagged_with.rb
341
+ - lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query.rb
342
+ - lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/all_tags_query.rb
343
+ - lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/any_tags_query.rb
344
+ - lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/base.rb
345
+ - lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/exclude_tags_query.rb
346
+ - lib/acts_as_taggable_on_mongoid/taggable/tagged_with_query/match_all_tags_query.rb
326
347
  - lib/acts_as_taggable_on_mongoid/taggable/utils/tag_list_diff.rb
327
348
  - lib/acts_as_taggable_on_mongoid/version.rb
328
349
  homepage: http://www.cardtapp.com