mongoid-braxton 2.0.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.
Files changed (226) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +50 -0
  3. data/Rakefile +51 -0
  4. data/lib/config/locales/bg.yml +41 -0
  5. data/lib/config/locales/de.yml +41 -0
  6. data/lib/config/locales/en.yml +45 -0
  7. data/lib/config/locales/es.yml +41 -0
  8. data/lib/config/locales/fr.yml +42 -0
  9. data/lib/config/locales/hu.yml +44 -0
  10. data/lib/config/locales/id.yml +46 -0
  11. data/lib/config/locales/it.yml +39 -0
  12. data/lib/config/locales/ja.yml +40 -0
  13. data/lib/config/locales/kr.yml +65 -0
  14. data/lib/config/locales/nl.yml +39 -0
  15. data/lib/config/locales/pl.yml +39 -0
  16. data/lib/config/locales/pt-BR.yml +40 -0
  17. data/lib/config/locales/pt.yml +40 -0
  18. data/lib/config/locales/ro.yml +46 -0
  19. data/lib/config/locales/ru.yml +41 -0
  20. data/lib/config/locales/sv.yml +40 -0
  21. data/lib/config/locales/vi.yml +45 -0
  22. data/lib/config/locales/zh-CN.yml +33 -0
  23. data/lib/mongoid.rb +140 -0
  24. data/lib/mongoid/atomicity.rb +111 -0
  25. data/lib/mongoid/attributes.rb +185 -0
  26. data/lib/mongoid/attributes/processing.rb +145 -0
  27. data/lib/mongoid/callbacks.rb +23 -0
  28. data/lib/mongoid/collection.rb +137 -0
  29. data/lib/mongoid/collections.rb +71 -0
  30. data/lib/mongoid/collections/master.rb +37 -0
  31. data/lib/mongoid/collections/operations.rb +42 -0
  32. data/lib/mongoid/collections/retry.rb +39 -0
  33. data/lib/mongoid/components.rb +45 -0
  34. data/lib/mongoid/config.rb +349 -0
  35. data/lib/mongoid/config/database.rb +167 -0
  36. data/lib/mongoid/config/replset_database.rb +78 -0
  37. data/lib/mongoid/contexts.rb +19 -0
  38. data/lib/mongoid/contexts/enumerable.rb +275 -0
  39. data/lib/mongoid/contexts/enumerable/sort.rb +43 -0
  40. data/lib/mongoid/contexts/mongo.rb +345 -0
  41. data/lib/mongoid/copyable.rb +46 -0
  42. data/lib/mongoid/criteria.rb +357 -0
  43. data/lib/mongoid/criterion/builder.rb +34 -0
  44. data/lib/mongoid/criterion/complex.rb +34 -0
  45. data/lib/mongoid/criterion/creational.rb +34 -0
  46. data/lib/mongoid/criterion/exclusion.rb +108 -0
  47. data/lib/mongoid/criterion/inclusion.rb +198 -0
  48. data/lib/mongoid/criterion/inspection.rb +22 -0
  49. data/lib/mongoid/criterion/optional.rb +193 -0
  50. data/lib/mongoid/criterion/selector.rb +143 -0
  51. data/lib/mongoid/criterion/unconvertable.rb +20 -0
  52. data/lib/mongoid/cursor.rb +86 -0
  53. data/lib/mongoid/default_scope.rb +36 -0
  54. data/lib/mongoid/dirty.rb +253 -0
  55. data/lib/mongoid/document.rb +284 -0
  56. data/lib/mongoid/errors.rb +13 -0
  57. data/lib/mongoid/errors/document_not_found.rb +29 -0
  58. data/lib/mongoid/errors/invalid_collection.rb +19 -0
  59. data/lib/mongoid/errors/invalid_database.rb +20 -0
  60. data/lib/mongoid/errors/invalid_field.rb +19 -0
  61. data/lib/mongoid/errors/invalid_options.rb +16 -0
  62. data/lib/mongoid/errors/invalid_type.rb +26 -0
  63. data/lib/mongoid/errors/mixed_relations.rb +37 -0
  64. data/lib/mongoid/errors/mongoid_error.rb +27 -0
  65. data/lib/mongoid/errors/too_many_nested_attribute_records.rb +21 -0
  66. data/lib/mongoid/errors/unsaved_document.rb +23 -0
  67. data/lib/mongoid/errors/unsupported_version.rb +21 -0
  68. data/lib/mongoid/errors/validations.rb +24 -0
  69. data/lib/mongoid/extensions.rb +123 -0
  70. data/lib/mongoid/extensions/array/conversions.rb +23 -0
  71. data/lib/mongoid/extensions/array/parentization.rb +13 -0
  72. data/lib/mongoid/extensions/big_decimal/conversions.rb +19 -0
  73. data/lib/mongoid/extensions/binary/conversions.rb +17 -0
  74. data/lib/mongoid/extensions/boolean/conversions.rb +27 -0
  75. data/lib/mongoid/extensions/date/conversions.rb +25 -0
  76. data/lib/mongoid/extensions/datetime/conversions.rb +12 -0
  77. data/lib/mongoid/extensions/false_class/equality.rb +13 -0
  78. data/lib/mongoid/extensions/float/conversions.rb +20 -0
  79. data/lib/mongoid/extensions/hash/conversions.rb +19 -0
  80. data/lib/mongoid/extensions/hash/criteria_helpers.rb +22 -0
  81. data/lib/mongoid/extensions/hash/scoping.rb +12 -0
  82. data/lib/mongoid/extensions/integer/conversions.rb +20 -0
  83. data/lib/mongoid/extensions/nil/collectionization.rb +12 -0
  84. data/lib/mongoid/extensions/object/checks.rb +32 -0
  85. data/lib/mongoid/extensions/object/conversions.rb +25 -0
  86. data/lib/mongoid/extensions/object/reflections.rb +17 -0
  87. data/lib/mongoid/extensions/object/yoda.rb +27 -0
  88. data/lib/mongoid/extensions/object_id/conversions.rb +96 -0
  89. data/lib/mongoid/extensions/proc/scoping.rb +12 -0
  90. data/lib/mongoid/extensions/range/conversions.rb +25 -0
  91. data/lib/mongoid/extensions/set/conversions.rb +20 -0
  92. data/lib/mongoid/extensions/string/conversions.rb +34 -0
  93. data/lib/mongoid/extensions/string/inflections.rb +97 -0
  94. data/lib/mongoid/extensions/symbol/conversions.rb +21 -0
  95. data/lib/mongoid/extensions/symbol/inflections.rb +40 -0
  96. data/lib/mongoid/extensions/time_conversions.rb +38 -0
  97. data/lib/mongoid/extensions/true_class/equality.rb +13 -0
  98. data/lib/mongoid/extras.rb +42 -0
  99. data/lib/mongoid/factory.rb +37 -0
  100. data/lib/mongoid/field.rb +162 -0
  101. data/lib/mongoid/fields.rb +183 -0
  102. data/lib/mongoid/finders.rb +127 -0
  103. data/lib/mongoid/hierarchy.rb +85 -0
  104. data/lib/mongoid/identity.rb +92 -0
  105. data/lib/mongoid/indexes.rb +38 -0
  106. data/lib/mongoid/inspection.rb +54 -0
  107. data/lib/mongoid/javascript.rb +21 -0
  108. data/lib/mongoid/javascript/functions.yml +37 -0
  109. data/lib/mongoid/json.rb +16 -0
  110. data/lib/mongoid/keys.rb +131 -0
  111. data/lib/mongoid/logger.rb +18 -0
  112. data/lib/mongoid/matchers.rb +32 -0
  113. data/lib/mongoid/matchers/all.rb +11 -0
  114. data/lib/mongoid/matchers/default.rb +70 -0
  115. data/lib/mongoid/matchers/exists.rb +13 -0
  116. data/lib/mongoid/matchers/gt.rb +11 -0
  117. data/lib/mongoid/matchers/gte.rb +11 -0
  118. data/lib/mongoid/matchers/in.rb +11 -0
  119. data/lib/mongoid/matchers/lt.rb +11 -0
  120. data/lib/mongoid/matchers/lte.rb +11 -0
  121. data/lib/mongoid/matchers/ne.rb +11 -0
  122. data/lib/mongoid/matchers/nin.rb +11 -0
  123. data/lib/mongoid/matchers/or.rb +30 -0
  124. data/lib/mongoid/matchers/size.rb +11 -0
  125. data/lib/mongoid/matchers/strategies.rb +63 -0
  126. data/lib/mongoid/multi_database.rb +11 -0
  127. data/lib/mongoid/multi_parameter_attributes.rb +82 -0
  128. data/lib/mongoid/named_scope.rb +137 -0
  129. data/lib/mongoid/nested_attributes.rb +51 -0
  130. data/lib/mongoid/observer.rb +67 -0
  131. data/lib/mongoid/paranoia.rb +103 -0
  132. data/lib/mongoid/paths.rb +61 -0
  133. data/lib/mongoid/persistence.rb +240 -0
  134. data/lib/mongoid/persistence/atomic.rb +88 -0
  135. data/lib/mongoid/persistence/atomic/add_to_set.rb +32 -0
  136. data/lib/mongoid/persistence/atomic/inc.rb +28 -0
  137. data/lib/mongoid/persistence/atomic/operation.rb +44 -0
  138. data/lib/mongoid/persistence/atomic/pull_all.rb +33 -0
  139. data/lib/mongoid/persistence/atomic/push.rb +28 -0
  140. data/lib/mongoid/persistence/command.rb +71 -0
  141. data/lib/mongoid/persistence/insert.rb +53 -0
  142. data/lib/mongoid/persistence/insert_embedded.rb +43 -0
  143. data/lib/mongoid/persistence/remove.rb +44 -0
  144. data/lib/mongoid/persistence/remove_all.rb +40 -0
  145. data/lib/mongoid/persistence/remove_embedded.rb +48 -0
  146. data/lib/mongoid/persistence/update.rb +77 -0
  147. data/lib/mongoid/railtie.rb +139 -0
  148. data/lib/mongoid/railties/database.rake +171 -0
  149. data/lib/mongoid/railties/document.rb +12 -0
  150. data/lib/mongoid/relations.rb +107 -0
  151. data/lib/mongoid/relations/accessors.rb +175 -0
  152. data/lib/mongoid/relations/auto_save.rb +34 -0
  153. data/lib/mongoid/relations/binding.rb +26 -0
  154. data/lib/mongoid/relations/bindings.rb +9 -0
  155. data/lib/mongoid/relations/bindings/embedded/in.rb +82 -0
  156. data/lib/mongoid/relations/bindings/embedded/many.rb +98 -0
  157. data/lib/mongoid/relations/bindings/embedded/one.rb +66 -0
  158. data/lib/mongoid/relations/bindings/referenced/in.rb +74 -0
  159. data/lib/mongoid/relations/bindings/referenced/many.rb +96 -0
  160. data/lib/mongoid/relations/bindings/referenced/many_to_many.rb +103 -0
  161. data/lib/mongoid/relations/bindings/referenced/one.rb +66 -0
  162. data/lib/mongoid/relations/builder.rb +42 -0
  163. data/lib/mongoid/relations/builders.rb +79 -0
  164. data/lib/mongoid/relations/builders/embedded/in.rb +25 -0
  165. data/lib/mongoid/relations/builders/embedded/many.rb +32 -0
  166. data/lib/mongoid/relations/builders/embedded/one.rb +26 -0
  167. data/lib/mongoid/relations/builders/nested_attributes/many.rb +126 -0
  168. data/lib/mongoid/relations/builders/nested_attributes/one.rb +135 -0
  169. data/lib/mongoid/relations/builders/referenced/in.rb +29 -0
  170. data/lib/mongoid/relations/builders/referenced/many.rb +47 -0
  171. data/lib/mongoid/relations/builders/referenced/many_to_many.rb +29 -0
  172. data/lib/mongoid/relations/builders/referenced/one.rb +27 -0
  173. data/lib/mongoid/relations/cascading.rb +55 -0
  174. data/lib/mongoid/relations/cascading/delete.rb +19 -0
  175. data/lib/mongoid/relations/cascading/destroy.rb +19 -0
  176. data/lib/mongoid/relations/cascading/nullify.rb +18 -0
  177. data/lib/mongoid/relations/cascading/strategy.rb +26 -0
  178. data/lib/mongoid/relations/constraint.rb +42 -0
  179. data/lib/mongoid/relations/cyclic.rb +103 -0
  180. data/lib/mongoid/relations/embedded/atomic.rb +86 -0
  181. data/lib/mongoid/relations/embedded/atomic/operation.rb +63 -0
  182. data/lib/mongoid/relations/embedded/atomic/pull.rb +65 -0
  183. data/lib/mongoid/relations/embedded/atomic/push_all.rb +59 -0
  184. data/lib/mongoid/relations/embedded/atomic/set.rb +61 -0
  185. data/lib/mongoid/relations/embedded/atomic/unset.rb +41 -0
  186. data/lib/mongoid/relations/embedded/in.rb +173 -0
  187. data/lib/mongoid/relations/embedded/many.rb +499 -0
  188. data/lib/mongoid/relations/embedded/one.rb +170 -0
  189. data/lib/mongoid/relations/macros.rb +310 -0
  190. data/lib/mongoid/relations/many.rb +215 -0
  191. data/lib/mongoid/relations/metadata.rb +539 -0
  192. data/lib/mongoid/relations/nested_builder.rb +68 -0
  193. data/lib/mongoid/relations/one.rb +47 -0
  194. data/lib/mongoid/relations/polymorphic.rb +54 -0
  195. data/lib/mongoid/relations/proxy.rb +143 -0
  196. data/lib/mongoid/relations/referenced/batch.rb +71 -0
  197. data/lib/mongoid/relations/referenced/batch/insert.rb +57 -0
  198. data/lib/mongoid/relations/referenced/in.rb +216 -0
  199. data/lib/mongoid/relations/referenced/many.rb +516 -0
  200. data/lib/mongoid/relations/referenced/many_to_many.rb +396 -0
  201. data/lib/mongoid/relations/referenced/one.rb +222 -0
  202. data/lib/mongoid/relations/reflections.rb +45 -0
  203. data/lib/mongoid/safe.rb +23 -0
  204. data/lib/mongoid/safety.rb +207 -0
  205. data/lib/mongoid/scope.rb +31 -0
  206. data/lib/mongoid/serialization.rb +99 -0
  207. data/lib/mongoid/sharding.rb +51 -0
  208. data/lib/mongoid/state.rb +67 -0
  209. data/lib/mongoid/timestamps.rb +14 -0
  210. data/lib/mongoid/timestamps/created.rb +31 -0
  211. data/lib/mongoid/timestamps/updated.rb +33 -0
  212. data/lib/mongoid/validations.rb +124 -0
  213. data/lib/mongoid/validations/associated.rb +44 -0
  214. data/lib/mongoid/validations/referenced.rb +58 -0
  215. data/lib/mongoid/validations/uniqueness.rb +85 -0
  216. data/lib/mongoid/version.rb +4 -0
  217. data/lib/mongoid/versioning.rb +113 -0
  218. data/lib/rails/generators/mongoid/config/config_generator.rb +25 -0
  219. data/lib/rails/generators/mongoid/config/templates/mongoid.yml +20 -0
  220. data/lib/rails/generators/mongoid/model/model_generator.rb +24 -0
  221. data/lib/rails/generators/mongoid/model/templates/model.rb +19 -0
  222. data/lib/rails/generators/mongoid/observer/observer_generator.rb +17 -0
  223. data/lib/rails/generators/mongoid/observer/templates/observer.rb +4 -0
  224. data/lib/rails/generators/mongoid_generator.rb +70 -0
  225. data/lib/rails/mongoid.rb +58 -0
  226. metadata +406 -0
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Symbol#:nodoc:
5
+ # This module converts objects into mongoid related objects.
6
+ module Conversions #:nodoc:
7
+ extend ActiveSupport::Concern
8
+
9
+ module ClassMethods
10
+ def set(value)
11
+ (value.nil? or (value.respond_to?(:empty?) && value.empty?)) ? nil : value.to_sym
12
+ end
13
+
14
+ def get(value)
15
+ value
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,40 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module Symbol #:nodoc:
5
+ module Inflections #:nodoc:
6
+
7
+ REVERSALS = {
8
+ :asc => :desc,
9
+ :ascending => :descending,
10
+ :desc => :asc,
11
+ :descending => :ascending
12
+ }
13
+
14
+ def invert
15
+ REVERSALS[self]
16
+ end
17
+
18
+ def singular?
19
+ to_s.singular?
20
+ end
21
+
22
+ def plural?
23
+ to_s.plural?
24
+ end
25
+
26
+ [ "asc", "ascending", "desc", "descending", "gt", "lt", "gte",
27
+ "lte", "ne", "near", "in", "nin", "mod", "all", "size", "exists",
28
+ "within", ["matches","elemMatch"] ].each do |oper|
29
+ m, oper = oper
30
+ oper = m unless oper
31
+ class_eval <<-OPERATORS
32
+ def #{m}
33
+ Criterion::Complex.new(:key => self, :operator => "#{oper}")
34
+ end
35
+ OPERATORS
36
+ end
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,38 @@
1
+ module Mongoid #:nodoc:
2
+ module Extensions #:nodoc:
3
+ module TimeConversions #:nodoc:
4
+ def set(value)
5
+ return nil if value.blank?
6
+ time = convert_to_time(value)
7
+ strip_milliseconds(time).utc
8
+ end
9
+
10
+ def get(value)
11
+ return nil if value.blank?
12
+ value = value.getlocal unless Mongoid::Config.use_utc?
13
+ if Mongoid::Config.use_activesupport_time_zone?
14
+ time_zone = Mongoid::Config.use_utc? ? 'UTC' : Time.zone
15
+ value = value.in_time_zone(time_zone)
16
+ end
17
+ value
18
+ end
19
+
20
+ protected
21
+
22
+ def strip_milliseconds(time)
23
+ ::Time.at(time.to_i)
24
+ end
25
+
26
+ def convert_to_time(value)
27
+ time = Mongoid::Config.use_activesupport_time_zone? ? ::Time.zone : ::Time
28
+ case value
29
+ when ::String then time.parse(value)
30
+ when ::DateTime then time.local(value.year, value.month, value.day, value.hour, value.min, value.sec)
31
+ when ::Date then time.local(value.year, value.month, value.day)
32
+ when ::Array then time.local(*value)
33
+ else value
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,13 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+ module Extensions #:nodoc:
4
+ module TrueClass #:nodoc:
5
+ module Equality #:nodoc:
6
+ def is_a?(other)
7
+ return true if other.name == "Boolean"
8
+ super(other)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,42 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Adds support for caching queries at the class level.
5
+ module Extras
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ class_attribute :cached
10
+ self.cached = false
11
+ delegate :cached?, :to => "self.class"
12
+ end
13
+
14
+ module ClassMethods #:nodoc
15
+
16
+ # Sets caching on for this class. This class level configuration will
17
+ # default all queries to cache the results of the first iteration over
18
+ # the cursor into an internal array. This should only be used for queries
19
+ # that return a small number of results or have small documents, as after
20
+ # the first iteration the entire results will be stored in memory.
21
+ #
22
+ # @example Cache all reads for the class.
23
+ # class Person
24
+ # include Mongoid::Document
25
+ # cache
26
+ # end
27
+ def cache
28
+ self.cached = true
29
+ end
30
+
31
+ # Determines if the class is cached or not.
32
+ #
33
+ # @example Are class reads cached?
34
+ # Document.cached?
35
+ #
36
+ # @return [ true, false ] If the reads are cached.
37
+ def cached?
38
+ !!self.cached
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,37 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Instantiates documents that came from the database.
5
+ module Factory
6
+ extend self
7
+
8
+ # Builds a new +Document+ from the supplied attributes.
9
+ #
10
+ # @example Build the document.
11
+ # Mongoid::Factory.build(Person, { "name" => "Durran" })
12
+ #
13
+ # @param [ Class ] klass The class to instantiate from if _type is not present.
14
+ # @param [ Hash ] attributes The document attributes.
15
+ #
16
+ # @return [ Document ] The instantiated document.
17
+ def build(klass, attributes = {})
18
+ type = (attributes || {})["_type"]
19
+ type.blank? ? klass.new(attributes) : type.constantize.new(attributes)
20
+ end
21
+
22
+ # Builds a new +Document+ from the supplied attributes loaded from the
23
+ # database.
24
+ #
25
+ # @example Build the document.
26
+ # Mongoid::Factory.from_db(Person, { "name" => "Durran" })
27
+ #
28
+ # @param [ Class ] klass The class to instantiate from if _type is not present.
29
+ # @param [ Hash ] attributes The document attributes.
30
+ #
31
+ # @return [ Document ] The instantiated document.
32
+ def from_db(klass, attributes = {})
33
+ type = attributes["_type"]
34
+ type.blank? ? klass.instantiate(attributes) : type.constantize.instantiate(attributes)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,162 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc:
3
+
4
+ # Defines the behaviour for defined fields in the document.
5
+ class Field
6
+
7
+ NO_CAST_ON_READ = [
8
+ Array, Binary, Boolean, Float, Hash,
9
+ Integer, BSON::ObjectId, Set, String, Symbol
10
+ ]
11
+
12
+ attr_accessor :type
13
+ attr_reader :copyable, :klass, :label, :name, :options
14
+
15
+ class << self
16
+
17
+ # Return a map of custom option names to their handlers.
18
+ #
19
+ # @example
20
+ # Mongoid::Field.options
21
+ # # => { :required => #<Proc:0x00000100976b38> }
22
+ #
23
+ # @return [ Hash ] the option map
24
+ def options
25
+ @options ||= {}
26
+ end
27
+
28
+ # Stores the provided block to be run when the option name specified is
29
+ # defined on a field.
30
+ #
31
+ # No assumptions are made about what sort of work the handler might
32
+ # perform, so it will always be called if the `option_name` key is
33
+ # provided in the field definition -- even if it is false or nil.
34
+ #
35
+ # @example
36
+ # Mongoid::Field.option :required do |model, field, value|
37
+ # model.validates_presence_of field if value
38
+ # end
39
+ #
40
+ # @param [ Symbol ] option_name the option name to match against
41
+ # @param [ Proc ] block the handler to execute when the option is
42
+ # provided.
43
+ def option(option_name, &block)
44
+ options[option_name] = block
45
+ end
46
+
47
+ end
48
+
49
+ # When reading the field do we need to cast the value? This holds true when
50
+ # times are stored or for big decimals which are stored as strings.
51
+ #
52
+ # @example Typecast on a read?
53
+ # field.cast_on_read?
54
+ #
55
+ # @return [ true, false ] If the field should be cast.
56
+ def cast_on_read?
57
+ !NO_CAST_ON_READ.include?(type)
58
+ end
59
+
60
+ # Get the default value for the field.
61
+ #
62
+ # @example Get the default.
63
+ # field.default
64
+ #
65
+ # @return [ Object ] The typecast default value.
66
+ #
67
+ # @since 1.0.0
68
+ def default
69
+ copy.respond_to?(:call) ? copy : set(copy)
70
+ end
71
+
72
+ # Create the new field with a name and optional additional options.
73
+ #
74
+ # @example Create the new field.
75
+ # Field.new(:name, :type => String)
76
+ #
77
+ # @param [ Hash ] options The field options.
78
+ #
79
+ # @option options [ Class ] :type The class of the field.
80
+ # @option options [ Object ] :default The default value for the field.
81
+ # @option options [ String ] :label The field's label.
82
+ #
83
+ # @since 1.0.0
84
+ def initialize(name, options = {})
85
+ @type = options[:type] || Object
86
+ @name, @default, @label = name, options[:default], options[:label]
87
+ @copyable = (@default.is_a?(Array) || @default.is_a?(Hash))
88
+ @options = options
89
+ check_default!
90
+ end
91
+
92
+ # Used for setting an object in the attributes hash.
93
+ #
94
+ # If nil is provided the default will get returned if it exists.
95
+ #
96
+ # If the field is an identity field, ie an id, it performs the necessary
97
+ # cast.
98
+ #
99
+ # @example Get the setter value.
100
+ # field.set("New Value")
101
+ #
102
+ # @param [ Object ] object The value to cast to a database value.
103
+ #
104
+ # @return [ Object ] The typecast value.
105
+ #
106
+ # @since 1.0.0
107
+ def set(object)
108
+ unless options[:identity]
109
+ type.set(object)
110
+ else
111
+ if object.blank?
112
+ type.set(object) if object.is_a?(Array)
113
+ else
114
+ options[:metadata].constraint.convert(object)
115
+ end
116
+ end
117
+ end
118
+
119
+ # Used for retrieving the object out of the attributes hash.
120
+ #
121
+ # @example Get the value.
122
+ # field.get("Value")
123
+ #
124
+ # @param [ Object ] The object to cast from the database.
125
+ #
126
+ # @return [ Object ] The converted value.
127
+ #
128
+ # @since 1.0.0
129
+ def get(object)
130
+ type.get(object)
131
+ end
132
+
133
+ protected
134
+
135
+ # Copy the default value if copyable.
136
+ #
137
+ # @example Copy the default.
138
+ # field.copy
139
+ #
140
+ # @return [ Object ] The copied object or the original.
141
+ #
142
+ # @since 1.0.0
143
+ def copy
144
+ copyable ? @default.dup : @default
145
+ end
146
+
147
+ # Checks if the default value is of the same type as the field.
148
+ #
149
+ # @example Check the default value.
150
+ # field.check_default!
151
+ #
152
+ # @raise [ Errors::InvalidType ] If the types differ.
153
+ #
154
+ # @since 1.0.0
155
+ def check_default!
156
+ return if @default.is_a?(Proc)
157
+ if !@default.nil? && !@default.is_a?(type)
158
+ raise Mongoid::Errors::InvalidType.new(type, @default)
159
+ end
160
+ end
161
+ end
162
+ end
@@ -0,0 +1,183 @@
1
+ # encoding: utf-8
2
+ module Mongoid #:nodoc
3
+
4
+ # This module defines behaviour for fields.
5
+ module Fields
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ # Set up the class attributes that must be available to all subclasses.
10
+ # These include defaults, fields
11
+ delegate :defaults, :fields, :to => "self.class"
12
+
13
+ field(:_type, :type => String)
14
+ field(:_id, :type => BSON::ObjectId)
15
+
16
+ alias :id :_id
17
+ alias :id= :_id=
18
+ end
19
+
20
+ module ClassMethods #:nodoc
21
+
22
+ # Defines all the fields that are accessible on the Document
23
+ # For each field that is defined, a getter and setter will be
24
+ # added as an instance method to the Document.
25
+ #
26
+ # @example Define a field.
27
+ # field :score, :type => Integer, :default => 0
28
+ #
29
+ # @param [ Symbol ] name The name of the field.
30
+ # @param [ Hash ] options The options to pass to the field.
31
+ #
32
+ # @option options [ Class ] :type The type of the field.
33
+ # @option options [ String ] :label The label for the field.
34
+ # @option options [ Object, Proc ] :default The field's default
35
+ #
36
+ # @return [ Field ] The generated field
37
+ def field(name, options = {})
38
+ access = name.to_s
39
+ set_field(access, options)
40
+ end
41
+
42
+ # Return the fields for this class.
43
+ #
44
+ # @example Get the fields.
45
+ # Person.fields
46
+ #
47
+ # @return [ Hash ] The fields for this document.
48
+ #
49
+ # @since 2.0.0.rc.6
50
+ def fields
51
+ @fields ||= {}
52
+ end
53
+
54
+ # Set the fields for the class.
55
+ #
56
+ # @example Set the fields.
57
+ # Person.fields = fields
58
+ #
59
+ # @param [ Hash ] fields The hash of fields to set.
60
+ #
61
+ # @since 2.0.0.rc.6
62
+ def fields=(fields)
63
+ @fields = fields
64
+ end
65
+
66
+ # Returns the default values for the fields on the document.
67
+ #
68
+ # @example Get the defaults.
69
+ # Person.defaults
70
+ #
71
+ # @return [ Hash ] The field defaults.
72
+ def defaults
73
+ fields.inject({}) do |defs, (field_name,field)|
74
+ next(defs) if field.default.nil?
75
+ defs[field_name.to_s] = field.default
76
+ defs
77
+ end
78
+ end
79
+
80
+ # When inheriting, we want to copy the fields from the parent class and
81
+ # set the on the child to start, mimicking the behaviour of the old
82
+ # class_inheritable_accessor that was deprecated in Rails edge.
83
+ #
84
+ # @example Inherit from this class.
85
+ # Person.inherited(Doctor)
86
+ #
87
+ # @param [ Class ] subclass The inheriting class.
88
+ #
89
+ # @since 2.0.0.rc.6
90
+ def inherited(subclass)
91
+ super
92
+ subclass.fields = fields.dup
93
+ end
94
+
95
+ protected
96
+
97
+ # Define a field attribute for the +Document+.
98
+ #
99
+ # @example Set the field.
100
+ # Person.set_field(:name, :default => "Test")
101
+ #
102
+ # @param [ Symbol ] name The name of the field.
103
+ # @param [ Hash ] options The hash of options.
104
+ def set_field(name, options = {})
105
+ meth = options.delete(:as) || name
106
+ Field.new(name, options).tap do |field|
107
+ fields[name] = field
108
+ create_accessors(name, meth, options)
109
+ add_dirty_methods(name)
110
+ process_options(field)
111
+ end
112
+ end
113
+
114
+ # Run through all custom options stored in Mongoid::Field.options and
115
+ # execute the handler if the option is provided.
116
+ #
117
+ # @example
118
+ # Mongoid::Field.option :custom do
119
+ # puts "called"
120
+ # end
121
+ #
122
+ # field = Mongoid::Field.new(:test, :custom => true)
123
+ # Person.process_options(field)
124
+ # # => "called"
125
+ #
126
+ # @param [ Field ] field the field to process
127
+ def process_options(field)
128
+ options = field.options
129
+
130
+ Field.options.each do |option_name, handler|
131
+ if options.has_key?(option_name)
132
+ handler.call(self, field, options[option_name])
133
+ end
134
+ end
135
+ end
136
+
137
+ # Create the field accessors.
138
+ #
139
+ # @example Generate the accessors.
140
+ # Person.create_accessors(:name, "name")
141
+ # person.name #=> returns the field
142
+ # person.name = "" #=> sets the field
143
+ # person.name? #=> Is the field present?
144
+ #
145
+ # @param [ Symbol ] name The name of the field.
146
+ # @param [ Symbol ] meth The name of the accessor.
147
+ # @param [ Hash ] options The options.
148
+ def create_accessors(name, meth, options = {})
149
+ field = fields[name]
150
+ generated_field_methods.module_eval do
151
+ if field.cast_on_read?
152
+ define_method(meth) do
153
+ field.get(read_attribute(name))
154
+ end
155
+ else
156
+ define_method(meth) do
157
+ read_attribute(name)
158
+ end
159
+ end
160
+ define_method("#{meth}=") do |value|
161
+ write_attribute(name, value)
162
+ end
163
+ define_method("#{meth}?") do
164
+ attr = read_attribute(name)
165
+ (options[:type] == Boolean) ? attr == true : attr.present?
166
+ end
167
+ end
168
+ end
169
+
170
+ # Include the field methods as a module, so they can be overridden.
171
+ #
172
+ # @example Include the fields.
173
+ # Person.generated_field_methods
174
+ def generated_field_methods
175
+ @generated_field_methods ||= begin
176
+ Module.new.tap do |mod|
177
+ include mod
178
+ end
179
+ end
180
+ end
181
+ end
182
+ end
183
+ end