mongoid 7.2.6 → 7.3.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (154) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/Rakefile +16 -0
  4. data/lib/config/locales/en.yml +2 -2
  5. data/lib/mongoid/association/accessors.rb +13 -1
  6. data/lib/mongoid/association/constrainable.rb +1 -1
  7. data/lib/mongoid/association/depending.rb +4 -4
  8. data/lib/mongoid/association/embedded/batchable.rb +1 -1
  9. data/lib/mongoid/association/embedded/embedded_in.rb +1 -1
  10. data/lib/mongoid/association/embedded/embeds_many/proxy.rb +10 -3
  11. data/lib/mongoid/association/nested/many.rb +1 -1
  12. data/lib/mongoid/association/nested/one.rb +4 -2
  13. data/lib/mongoid/association/proxy.rb +6 -1
  14. data/lib/mongoid/association/referenced/auto_save.rb +2 -2
  15. data/lib/mongoid/association/referenced/has_many/enumerable.rb +490 -496
  16. data/lib/mongoid/association/referenced/has_many/proxy.rb +2 -2
  17. data/lib/mongoid/association/referenced/has_one/nested_builder.rb +2 -2
  18. data/lib/mongoid/atomic.rb +26 -2
  19. data/lib/mongoid/attributes/projector.rb +120 -0
  20. data/lib/mongoid/attributes.rb +24 -13
  21. data/lib/mongoid/cacheable.rb +2 -2
  22. data/lib/mongoid/clients/factory.rb +22 -8
  23. data/lib/mongoid/clients.rb +1 -1
  24. data/lib/mongoid/config.rb +19 -2
  25. data/lib/mongoid/contextual/aggregable/mongo.rb +10 -8
  26. data/lib/mongoid/copyable.rb +1 -1
  27. data/lib/mongoid/criteria/findable.rb +1 -1
  28. data/lib/mongoid/criteria/queryable/expandable.rb +0 -24
  29. data/lib/mongoid/criteria/queryable/extensions/boolean.rb +1 -1
  30. data/lib/mongoid/criteria/queryable/extensions.rb +0 -4
  31. data/lib/mongoid/criteria/queryable/mergeable.rb +46 -20
  32. data/lib/mongoid/criteria/queryable/selectable.rb +8 -8
  33. data/lib/mongoid/criteria.rb +4 -5
  34. data/lib/mongoid/document.rb +1 -15
  35. data/lib/mongoid/errors/delete_restriction.rb +8 -9
  36. data/lib/mongoid/evolvable.rb +1 -1
  37. data/lib/mongoid/extensions/boolean.rb +1 -2
  38. data/lib/mongoid/extensions/false_class.rb +1 -1
  39. data/lib/mongoid/extensions/hash.rb +2 -2
  40. data/lib/mongoid/extensions/true_class.rb +1 -1
  41. data/lib/mongoid/fields.rb +43 -5
  42. data/lib/mongoid/inspectable.rb +1 -1
  43. data/lib/mongoid/matcher/bits.rb +41 -0
  44. data/lib/mongoid/matcher/bits_all_clear.rb +20 -0
  45. data/lib/mongoid/matcher/bits_all_set.rb +20 -0
  46. data/lib/mongoid/matcher/bits_any_clear.rb +20 -0
  47. data/lib/mongoid/matcher/bits_any_set.rb +20 -0
  48. data/lib/mongoid/matcher/expression.rb +4 -0
  49. data/lib/mongoid/matcher/field_operator.rb +6 -0
  50. data/lib/mongoid/matcher/mod.rb +17 -0
  51. data/lib/mongoid/matcher/type.rb +99 -0
  52. data/lib/mongoid/matcher.rb +7 -0
  53. data/lib/mongoid/persistable/deletable.rb +1 -2
  54. data/lib/mongoid/persistable/destroyable.rb +8 -2
  55. data/lib/mongoid/persistable/updatable.rb +27 -2
  56. data/lib/mongoid/query_cache.rb +35 -29
  57. data/lib/mongoid/selectable.rb +5 -7
  58. data/lib/mongoid/shardable.rb +21 -5
  59. data/lib/mongoid/touchable.rb +33 -4
  60. data/lib/mongoid/version.rb +1 -1
  61. data/spec/integration/associations/embeds_many_spec.rb +44 -0
  62. data/spec/integration/associations/has_one_spec.rb +48 -0
  63. data/spec/integration/criteria/date_field_spec.rb +1 -1
  64. data/spec/integration/document_spec.rb +9 -0
  65. data/spec/integration/matcher_operator_data/bits_all_clear.yml +159 -0
  66. data/spec/integration/matcher_operator_data/bits_all_set.yml +159 -0
  67. data/spec/integration/matcher_operator_data/bits_any_clear.yml +159 -0
  68. data/spec/integration/matcher_operator_data/bits_any_set.yml +159 -0
  69. data/spec/integration/matcher_operator_data/comment.yml +22 -0
  70. data/spec/integration/matcher_operator_data/in.yml +16 -0
  71. data/spec/integration/matcher_operator_data/mod.yml +55 -0
  72. data/spec/integration/matcher_operator_data/type.yml +70 -0
  73. data/spec/integration/matcher_operator_data/type_array.yml +16 -0
  74. data/spec/integration/matcher_operator_data/type_binary.yml +18 -0
  75. data/spec/integration/matcher_operator_data/type_boolean.yml +39 -0
  76. data/spec/integration/matcher_operator_data/type_code.yml +26 -0
  77. data/spec/integration/matcher_operator_data/type_code_with_scope.yml +26 -0
  78. data/spec/integration/matcher_operator_data/type_date.yml +39 -0
  79. data/spec/integration/matcher_operator_data/type_db_pointer.yml +19 -0
  80. data/spec/integration/matcher_operator_data/type_decimal.yml +40 -0
  81. data/spec/integration/matcher_operator_data/type_double.yml +15 -0
  82. data/spec/integration/matcher_operator_data/type_int32.yml +33 -0
  83. data/spec/integration/matcher_operator_data/type_int64.yml +33 -0
  84. data/spec/integration/matcher_operator_data/type_max_key.yml +17 -0
  85. data/spec/integration/matcher_operator_data/type_min_key.yml +17 -0
  86. data/spec/integration/matcher_operator_data/type_null.yml +23 -0
  87. data/spec/integration/matcher_operator_data/type_object.yml +23 -0
  88. data/spec/integration/matcher_operator_data/type_object_id.yml +25 -0
  89. data/spec/integration/matcher_operator_data/type_regex.yml +44 -0
  90. data/spec/integration/matcher_operator_data/type_string.yml +15 -0
  91. data/spec/integration/matcher_operator_data/type_symbol.yml +32 -0
  92. data/spec/integration/matcher_operator_data/type_timestamp.yml +25 -0
  93. data/spec/integration/matcher_operator_data/type_undefined.yml +17 -0
  94. data/spec/lite_spec_helper.rb +2 -0
  95. data/spec/mongoid/association/depending_spec.rb +391 -352
  96. data/spec/mongoid/association/nested/one_spec.rb +18 -14
  97. data/spec/mongoid/association/referenced/belongs_to/proxy_spec.rb +25 -8
  98. data/spec/mongoid/association/referenced/has_and_belongs_to_many/binding_spec.rb +1 -1
  99. data/spec/mongoid/association/referenced/has_many/binding_spec.rb +1 -1
  100. data/spec/mongoid/association/referenced/has_many/enumerable_spec.rb +245 -93
  101. data/spec/mongoid/association/referenced/has_many/proxy_spec.rb +6 -6
  102. data/spec/mongoid/association/referenced/has_one_models.rb +8 -0
  103. data/spec/mongoid/atomic/paths_spec.rb +64 -12
  104. data/spec/mongoid/attributes/projector_data/embedded.yml +105 -0
  105. data/spec/mongoid/attributes/projector_data/fields.yml +93 -0
  106. data/spec/mongoid/attributes/projector_spec.rb +41 -0
  107. data/spec/mongoid/attributes_spec.rb +98 -6
  108. data/spec/mongoid/clients/factory_spec.rb +48 -0
  109. data/spec/mongoid/config_spec.rb +106 -1
  110. data/spec/mongoid/contextual/mongo_spec.rb +2 -2
  111. data/spec/mongoid/criteria/modifiable_spec.rb +1 -1
  112. data/spec/mongoid/criteria/queryable/expandable_spec.rb +0 -73
  113. data/spec/mongoid/criteria/queryable/extensions/boolean_spec.rb +1 -1
  114. data/spec/mongoid/criteria/queryable/mergeable_spec.rb +105 -7
  115. data/spec/mongoid/criteria/queryable/selectable_logical_spec.rb +229 -24
  116. data/spec/mongoid/criteria/queryable/selectable_shared_examples.rb +39 -0
  117. data/spec/mongoid/criteria/queryable/selectable_spec.rb +1 -565
  118. data/spec/mongoid/criteria/queryable/selectable_where_spec.rb +590 -0
  119. data/spec/mongoid/criteria_projection_spec.rb +411 -0
  120. data/spec/mongoid/criteria_spec.rb +0 -275
  121. data/spec/mongoid/document_spec.rb +13 -13
  122. data/spec/mongoid/errors/delete_restriction_spec.rb +1 -1
  123. data/spec/mongoid/extensions/false_class_spec.rb +1 -1
  124. data/spec/mongoid/extensions/string_spec.rb +5 -5
  125. data/spec/mongoid/extensions/true_class_spec.rb +1 -1
  126. data/spec/mongoid/fields/localized_spec.rb +4 -4
  127. data/spec/mongoid/fields_spec.rb +4 -4
  128. data/spec/mongoid/inspectable_spec.rb +12 -4
  129. data/spec/mongoid/persistable/deletable_spec.rb +175 -1
  130. data/spec/mongoid/persistable/destroyable_spec.rb +191 -3
  131. data/spec/mongoid/persistable/savable_spec.rb +3 -5
  132. data/spec/mongoid/persistable/upsertable_spec.rb +1 -1
  133. data/spec/mongoid/query_cache_middleware_spec.rb +8 -0
  134. data/spec/mongoid/reloadable_spec.rb +18 -1
  135. data/spec/mongoid/shardable_spec.rb +44 -0
  136. data/spec/mongoid/touchable_spec.rb +122 -16
  137. data/spec/mongoid/touchable_spec_models.rb +54 -0
  138. data/spec/mongoid/validatable_spec.rb +1 -1
  139. data/spec/spec_helper.rb +6 -2
  140. data/spec/support/client_registry.rb +9 -0
  141. data/spec/support/models/bolt.rb +8 -0
  142. data/spec/support/models/hole.rb +13 -0
  143. data/spec/support/models/mop.rb +0 -1
  144. data/spec/support/models/nut.rb +8 -0
  145. data/spec/support/models/person.rb +6 -0
  146. data/spec/support/models/sealer.rb +8 -0
  147. data/spec/support/models/shirt.rb +12 -0
  148. data/spec/support/models/spacer.rb +8 -0
  149. data/spec/support/models/threadlocker.rb +8 -0
  150. data/spec/support/models/washer.rb +8 -0
  151. data.tar.gz.sig +0 -0
  152. metadata +97 -3
  153. metadata.gz.sig +0 -0
  154. data/spec/support/cluster_config.rb +0 -158
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e421b4ac00142136b0a04a14e31c432c95d6fc040dd54a606b4a26f5028ef04e
4
- data.tar.gz: cb252a745ffcf28e5da18a2f6d8007be05403af3c81d3f35307608acc19c99b5
3
+ metadata.gz: bf7cd241503d485cd393a4d0885629b2916aa5542083a281ff8883111938044e
4
+ data.tar.gz: f10cbf0946bd1b4a6f93deebe42fc2f9a728704d0565e1ea392df3007e5d6cc7
5
5
  SHA512:
6
- metadata.gz: 5ad32c694837c1ebb182f7082b084b57680d20f47306745f2c58c9af7eab41058acfa877e73e25d731bdb84d103f761ff8aca7fb13d49d7ecd1c846491581f4a
7
- data.tar.gz: b8b329017900e2405af3bb183f824ee3bb5e43bca44784ea0a43895c03ce2bb650e9862395f6118bb346dc02dc838fc997b900e9b24e5ce7b1e84f0c81948538
6
+ metadata.gz: 7e2a3edf8051a2ad27202288f73dc7d284effe7c766ab5d7a7274c0901e793eb124fd178d5b366ffb3b3c196e9e69cded899b66dab8f15044a9981e4b12f5c55
7
+ data.tar.gz: 3c990c42772c0b2f61eccf88bdb8ad5f26779fe62c8ad119f5717d9da48c558a85deaf56aa8ff088f97c2aee2e41c2a29cfec67018142a59c79e3ea13f8e415c
checksums.yaml.gz.sig CHANGED
Binary file
data/Rakefile CHANGED
@@ -66,6 +66,22 @@ task :ci do
66
66
  spec_organizer.run
67
67
  end
68
68
 
69
+ task :bucket, %i(buckets) do |task, args|
70
+ buckets = args[:buckets]
71
+ buckets = if buckets.nil? || buckets.empty?
72
+ [nil]
73
+ else
74
+ buckets.split(':').map do |bucket|
75
+ if bucket.empty?
76
+ nil
77
+ else
78
+ bucket.to_sym
79
+ end
80
+ end
81
+ end
82
+ spec_organizer.run_buckets(*buckets)
83
+ end
84
+
69
85
  task :default => :spec
70
86
 
71
87
  desc "Generate all documentation"
@@ -591,9 +591,9 @@ en:
591
591
  resolution: "Try persisting the document with valid data or remove
592
592
  the validations."
593
593
  delete_restriction:
594
- message: "Cannot delete %{document} because of dependent '%{relation}'."
594
+ message: "Cannot destroy %{document} because of dependent '%{relation}'."
595
595
  summary: "When defining '%{relation}' with a :dependent => :restrict_with_error,
596
- Mongoid will raise an error when attempting to delete the
596
+ Mongoid will raise an error when attempting to destroy the
597
597
  %{document} when the child '%{relation}' still has documents in it."
598
598
  resolution: "Don't attempt to delete the parent %{document} when
599
599
  it has children, or change the dependent option on the association."
@@ -121,6 +121,9 @@ module Mongoid
121
121
  # (embedded) association with the given key, or nil if no projection
122
122
  # is to be performed.
123
123
  #
124
+ # Also returns nil if exclusionary projection was requested but it does
125
+ # not exclude the field of the association.
126
+ #
124
127
  # For example, if __selected_fields is {'a' => 1, 'b.c' => 2, 'b.c.f' => 3},
125
128
  # and assoc_key is 'b', return value would be {'c' => 2, 'c.f' => 3}.
126
129
  #
@@ -132,6 +135,15 @@ module Mongoid
132
135
  def _mongoid_filter_selected_fields(assoc_key)
133
136
  return nil unless __selected_fields
134
137
 
138
+ # If the list of fields was specified using #without instead of #only
139
+ # and the provided list does not include the association, any of its
140
+ # fields should be allowed.
141
+ if __selected_fields.values.all? { |v| v == 0 } &&
142
+ __selected_fields.keys.none? { |k| k.split('.', 2).first == assoc_key }
143
+ then
144
+ return nil
145
+ end
146
+
135
147
  projecting_assoc = false
136
148
 
137
149
  filtered = {}
@@ -300,7 +312,7 @@ module Mongoid
300
312
  ids_method = "#{association.name.to_s.singularize}_ids"
301
313
  association.inverse_class.tap do |klass|
302
314
  klass.re_define_method(ids_method) do
303
- send(association.name).only(:id).map(&:id)
315
+ send(association.name).only(:_id).map(&:_id)
304
316
  end
305
317
  end
306
318
  end
@@ -36,7 +36,7 @@ module Mongoid
36
36
 
37
37
  def convert_polymorphic(object)
38
38
  if object.is_a?(Mongoid::Document)
39
- object.id
39
+ object._id
40
40
  else
41
41
  BSON::ObjectId.mongoize(object)
42
42
  end
@@ -78,13 +78,13 @@ module Mongoid
78
78
  # the appropriate strategy to perform the operation.
79
79
  #
80
80
  # @example Execute cascades.
81
- # document.apply_delete_dependencies!
81
+ # document.apply_destroy_dependencies!
82
82
  #
83
83
  # @since 2.0.0.rc.1
84
- def apply_delete_dependencies!
84
+ def apply_destroy_dependencies!
85
85
  self.class._all_dependents.each do |association|
86
- if association.try(:dependent)
87
- send("_dependent_#{association.dependent}!", association)
86
+ if dependent = association.try(:dependent)
87
+ send("_dependent_#{dependent}!", association)
88
88
  end
89
89
  end
90
90
  end
@@ -329,7 +329,7 @@ module Mongoid
329
329
  self.path = doc.atomic_path unless path
330
330
  execute_callback :before_remove, doc
331
331
  unless _assigning?
332
- doc.apply_delete_dependencies!
332
+ doc.apply_destroy_dependencies!
333
333
  doc.run_before_callbacks(:destroy) if method == :destroy
334
334
  end
335
335
  _target.delete_one(doc)
@@ -26,7 +26,7 @@ module Mongoid
26
26
  :autobuild,
27
27
  :cyclic,
28
28
  :polymorphic,
29
- :touch
29
+ :touch,
30
30
  ].freeze
31
31
 
32
32
  # The complete list of valid options for this association, including
@@ -83,8 +83,15 @@ module Mongoid
83
83
 
84
84
  alias :new :build
85
85
 
86
- # Clear the association. Will delete the documents from the db if they are
87
- # already persisted.
86
+ # Clear the association. Will delete the documents from the db
87
+ # if they are already persisted.
88
+ #
89
+ # If the host document is not persisted but its _id matches a
90
+ # persisted document, calling #clear on an association will remove
91
+ # the association's documents from the database even though the
92
+ # set of documents in the application (as loaded in the host)
93
+ # is different from what is in the database, and the host may
94
+ # not contain any persisted documents in the association either.
88
95
  #
89
96
  # @example Clear the association.
90
97
  # person.addresses.clear
@@ -332,7 +339,7 @@ module Mongoid
332
339
  private
333
340
 
334
341
  def object_already_related?(document)
335
- _target.any? { |existing| existing.id && existing === document }
342
+ _target.any? { |existing| existing._id && existing === document }
336
343
  end
337
344
 
338
345
  # Appends the document to the target array, updating the index on the
@@ -181,7 +181,7 @@ module Mongoid
181
181
  first = existing.first
182
182
  converted = first ? convert_id(first.class, id) : id
183
183
 
184
- if existing.where(id: converted).exists?
184
+ if existing.where(_id: converted).exists?
185
185
  # document exists in association
186
186
  doc = existing.find(converted)
187
187
  if destroyable?(attrs)
@@ -71,7 +71,8 @@ module Mongoid
71
71
  #
72
72
  # @since 2.0.0
73
73
  def acceptable_id?
74
- id = convert_id(existing.class, attributes[:id])
74
+ id = association.klass.extract_id_field(attributes)
75
+ id = convert_id(existing.class, id)
75
76
  existing._id == id || id.nil? || (existing._id != id && update_only?)
76
77
  end
77
78
 
@@ -84,7 +85,8 @@ module Mongoid
84
85
  #
85
86
  # @since 2.0.0
86
87
  def delete?
87
- destroyable? && !attributes[:id].nil?
88
+ id = association.klass.extract_id_field(attributes)
89
+ destroyable? && !id.nil?
88
90
  end
89
91
 
90
92
  # Can the existing association potentially be destroyed?
@@ -16,7 +16,7 @@ module Mongoid
16
16
  # We undefine most methods to get them sent through to the target.
17
17
  instance_methods.each do |method|
18
18
  undef_method(method) unless
19
- method =~ /\A(__.*|send|object_id|equal\?|respond_to\?|tap|public_send|extend_proxy|extend_proxies)\z/
19
+ method =~ /\A(?:__.*|send|object_id|equal\?|respond_to\?|respond_to_missing\?|tap|public_send|extend_proxy|extend_proxies)\z/
20
20
  end
21
21
 
22
22
  include Threaded::Lifecycle
@@ -137,6 +137,11 @@ module Mongoid
137
137
  _target.send(name, *args, &block)
138
138
  end
139
139
 
140
+ # @api private
141
+ ruby2_keywords def respond_to_missing?(name, *args)
142
+ _target.respond_to?(name, *args)
143
+ end
144
+
140
145
  # When the base document illegally references an embedded document this
141
146
  # error will get raised.
142
147
  #
@@ -63,8 +63,8 @@ module Mongoid
63
63
  self.before_callback_halted = false
64
64
  else
65
65
  __autosaving__ do
66
- if relation = ivar(association.name)
67
- Array(relation).each do |doc|
66
+ if assoc_value = ivar(association.name)
67
+ Array(assoc_value).each do |doc|
68
68
  doc.with(persistence_context) do |d|
69
69
  d.save
70
70
  end
@@ -5,544 +5,538 @@ module Mongoid
5
5
  module Association
6
6
  module Referenced
7
7
  class HasMany
8
- module Targets
9
-
10
- # This class is the wrapper for all referenced associations that have a
11
- # target that can be a criteria or array of _loaded documents. This
12
- # handles both cases or a combination of the two.
13
- class Enumerable
14
- extend Forwardable
15
- include ::Enumerable
16
-
17
- # The three main instance variables are collections of documents.
18
- #
19
- # @attribute [rw] _added Documents that have been appended.
20
- # @attribute [rw] _loaded Persisted documents that have been _loaded.
21
- # @attribute [rw] _unloaded A criteria representing persisted docs.
22
- attr_accessor :_added, :_loaded, :_unloaded
23
-
24
- def_delegators [], :is_a?, :kind_of?
25
-
26
- # Check if the enumerable is equal to the other object.
27
- #
28
- # @example Check equality.
29
- # enumerable == []
30
- #
31
- # @param [ Enumerable ] other The other enumerable.
32
- #
33
- # @return [ true, false ] If the objects are equal.
34
- #
35
- # @since 2.1.0
36
- def ==(other)
37
- return false unless other.respond_to?(:entries)
38
- entries == other.entries
39
- end
40
8
 
41
- # Check equality of the enumerable against the provided object for case
42
- # statements.
43
- #
44
- # @example Check case equality.
45
- # enumerable === Array
46
- #
47
- # @param [ Object ] other The object to check.
48
- #
49
- # @return [ true, false ] If the objects are equal in a case.
50
- #
51
- # @since 3.1.4
52
- def ===(other)
53
- other.class == Class ? (Array == other || Enumerable == other) : self == other
54
- end
9
+ # This class is the wrapper for all referenced associations that have a
10
+ # target that can be a criteria or array of _loaded documents. This
11
+ # handles both cases or a combination of the two.
12
+ class Enumerable
13
+ extend Forwardable
14
+ include ::Enumerable
15
+
16
+ # The three main instance variables are collections of documents.
17
+ #
18
+ # @attribute [rw] _added Documents that have been appended.
19
+ # @attribute [rw] _loaded Persisted documents that have been _loaded.
20
+ # @attribute [rw] _unloaded A criteria representing persisted docs.
21
+ attr_accessor :_added, :_loaded, :_unloaded
22
+
23
+ def_delegators [], :is_a?, :kind_of?
24
+
25
+ # Check if the enumerable is equal to the other object.
26
+ #
27
+ # @example Check equality.
28
+ # enumerable == []
29
+ #
30
+ # @param [ Enumerable ] other The other enumerable.
31
+ #
32
+ # @return [ true, false ] If the objects are equal.
33
+ #
34
+ # @since 2.1.0
35
+ def ==(other)
36
+ return false unless other.respond_to?(:entries)
37
+ entries == other.entries
38
+ end
55
39
 
56
- # Append a document to the enumerable.
57
- #
58
- # @example Append the document.
59
- # enumerable << document
60
- #
61
- # @param [ Document ] document The document to append.
62
- #
63
- # @return [ Document ] The document.
64
- #
65
- # @since 2.1.0
66
- def <<(document)
67
- _added[document._id] = document
68
- self
69
- end
40
+ # Check equality of the enumerable against the provided object for case
41
+ # statements.
42
+ #
43
+ # @example Check case equality.
44
+ # enumerable === Array
45
+ #
46
+ # @param [ Object ] other The object to check.
47
+ #
48
+ # @return [ true, false ] If the objects are equal in a case.
49
+ #
50
+ # @since 3.1.4
51
+ def ===(other)
52
+ other.class == Class ? (Array == other || Enumerable == other) : self == other
53
+ end
70
54
 
71
- alias :push :<<
72
-
73
- # Clears out all the documents in this enumerable. If passed a block it
74
- # will yield to each document that is in memory.
75
- #
76
- # @example Clear out the enumerable.
77
- # enumerable.clear
78
- #
79
- # @example Clear out the enumerable with a block.
80
- # enumerable.clear do |doc|
81
- # doc.unbind
82
- # end
83
- #
84
- # @return [ Array<Document> ] The cleared out _added docs.
85
- #
86
- # @since 2.1.0
87
- def clear
88
- if block_given?
89
- in_memory { |doc| yield(doc) }
90
- end
91
- _loaded.clear and _added.clear
92
- end
55
+ # Append a document to the enumerable.
56
+ #
57
+ # @example Append the document.
58
+ # enumerable << document
59
+ #
60
+ # @param [ Document ] document The document to append.
61
+ #
62
+ # @return [ Document ] The document.
63
+ #
64
+ # @since 2.1.0
65
+ def <<(document)
66
+ _added[document._id] = document
67
+ self
68
+ end
93
69
 
94
- # Clones each document in the enumerable.
95
- #
96
- # @note This loads all documents into memory.
97
- #
98
- # @example Clone the enumerable.
99
- # enumerable.clone
100
- #
101
- # @return [ Array<Document> ] An array clone of the enumerable.
102
- #
103
- # @since 2.1.6
104
- def clone
105
- collect { |doc| doc.clone }
70
+ alias :push :<<
71
+
72
+ # Clears out all the documents in this enumerable. If passed a block it
73
+ # will yield to each document that is in memory.
74
+ #
75
+ # @example Clear out the enumerable.
76
+ # enumerable.clear
77
+ #
78
+ # @example Clear out the enumerable with a block.
79
+ # enumerable.clear do |doc|
80
+ # doc.unbind
81
+ # end
82
+ #
83
+ # @return [ Array<Document> ] The cleared out _added docs.
84
+ #
85
+ # @since 2.1.0
86
+ def clear
87
+ if block_given?
88
+ in_memory { |doc| yield(doc) }
106
89
  end
90
+ _loaded.clear and _added.clear
91
+ end
92
+
93
+ # Clones each document in the enumerable.
94
+ #
95
+ # @note This loads all documents into memory.
96
+ #
97
+ # @example Clone the enumerable.
98
+ # enumerable.clone
99
+ #
100
+ # @return [ Array<Document> ] An array clone of the enumerable.
101
+ #
102
+ # @since 2.1.6
103
+ def clone
104
+ collect { |doc| doc.clone }
105
+ end
107
106
 
108
- # Delete the supplied document from the enumerable.
109
- #
110
- # @example Delete the document.
111
- # enumerable.delete(document)
112
- #
113
- # @param [ Document ] document The document to delete.
114
- #
115
- # @return [ Document ] The deleted document.
116
- #
117
- # @since 2.1.0
118
- def delete(document)
119
- doc = (_loaded.delete(document._id) || _added.delete(document._id))
120
- unless doc
121
- if _unloaded && _unloaded.where(_id: document._id).exists?
122
- yield(document) if block_given?
123
- return document
124
- end
107
+ # Delete the supplied document from the enumerable.
108
+ #
109
+ # @example Delete the document.
110
+ # enumerable.delete(document)
111
+ #
112
+ # @param [ Document ] document The document to delete.
113
+ #
114
+ # @return [ Document ] The deleted document.
115
+ #
116
+ # @since 2.1.0
117
+ def delete(document)
118
+ doc = (_loaded.delete(document._id) || _added.delete(document._id))
119
+ unless doc
120
+ if _unloaded && _unloaded.where(_id: document._id).exists?
121
+ yield(document) if block_given?
122
+ return document
125
123
  end
126
- yield(doc) if block_given?
127
- doc
128
124
  end
125
+ yield(doc) if block_given?
126
+ doc
127
+ end
129
128
 
130
- # Deletes every document in the enumerable for where the block returns
131
- # true.
132
- #
133
- # @note This operation loads all documents from the database.
134
- #
135
- # @example Delete all matching documents.
136
- # enumerable.delete_if do |doc|
137
- # dod._id == _id
138
- # end
139
- #
140
- # @return [ Array<Document> ] The remaining docs.
141
- #
142
- # @since 2.1.0
143
- def delete_if(&block)
144
- load_all!
145
- deleted = in_memory.select(&block)
146
- deleted.each do |doc|
147
- _loaded.delete(doc._id)
148
- _added.delete(doc._id)
149
- end
150
- self
129
+ # Deletes every document in the enumerable for where the block returns
130
+ # true.
131
+ #
132
+ # @note This operation loads all documents from the database.
133
+ #
134
+ # @example Delete all matching documents.
135
+ # enumerable.delete_if do |doc|
136
+ # dod._id == _id
137
+ # end
138
+ #
139
+ # @return [ Array<Document> ] The remaining docs.
140
+ #
141
+ # @since 2.1.0
142
+ def delete_if(&block)
143
+ load_all!
144
+ deleted = in_memory.select(&block)
145
+ deleted.each do |doc|
146
+ _loaded.delete(doc._id)
147
+ _added.delete(doc._id)
151
148
  end
149
+ self
150
+ end
152
151
 
153
- # Iterating over this enumerable has to handle a few different
154
- # scenarios.
155
- #
156
- # If the enumerable has its criteria _loaded into memory then it yields
157
- # to all the _loaded docs and all the _added docs.
158
- #
159
- # If the enumerable has not _loaded the criteria then it iterates over
160
- # the cursor while loading the documents and then iterates over the
161
- # _added docs.
162
- #
163
- # If no block is passed then it returns an enumerator containing all
164
- # docs.
165
- #
166
- # @example Iterate over the enumerable.
167
- # enumerable.each do |doc|
168
- # puts doc
169
- # end
170
- #
171
- # @example return an enumerator containing all the docs
172
- #
173
- # a = enumerable.each
174
- #
175
- # @return [ true ] That the enumerable is now _loaded.
176
- #
177
- # @since 2.1.0
178
- def each
179
- unless block_given?
180
- return to_enum
181
- end
182
- if _loaded?
183
- _loaded.each_pair do |id, doc|
184
- document = _added.delete(doc._id) || doc
185
- set_base(document)
186
- yield(document)
187
- end
188
- else
189
- unloaded_documents.each do |doc|
190
- document = _added.delete(doc._id) || _loaded.delete(doc._id) || doc
191
- _loaded[document._id] = document
192
- set_base(document)
193
- yield(document)
194
- end
152
+ # Iterating over this enumerable has to handle a few different
153
+ # scenarios.
154
+ #
155
+ # If the enumerable has its criteria _loaded into memory then it yields
156
+ # to all the _loaded docs and all the _added docs.
157
+ #
158
+ # If the enumerable has not _loaded the criteria then it iterates over
159
+ # the cursor while loading the documents and then iterates over the
160
+ # _added docs.
161
+ #
162
+ # If no block is passed then it returns an enumerator containing all
163
+ # docs.
164
+ #
165
+ # @example Iterate over the enumerable.
166
+ # enumerable.each do |doc|
167
+ # puts doc
168
+ # end
169
+ #
170
+ # @example return an enumerator containing all the docs
171
+ #
172
+ # a = enumerable.each
173
+ #
174
+ # @return [ true ] That the enumerable is now _loaded.
175
+ #
176
+ # @since 2.1.0
177
+ def each
178
+ unless block_given?
179
+ return to_enum
180
+ end
181
+ if _loaded?
182
+ _loaded.each_pair do |id, doc|
183
+ document = _added.delete(doc._id) || doc
184
+ set_base(document)
185
+ yield(document)
195
186
  end
196
- _added.each_pair do |id, doc|
197
- yield(doc)
187
+ else
188
+ unloaded_documents.each do |doc|
189
+ document = _added.delete(doc._id) || _loaded.delete(doc._id) || doc
190
+ _loaded[document._id] = document
191
+ set_base(document)
192
+ yield(document)
198
193
  end
199
- @executed = true
200
194
  end
201
-
202
- # Is the enumerable empty? Will determine if the count is zero based on
203
- # whether or not it is _loaded.
204
- #
205
- # @example Is the enumerable empty?
206
- # enumerable.empty?
207
- #
208
- # @return [ true, false ] If the enumerable is empty.
209
- #
210
- # @since 2.1.0
211
- def empty?
212
- if _loaded?
213
- in_memory.count == 0
214
- else
215
- _unloaded.count + _added.count == 0
216
- end
195
+ _added.each_pair do |id, doc|
196
+ yield(doc)
217
197
  end
198
+ @executed = true
199
+ end
218
200
 
219
- # Returns whether the association has any documents, optionally
220
- # subject to the provided filters.
221
- #
222
- # This method returns true if the association has any persisted
223
- # documents and if it has any not yet persisted documents.
224
- #
225
- # If the association is already loaded, this method inspects the
226
- # loaded documents and does not query the database. If the
227
- # association is not loaded, the argument-less and block-less
228
- # version does not load the association; the other versions
229
- # (that delegate to Enumerable) may or may not load the association
230
- # completely depending on whether it is iterated to completion.
231
- #
232
- # This method can take a parameter and a block. The behavior with
233
- # either the paramater or the block is delegated to the standard
234
- # library Enumerable module.
235
- #
236
- # Note that when Enumerable's any? method is invoked with both
237
- # a block and a pattern, it only uses the pattern.
238
- #
239
- # @param [ Object ] condition The condition that documents
240
- # must satisfy. See Enumerable documentation for details.
241
- #
242
- # @return [ true, false ] If the association has any documents.
243
- def any?(*args)
244
- return super if args.any? || block_given?
245
-
246
- if _loaded?
247
- in_memory.length > 0
248
- else
249
- _unloaded.exists? || _added.length > 0
250
- end
201
+ # Is the enumerable empty? Will determine if the count is zero based on
202
+ # whether or not it is _loaded.
203
+ #
204
+ # @example Is the enumerable empty?
205
+ # enumerable.empty?
206
+ #
207
+ # @return [ true, false ] If the enumerable is empty.
208
+ #
209
+ # @since 2.1.0
210
+ def empty?
211
+ if _loaded?
212
+ in_memory.empty?
213
+ else
214
+ _added.empty? && !_unloaded.exists?
251
215
  end
216
+ end
252
217
 
253
- # Get the first document in the enumerable. Will check the persisted
254
- # documents first. Does not load the entire enumerable.
255
- #
256
- # @example Get the first document.
257
- # enumerable.first
258
- #
259
- # @note Automatically adding a sort on _id when no other sort is
260
- # defined on the criteria has the potential to cause bad performance issues.
261
- # If you experience unexpected poor performance when using #first or #last,
262
- # use the option { id_sort: :none }.
263
- # Be aware that #first/#last won't guarantee order in this case.
264
- #
265
- # @param [ Hash ] opts The options for the query returning the first document.
266
- #
267
- # @option opts [ :none ] :id_sort Don't apply a sort on _id.
268
- #
269
- # @return [ Document ] The first document found.
270
- #
271
- # @since 2.1.0
272
- def first(opts = {})
273
- _loaded.try(:values).try(:first) ||
274
- _added[(ul = _unloaded.try(:first, opts)).try(:id)] ||
275
- ul ||
276
- _added.values.try(:first)
277
- end
218
+ # Returns whether the association has any documents, optionally
219
+ # subject to the provided filters.
220
+ #
221
+ # This method returns true if the association has any persisted
222
+ # documents and if it has any not yet persisted documents.
223
+ #
224
+ # If the association is already loaded, this method inspects the
225
+ # loaded documents and does not query the database. If the
226
+ # association is not loaded, the argument-less and block-less
227
+ # version does not load the association; the other versions
228
+ # (that delegate to Enumerable) may or may not load the association
229
+ # completely depending on whether it is iterated to completion.
230
+ #
231
+ # This method can take a parameter and a block. The behavior with
232
+ # either the paramater or the block is delegated to the standard
233
+ # library Enumerable module.
234
+ #
235
+ # Note that when Enumerable's any? method is invoked with both
236
+ # a block and a pattern, it only uses the pattern.
237
+ #
238
+ # @param [ Object ] condition The condition that documents
239
+ # must satisfy. See Enumerable documentation for details.
240
+ #
241
+ # @return [ true, false ] If the association has any documents.
242
+ def any?(*args)
243
+ return super if args.any? || block_given?
244
+
245
+ !empty?
246
+ end
278
247
 
279
- # Initialize the new enumerable either with a criteria or an array.
280
- #
281
- # @example Initialize the enumerable with a criteria.
282
- # Enumberable.new(Post.where(:person_id => id))
283
- #
284
- # @example Initialize the enumerable with an array.
285
- # Enumerable.new([ post ])
286
- #
287
- # @param [ Criteria, Array<Document> ] target The wrapped object.
288
- #
289
- # @since 2.1.0
290
- def initialize(target, base = nil, association = nil)
291
- @_base = base
292
- @_association = association
293
- if target.is_a?(Criteria)
294
- @_added, @executed, @_loaded, @_unloaded = {}, false, {}, target
295
- else
296
- @_added, @executed = {}, true
297
- @_loaded = target.inject({}) do |_target, doc|
298
- _target[doc._id] = doc if doc
299
- _target
300
- end
248
+ # Get the first document in the enumerable. Will check the persisted
249
+ # documents first. Does not load the entire enumerable.
250
+ #
251
+ # @example Get the first document.
252
+ # enumerable.first
253
+ #
254
+ # @note Automatically adding a sort on _id when no other sort is
255
+ # defined on the criteria has the potential to cause bad performance issues.
256
+ # If you experience unexpected poor performance when using #first or #last,
257
+ # use the option { id_sort: :none }.
258
+ # Be aware that #first/#last won't guarantee order in this case.
259
+ #
260
+ # @param [ Hash ] opts The options for the query returning the first document.
261
+ #
262
+ # @option opts [ :none ] :id_sort Don't apply a sort on _id.
263
+ #
264
+ # @return [ Document ] The first document found.
265
+ #
266
+ # @since 2.1.0
267
+ def first(opts = {})
268
+ _loaded.try(:values).try(:first) ||
269
+ _added[(ul = _unloaded.try(:first, opts)).try(:_id)] ||
270
+ ul ||
271
+ _added.values.try(:first)
272
+ end
273
+
274
+ # Initialize the new enumerable either with a criteria or an array.
275
+ #
276
+ # @example Initialize the enumerable with a criteria.
277
+ # Enumberable.new(Post.where(:person_id => id))
278
+ #
279
+ # @example Initialize the enumerable with an array.
280
+ # Enumerable.new([ post ])
281
+ #
282
+ # @param [ Criteria, Array<Document> ] target The wrapped object.
283
+ #
284
+ # @since 2.1.0
285
+ def initialize(target, base = nil, association = nil)
286
+ @_base = base
287
+ @_association = association
288
+ if target.is_a?(Criteria)
289
+ @_added, @executed, @_loaded, @_unloaded = {}, false, {}, target
290
+ else
291
+ @_added, @executed = {}, true
292
+ @_loaded = target.inject({}) do |_target, doc|
293
+ _target[doc._id] = doc if doc
294
+ _target
301
295
  end
302
296
  end
297
+ end
303
298
 
304
- # Does the target include the provided document?
305
- #
306
- # @example Does the target include the document?
307
- # enumerable.include?(document)
308
- #
309
- # @param [ Document ] doc The document to check.
310
- #
311
- # @return [ true, false ] If the document is in the target.
312
- #
313
- # @since 3.0.0
314
- def include?(doc)
315
- return super unless _unloaded
316
- _unloaded.where(_id: doc._id).exists? || _added.has_key?(doc._id)
317
- end
299
+ # Does the target include the provided document?
300
+ #
301
+ # @example Does the target include the document?
302
+ # enumerable.include?(document)
303
+ #
304
+ # @param [ Document ] doc The document to check.
305
+ #
306
+ # @return [ true, false ] If the document is in the target.
307
+ #
308
+ # @since 3.0.0
309
+ def include?(doc)
310
+ return super unless _unloaded
311
+ _unloaded.where(_id: doc._id).exists? || _added.has_key?(doc._id)
312
+ end
318
313
 
319
- # Inspection will just inspect the entries for nice array-style
320
- # printing.
321
- #
322
- # @example Inspect the enumerable.
323
- # enumerable.inspect
324
- #
325
- # @return [ String ] The inspected enum.
326
- #
327
- # @since 2.1.0
328
- def inspect
329
- entries.inspect
330
- end
314
+ # Inspection will just inspect the entries for nice array-style
315
+ # printing.
316
+ #
317
+ # @example Inspect the enumerable.
318
+ # enumerable.inspect
319
+ #
320
+ # @return [ String ] The inspected enum.
321
+ #
322
+ # @since 2.1.0
323
+ def inspect
324
+ entries.inspect
325
+ end
331
326
 
332
- # Return all the documents in the enumerable that have been _loaded or
333
- # _added.
334
- #
335
- # @note When passed a block it yields to each document.
336
- #
337
- # @example Get the in memory docs.
338
- # enumerable.in_memory
339
- #
340
- # @return [ Array<Document> ] The in memory docs.
341
- #
342
- # @since 2.1.0
343
- def in_memory
344
- docs = (_loaded.values + _added.values)
345
- docs.each do |doc|
346
- yield(doc) if block_given?
347
- end
327
+ # Return all the documents in the enumerable that have been _loaded or
328
+ # _added.
329
+ #
330
+ # @note When passed a block it yields to each document.
331
+ #
332
+ # @example Get the in memory docs.
333
+ # enumerable.in_memory
334
+ #
335
+ # @return [ Array<Document> ] The in memory docs.
336
+ #
337
+ # @since 2.1.0
338
+ def in_memory
339
+ docs = (_loaded.values + _added.values)
340
+ docs.each do |doc|
341
+ yield(doc) if block_given?
348
342
  end
343
+ end
349
344
 
350
- # Get the last document in the enumerable. Will check the new
351
- # documents first. Does not load the entire enumerable.
352
- #
353
- # @example Get the last document.
354
- # enumerable.last
355
- #
356
- # @note Automatically adding a sort on _id when no other sort is
357
- # defined on the criteria has the potential to cause bad performance issues.
358
- # If you experience unexpected poor performance when using #first or #last,
359
- # use the option { id_sort: :none }.
360
- # Be aware that #first/#last won't guarantee order in this case.
361
- #
362
- # @param [ Hash ] opts The options for the query returning the first document.
363
- #
364
- # @option opts [ :none ] :id_sort Don't apply a sort on _id.
365
- #
366
- # @return [ Document ] The last document found.
367
- #
368
- # @since 2.1.0
369
- def last(opts = {})
370
- _added.values.try(:last) ||
371
- _loaded.try(:values).try(:last) ||
372
- _added[(ul = _unloaded.try(:last, opts)).try(:id)] ||
373
- ul
374
- end
345
+ # Get the last document in the enumerable. Will check the new
346
+ # documents first. Does not load the entire enumerable.
347
+ #
348
+ # @example Get the last document.
349
+ # enumerable.last
350
+ #
351
+ # @note Automatically adding a sort on _id when no other sort is
352
+ # defined on the criteria has the potential to cause bad performance issues.
353
+ # If you experience unexpected poor performance when using #first or #last,
354
+ # use the option { id_sort: :none }.
355
+ # Be aware that #first/#last won't guarantee order in this case.
356
+ #
357
+ # @param [ Hash ] opts The options for the query returning the first document.
358
+ #
359
+ # @option opts [ :none ] :id_sort Don't apply a sort on _id.
360
+ #
361
+ # @return [ Document ] The last document found.
362
+ #
363
+ # @since 2.1.0
364
+ def last(opts = {})
365
+ _added.values.try(:last) ||
366
+ _loaded.try(:values).try(:last) ||
367
+ _added[(ul = _unloaded.try(:last, opts)).try(:_id)] ||
368
+ ul
369
+ end
375
370
 
376
- # Loads all the documents in the enumerable from the database.
377
- #
378
- # @example Load all the documents.
379
- # enumerable.load_all!
380
- #
381
- # @return [ true ] That the enumerable is _loaded.
382
- #
383
- # @since 2.1.0
384
- alias :load_all! :entries
385
-
386
- # Has the enumerable been _loaded? This will be true if the criteria has
387
- # been executed or we manually load the entire thing.
388
- #
389
- # @example Is the enumerable _loaded?
390
- # enumerable._loaded?
391
- #
392
- # @return [ true, false ] If the enumerable has been _loaded.
393
- #
394
- # @since 2.1.0
395
- def _loaded?
396
- !!@executed
397
- end
371
+ # Loads all the documents in the enumerable from the database.
372
+ #
373
+ # @example Load all the documents.
374
+ # enumerable.load_all!
375
+ #
376
+ # @return [ true ] That the enumerable is _loaded.
377
+ #
378
+ # @since 2.1.0
379
+ alias :load_all! :entries
380
+
381
+ # Has the enumerable been _loaded? This will be true if the criteria has
382
+ # been executed or we manually load the entire thing.
383
+ #
384
+ # @example Is the enumerable _loaded?
385
+ # enumerable._loaded?
386
+ #
387
+ # @return [ true, false ] If the enumerable has been _loaded.
388
+ #
389
+ # @since 2.1.0
390
+ def _loaded?
391
+ !!@executed
392
+ end
398
393
 
399
- # Provides the data needed to Marshal.dump an enumerable proxy.
400
- #
401
- # @example Dump the proxy.
402
- # Marshal.dump(proxy)
403
- #
404
- # @return [ Array<Object> ] The dumped data.
405
- #
406
- # @since 3.0.15
407
- def marshal_dump
408
- [_added, _loaded, _unloaded, @executed]
409
- end
394
+ # Provides the data needed to Marshal.dump an enumerable proxy.
395
+ #
396
+ # @example Dump the proxy.
397
+ # Marshal.dump(proxy)
398
+ #
399
+ # @return [ Array<Object> ] The dumped data.
400
+ #
401
+ # @since 3.0.15
402
+ def marshal_dump
403
+ [_added, _loaded, _unloaded, @executed]
404
+ end
410
405
 
411
- # Loads the data needed to Marshal.load an enumerable proxy.
412
- #
413
- # @example Load the proxy.
414
- # Marshal.load(proxy)
415
- #
416
- # @return [ Array<Object> ] The dumped data.
417
- #
418
- # @since 3.0.15
419
- def marshal_load(data)
420
- @_added, @_loaded, @_unloaded, @executed = data
421
- end
406
+ # Loads the data needed to Marshal.load an enumerable proxy.
407
+ #
408
+ # @example Load the proxy.
409
+ # Marshal.load(proxy)
410
+ #
411
+ # @return [ Array<Object> ] The dumped data.
412
+ #
413
+ # @since 3.0.15
414
+ def marshal_load(data)
415
+ @_added, @_loaded, @_unloaded, @executed = data
416
+ end
422
417
 
423
- # Reset the enumerable back to its persisted state.
424
- #
425
- # @example Reset the enumerable.
426
- # enumerable.reset
427
- #
428
- # @return [ false ] Always false.
429
- #
430
- # @since 2.1.0
431
- def reset
432
- _loaded.clear
433
- _added.clear
434
- @executed = false
435
- end
418
+ # Reset the enumerable back to its persisted state.
419
+ #
420
+ # @example Reset the enumerable.
421
+ # enumerable.reset
422
+ #
423
+ # @return [ false ] Always false.
424
+ #
425
+ # @since 2.1.0
426
+ def reset
427
+ _loaded.clear
428
+ _added.clear
429
+ @executed = false
430
+ end
436
431
 
437
- # Resets the underlying unloaded criteria object with a new one. Used
438
- # my HABTM associations to keep the underlying array in sync.
439
- #
440
- # @example Reset the unloaded documents.
441
- # enumerable.reset_unloaded(criteria)
442
- #
443
- # @param [ Criteria ] criteria The criteria to replace with.
444
- #
445
- # @since 3.0.14
446
- def reset_unloaded(criteria)
447
- @_unloaded = criteria if _unloaded.is_a?(Criteria)
448
- end
432
+ # Resets the underlying unloaded criteria object with a new one. Used
433
+ # my HABTM associations to keep the underlying array in sync.
434
+ #
435
+ # @example Reset the unloaded documents.
436
+ # enumerable.reset_unloaded(criteria)
437
+ #
438
+ # @param [ Criteria ] criteria The criteria to replace with.
439
+ #
440
+ # @since 3.0.14
441
+ def reset_unloaded(criteria)
442
+ @_unloaded = criteria if _unloaded.is_a?(Criteria)
443
+ end
449
444
 
450
- # Does this enumerable respond to the provided method?
451
- #
452
- # @example Does the enumerable respond to the method?
453
- # enumerable.respond_to?(:sum)
454
- #
455
- # @param [ String, Symbol ] name The name of the method.
456
- # @param [ true, false ] include_private Whether to include private
457
- # methods.
458
- #
459
- # @return [ true, false ] Whether the enumerable responds.
460
- #
461
- # @since 2.1.0
462
- def respond_to?(name, include_private = false)
463
- [].respond_to?(name, include_private) || super
464
- end
445
+ # Does this enumerable respond to the provided method?
446
+ #
447
+ # @example Does the enumerable respond to the method?
448
+ # enumerable.respond_to?(:sum)
449
+ #
450
+ # @param [ String, Symbol ] name The name of the method.
451
+ # @param [ true, false ] include_private Whether to include private
452
+ # methods.
453
+ #
454
+ # @return [ true, false ] Whether the enumerable responds.
455
+ #
456
+ # @since 2.1.0
457
+ def respond_to?(name, include_private = false)
458
+ [].respond_to?(name, include_private) || super
459
+ end
465
460
 
466
- # Gets the total size of this enumerable. This is a combination of all
467
- # the persisted and unpersisted documents.
468
- #
469
- # @example Get the size.
470
- # enumerable.size
471
- #
472
- # @return [ Integer ] The size of the enumerable.
473
- #
474
- # @since 2.1.0
475
- def size
476
- count = (_unloaded ? _unloaded.count : _loaded.count)
477
- if count.zero?
478
- count + _added.count
479
- else
480
- count + _added.values.count { |d| d.new_record? }
481
- end
461
+ # Gets the total size of this enumerable. This is a combination of all
462
+ # the persisted and unpersisted documents.
463
+ #
464
+ # @example Get the size.
465
+ # enumerable.size
466
+ #
467
+ # @return [ Integer ] The size of the enumerable.
468
+ #
469
+ # @since 2.1.0
470
+ def size
471
+ count = (_unloaded ? _unloaded.count : _loaded.count)
472
+ if count.zero?
473
+ count + _added.count
474
+ else
475
+ count + _added.values.count { |d| d.new_record? }
482
476
  end
477
+ end
483
478
 
484
- alias :length :size
485
-
486
- # Send #to_json to the entries.
487
- #
488
- # @example Get the enumerable as json.
489
- # enumerable.to_json
490
- #
491
- # @param [ Hash ] options Optional parameters.
492
- #
493
- # @return [ String ] The entries all _loaded as a string.
494
- #
495
- # @since 2.2.0
496
- def to_json(options = {})
497
- entries.to_json(options)
498
- end
479
+ alias :length :size
480
+
481
+ # Send #to_json to the entries.
482
+ #
483
+ # @example Get the enumerable as json.
484
+ # enumerable.to_json
485
+ #
486
+ # @param [ Hash ] options Optional parameters.
487
+ #
488
+ # @return [ String ] The entries all _loaded as a string.
489
+ #
490
+ # @since 2.2.0
491
+ def to_json(options = {})
492
+ entries.to_json(options)
493
+ end
499
494
 
500
- # Send #as_json to the entries, without encoding.
501
- #
502
- # @example Get the enumerable as json.
503
- # enumerable.as_json
504
- #
505
- # @param [ Hash ] options Optional parameters.
506
- #
507
- # @return [ Hash ] The entries all _loaded as a hash.
508
- #
509
- # @since 2.2.0
510
- def as_json(options = {})
511
- entries.as_json(options)
512
- end
495
+ # Send #as_json to the entries, without encoding.
496
+ #
497
+ # @example Get the enumerable as json.
498
+ # enumerable.as_json
499
+ #
500
+ # @param [ Hash ] options Optional parameters.
501
+ #
502
+ # @return [ Hash ] The entries all _loaded as a hash.
503
+ #
504
+ # @since 2.2.0
505
+ def as_json(options = {})
506
+ entries.as_json(options)
507
+ end
513
508
 
514
- # Return all the unique documents in the enumerable.
515
- #
516
- # @note This operation loads all documents from the database.
517
- #
518
- # @example Get all the unique documents.
519
- # enumerable.uniq
520
- #
521
- # @return [ Array<Document> ] The unique documents.
522
- #
523
- # @since 2.1.0
524
- def uniq
525
- entries.uniq
526
- end
509
+ # Return all the unique documents in the enumerable.
510
+ #
511
+ # @note This operation loads all documents from the database.
512
+ #
513
+ # @example Get all the unique documents.
514
+ # enumerable.uniq
515
+ #
516
+ # @return [ Array<Document> ] The unique documents.
517
+ #
518
+ # @since 2.1.0
519
+ def uniq
520
+ entries.uniq
521
+ end
527
522
 
528
- private
523
+ private
529
524
 
530
- def set_base(document)
531
- if @_association.is_a?(Referenced::HasMany)
532
- document.set_relation(@_association.inverse, @_base) if @_association
533
- end
525
+ def set_base(document)
526
+ if @_association.is_a?(Referenced::HasMany)
527
+ document.set_relation(@_association.inverse, @_base) if @_association
534
528
  end
529
+ end
535
530
 
536
- ruby2_keywords def method_missing(name, *args, &block)
537
- entries.send(name, *args, &block)
538
- end
531
+ ruby2_keywords def method_missing(name, *args, &block)
532
+ entries.send(name, *args, &block)
533
+ end
539
534
 
540
- def unloaded_documents
541
- if _unloaded.selector._mongoid_unsatisfiable_criteria?
542
- []
543
- else
544
- _unloaded
545
- end
535
+ def unloaded_documents
536
+ if _unloaded.selector._mongoid_unsatisfiable_criteria?
537
+ []
538
+ else
539
+ _unloaded
546
540
  end
547
541
  end
548
542
  end