lookout-mongo_mapper 0.11.3

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 (176) hide show
  1. data/LICENSE +20 -0
  2. data/README.rdoc +33 -0
  3. data/UPGRADES +26 -0
  4. data/bin/mmconsole +59 -0
  5. data/examples/attr_accessible.rb +22 -0
  6. data/examples/attr_protected.rb +22 -0
  7. data/examples/cache_key.rb +24 -0
  8. data/examples/custom_types.rb +24 -0
  9. data/examples/identity_map.rb +33 -0
  10. data/examples/identity_map/automatic.rb +2 -0
  11. data/examples/keys.rb +40 -0
  12. data/examples/modifiers/set.rb +25 -0
  13. data/examples/plugins.rb +38 -0
  14. data/examples/querying.rb +35 -0
  15. data/examples/safe.rb +43 -0
  16. data/examples/scopes.rb +52 -0
  17. data/examples/validating/embedded_docs.rb +29 -0
  18. data/lib/mongo_mapper.rb +94 -0
  19. data/lib/mongo_mapper/connection.rb +96 -0
  20. data/lib/mongo_mapper/document.rb +42 -0
  21. data/lib/mongo_mapper/embedded_document.rb +32 -0
  22. data/lib/mongo_mapper/exceptions.rb +30 -0
  23. data/lib/mongo_mapper/extensions/array.rb +19 -0
  24. data/lib/mongo_mapper/extensions/binary.rb +22 -0
  25. data/lib/mongo_mapper/extensions/boolean.rb +44 -0
  26. data/lib/mongo_mapper/extensions/date.rb +25 -0
  27. data/lib/mongo_mapper/extensions/float.rb +14 -0
  28. data/lib/mongo_mapper/extensions/hash.rb +14 -0
  29. data/lib/mongo_mapper/extensions/integer.rb +19 -0
  30. data/lib/mongo_mapper/extensions/kernel.rb +9 -0
  31. data/lib/mongo_mapper/extensions/nil_class.rb +18 -0
  32. data/lib/mongo_mapper/extensions/object.rb +26 -0
  33. data/lib/mongo_mapper/extensions/object_id.rb +32 -0
  34. data/lib/mongo_mapper/extensions/set.rb +20 -0
  35. data/lib/mongo_mapper/extensions/string.rb +18 -0
  36. data/lib/mongo_mapper/extensions/time.rb +28 -0
  37. data/lib/mongo_mapper/locale/en.yml +5 -0
  38. data/lib/mongo_mapper/middleware/identity_map.rb +16 -0
  39. data/lib/mongo_mapper/plugins.rb +22 -0
  40. data/lib/mongo_mapper/plugins/accessible.rb +52 -0
  41. data/lib/mongo_mapper/plugins/active_model.rb +18 -0
  42. data/lib/mongo_mapper/plugins/associations.rb +90 -0
  43. data/lib/mongo_mapper/plugins/associations/base.rb +92 -0
  44. data/lib/mongo_mapper/plugins/associations/belongs_to_association.rb +54 -0
  45. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +34 -0
  46. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +52 -0
  47. data/lib/mongo_mapper/plugins/associations/collection.rb +27 -0
  48. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +44 -0
  49. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +133 -0
  50. data/lib/mongo_mapper/plugins/associations/many_association.rb +63 -0
  51. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  52. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +118 -0
  53. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +32 -0
  54. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +24 -0
  55. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +14 -0
  56. data/lib/mongo_mapper/plugins/associations/one_as_proxy.rb +22 -0
  57. data/lib/mongo_mapper/plugins/associations/one_association.rb +48 -0
  58. data/lib/mongo_mapper/plugins/associations/one_embedded_polymorphic_proxy.rb +30 -0
  59. data/lib/mongo_mapper/plugins/associations/one_embedded_proxy.rb +44 -0
  60. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +95 -0
  61. data/lib/mongo_mapper/plugins/associations/proxy.rb +134 -0
  62. data/lib/mongo_mapper/plugins/associations/single_association.rb +46 -0
  63. data/lib/mongo_mapper/plugins/caching.rb +21 -0
  64. data/lib/mongo_mapper/plugins/callbacks.rb +29 -0
  65. data/lib/mongo_mapper/plugins/clone.rb +22 -0
  66. data/lib/mongo_mapper/plugins/dirty.rb +60 -0
  67. data/lib/mongo_mapper/plugins/document.rb +41 -0
  68. data/lib/mongo_mapper/plugins/dynamic_querying.rb +45 -0
  69. data/lib/mongo_mapper/plugins/dynamic_querying/dynamic_finder.rb +44 -0
  70. data/lib/mongo_mapper/plugins/embedded_callbacks.rb +56 -0
  71. data/lib/mongo_mapper/plugins/embedded_document.rb +53 -0
  72. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  73. data/lib/mongo_mapper/plugins/identity_map.rb +128 -0
  74. data/lib/mongo_mapper/plugins/indexes.rb +13 -0
  75. data/lib/mongo_mapper/plugins/inspect.rb +16 -0
  76. data/lib/mongo_mapper/plugins/keys.rb +313 -0
  77. data/lib/mongo_mapper/plugins/keys/key.rb +61 -0
  78. data/lib/mongo_mapper/plugins/logger.rb +18 -0
  79. data/lib/mongo_mapper/plugins/modifiers.rb +134 -0
  80. data/lib/mongo_mapper/plugins/pagination.rb +16 -0
  81. data/lib/mongo_mapper/plugins/persistence.rb +69 -0
  82. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  83. data/lib/mongo_mapper/plugins/querying.rb +165 -0
  84. data/lib/mongo_mapper/plugins/querying/decorator.rb +36 -0
  85. data/lib/mongo_mapper/plugins/rails.rb +58 -0
  86. data/lib/mongo_mapper/plugins/rails/active_record_association_adapter.rb +33 -0
  87. data/lib/mongo_mapper/plugins/safe.rb +28 -0
  88. data/lib/mongo_mapper/plugins/sci.rb +36 -0
  89. data/lib/mongo_mapper/plugins/scopes.rb +27 -0
  90. data/lib/mongo_mapper/plugins/serialization.rb +109 -0
  91. data/lib/mongo_mapper/plugins/timestamps.rb +22 -0
  92. data/lib/mongo_mapper/plugins/touch.rb +18 -0
  93. data/lib/mongo_mapper/plugins/userstamps.rb +18 -0
  94. data/lib/mongo_mapper/plugins/validations.rb +86 -0
  95. data/lib/mongo_mapper/railtie.rb +48 -0
  96. data/lib/mongo_mapper/railtie/database.rake +65 -0
  97. data/lib/mongo_mapper/translation.rb +10 -0
  98. data/lib/mongo_mapper/version.rb +4 -0
  99. data/lib/rails/generators/mongo_mapper/config/config_generator.rb +24 -0
  100. data/lib/rails/generators/mongo_mapper/config/templates/mongo.yml +18 -0
  101. data/lib/rails/generators/mongo_mapper/model/model_generator.rb +23 -0
  102. data/lib/rails/generators/mongo_mapper/model/templates/model.rb +13 -0
  103. data/test/_NOTE_ON_TESTING +1 -0
  104. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +64 -0
  105. data/test/functional/associations/test_belongs_to_proxy.rb +238 -0
  106. data/test/functional/associations/test_in_array_proxy.rb +349 -0
  107. data/test/functional/associations/test_many_documents_as_proxy.rb +231 -0
  108. data/test/functional/associations/test_many_documents_proxy.rb +866 -0
  109. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +239 -0
  110. data/test/functional/associations/test_many_embedded_proxy.rb +289 -0
  111. data/test/functional/associations/test_many_polymorphic_proxy.rb +303 -0
  112. data/test/functional/associations/test_one_as_proxy.rb +491 -0
  113. data/test/functional/associations/test_one_embedded_polymorphic_proxy.rb +208 -0
  114. data/test/functional/associations/test_one_embedded_proxy.rb +100 -0
  115. data/test/functional/associations/test_one_proxy.rb +383 -0
  116. data/test/functional/test_accessible.rb +198 -0
  117. data/test/functional/test_associations.rb +46 -0
  118. data/test/functional/test_binary.rb +27 -0
  119. data/test/functional/test_caching.rb +77 -0
  120. data/test/functional/test_callbacks.rb +232 -0
  121. data/test/functional/test_dirty.rb +301 -0
  122. data/test/functional/test_document.rb +282 -0
  123. data/test/functional/test_dynamic_querying.rb +75 -0
  124. data/test/functional/test_embedded_document.rb +288 -0
  125. data/test/functional/test_equality.rb +20 -0
  126. data/test/functional/test_identity_map.rb +513 -0
  127. data/test/functional/test_indexes.rb +50 -0
  128. data/test/functional/test_logger.rb +20 -0
  129. data/test/functional/test_modifiers.rb +537 -0
  130. data/test/functional/test_pagination.rb +91 -0
  131. data/test/functional/test_protected.rb +201 -0
  132. data/test/functional/test_querying.rb +935 -0
  133. data/test/functional/test_safe.rb +76 -0
  134. data/test/functional/test_sci.rb +240 -0
  135. data/test/functional/test_scopes.rb +171 -0
  136. data/test/functional/test_timestamps.rb +62 -0
  137. data/test/functional/test_touch.rb +125 -0
  138. data/test/functional/test_userstamps.rb +44 -0
  139. data/test/functional/test_validations.rb +414 -0
  140. data/test/models.rb +261 -0
  141. data/test/support/railtie.rb +4 -0
  142. data/test/support/railtie/autoloaded.rb +2 -0
  143. data/test/support/railtie/not_autoloaded.rb +3 -0
  144. data/test/support/railtie/parent.rb +3 -0
  145. data/test/test_active_model_lint.rb +18 -0
  146. data/test/test_helper.rb +93 -0
  147. data/test/unit/associations/test_base.rb +146 -0
  148. data/test/unit/associations/test_belongs_to_association.rb +29 -0
  149. data/test/unit/associations/test_many_association.rb +63 -0
  150. data/test/unit/associations/test_one_association.rb +47 -0
  151. data/test/unit/associations/test_proxy.rb +100 -0
  152. data/test/unit/serializers/test_json_serializer.rb +216 -0
  153. data/test/unit/serializers/test_xml_serializer.rb +196 -0
  154. data/test/unit/test_clone.rb +69 -0
  155. data/test/unit/test_document.rb +249 -0
  156. data/test/unit/test_dynamic_finder.rb +125 -0
  157. data/test/unit/test_embedded_document.rb +682 -0
  158. data/test/unit/test_equality.rb +38 -0
  159. data/test/unit/test_exceptions.rb +12 -0
  160. data/test/unit/test_extensions.rb +380 -0
  161. data/test/unit/test_identity_map_middleware.rb +34 -0
  162. data/test/unit/test_inspect.rb +47 -0
  163. data/test/unit/test_key.rb +205 -0
  164. data/test/unit/test_keys.rb +65 -0
  165. data/test/unit/test_mongo_mapper.rb +143 -0
  166. data/test/unit/test_pagination.rb +11 -0
  167. data/test/unit/test_plugins.rb +89 -0
  168. data/test/unit/test_rails.rb +183 -0
  169. data/test/unit/test_rails_compatibility.rb +38 -0
  170. data/test/unit/test_rails_reflect_on_association.rb +118 -0
  171. data/test/unit/test_railtie.rb +66 -0
  172. data/test/unit/test_serialization.rb +166 -0
  173. data/test/unit/test_time_zones.rb +44 -0
  174. data/test/unit/test_translation.rb +27 -0
  175. data/test/unit/test_validations.rb +562 -0
  176. metadata +285 -0
@@ -0,0 +1,25 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module Date
5
+ def to_mongo(value)
6
+ if value.nil? || value == ''
7
+ nil
8
+ else
9
+ date = value.is_a?(::Date) || value.is_a?(::Time) ? value : ::Date.parse(value.to_s)
10
+ ::Time.utc(date.year, date.month, date.day)
11
+ end
12
+ rescue
13
+ nil
14
+ end
15
+
16
+ def from_mongo(value)
17
+ value.to_date if value.present?
18
+ end
19
+ end
20
+ end
21
+ end
22
+
23
+ class Date
24
+ extend MongoMapper::Extensions::Date
25
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module Float
5
+ def to_mongo(value)
6
+ value.blank? ? nil : value.to_f
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ class Float
13
+ extend MongoMapper::Extensions::Float
14
+ end
@@ -0,0 +1,14 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module Hash
5
+ def from_mongo(value)
6
+ HashWithIndifferentAccess.new(value || {})
7
+ end
8
+ end
9
+ end
10
+ end
11
+
12
+ class Hash
13
+ extend MongoMapper::Extensions::Hash
14
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module Integer
5
+ def to_mongo(value)
6
+ value_to_i = value.to_i
7
+ if value_to_i == 0 && value != value_to_i
8
+ value.to_s =~ /^(0x|0b)?0+/ ? 0 : nil
9
+ else
10
+ value_to_i
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end
16
+
17
+ class Integer
18
+ extend MongoMapper::Extensions::Integer
19
+ end
@@ -0,0 +1,9 @@
1
+ # encoding: UTF-8
2
+ module Kernel
3
+ # Returns the object's singleton class.
4
+ def singleton_class
5
+ class << self
6
+ self
7
+ end
8
+ end unless respond_to?(:singleton_class) # exists in 1.9.2
9
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module NilClass
5
+ def to_mongo(value)
6
+ value
7
+ end
8
+
9
+ def from_mongo(value)
10
+ value
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class NilClass
17
+ include MongoMapper::Extensions::NilClass
18
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module Object
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def to_mongo(value)
9
+ value
10
+ end
11
+
12
+ def from_mongo(value)
13
+ value
14
+ end
15
+ end
16
+
17
+ def to_mongo
18
+ self.class.to_mongo(self)
19
+ end
20
+ end
21
+ end
22
+ end
23
+
24
+ class Object
25
+ include MongoMapper::Extensions::Object
26
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module ObjectId
5
+ def to_mongo(value)
6
+ Plucky.to_object_id(value)
7
+ end
8
+
9
+ def from_mongo(value)
10
+ value
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class ObjectId
17
+ extend MongoMapper::Extensions::ObjectId
18
+ end
19
+
20
+ class BSON::ObjectId
21
+ alias_method :original_to_json, :to_json
22
+
23
+ def as_json(options=nil)
24
+ to_s
25
+ end
26
+
27
+ def to_json(options = nil)
28
+ as_json.to_json
29
+ end
30
+
31
+ alias to_str to_s
32
+ end
@@ -0,0 +1,20 @@
1
+ # encoding: UTF-8
2
+ require 'set'
3
+
4
+ module MongoMapper
5
+ module Extensions
6
+ module Set
7
+ def to_mongo(value)
8
+ value.to_a
9
+ end
10
+
11
+ def from_mongo(value)
12
+ (value || []).to_set
13
+ end
14
+ end
15
+ end
16
+ end
17
+
18
+ class Set
19
+ extend MongoMapper::Extensions::Set
20
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module String
5
+ def to_mongo(value)
6
+ value.nil? ? nil : value.to_s
7
+ end
8
+
9
+ def from_mongo(value)
10
+ value.nil? ? nil : value.to_s
11
+ end
12
+ end
13
+ end
14
+ end
15
+
16
+ class String
17
+ extend MongoMapper::Extensions::String
18
+ end
@@ -0,0 +1,28 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Extensions
4
+ module Time
5
+ def to_mongo(value)
6
+ if value.nil? || value == ''
7
+ nil
8
+ else
9
+ time_class = ::Time.try(:zone).present? ? ::Time.zone : ::Time
10
+ time = value.is_a?(::Time) ? value : time_class.parse(value.to_s)
11
+ at(time.to_f).utc if time # ensure milliseconds are preserved with to_f (issue #308)
12
+ end
13
+ end
14
+
15
+ def from_mongo(value)
16
+ if ::Time.try(:zone).present? && value.present?
17
+ value.in_time_zone(::Time.zone)
18
+ else
19
+ value
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+
26
+ class Time
27
+ extend MongoMapper::Extensions::Time
28
+ end
@@ -0,0 +1,5 @@
1
+ en:
2
+ mongo_mapper:
3
+ errors:
4
+ messages:
5
+ taken: "has already been taken"
@@ -0,0 +1,16 @@
1
+ module MongoMapper
2
+ module Middleware
3
+ class IdentityMap
4
+ def initialize(app)
5
+ @app = app
6
+ end
7
+
8
+ def call(env)
9
+ MongoMapper::Plugins::IdentityMap.clear
10
+ @app.call(env)
11
+ ensure
12
+ MongoMapper::Plugins::IdentityMap.clear
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ include ActiveSupport::DescendantsTracker
5
+
6
+ def plugins
7
+ @plugins ||= []
8
+ end
9
+
10
+ def plugin(mod)
11
+ raise ArgumentError, "Plugins must extend ActiveSupport::Concern" unless ActiveSupport::Concern === mod
12
+ include mod
13
+ direct_descendants.each {|model| model.send(:include, mod) }
14
+ plugins << mod
15
+ end
16
+
17
+ def included(base = nil, &block)
18
+ direct_descendants << base if base
19
+ super
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,52 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Accessible
4
+ extend ActiveSupport::Concern
5
+
6
+ included do
7
+ class_attribute :_accessible_attributes
8
+ end
9
+
10
+ module ClassMethods
11
+ def attr_accessible(*attrs)
12
+ raise AccessibleOrProtected.new(name) if try(:protected_attributes?)
13
+ self._accessible_attributes = Set.new(attrs) + (_accessible_attributes || [])
14
+ end
15
+
16
+ def accessible_attributes(*)
17
+ _accessible_attributes
18
+ end
19
+
20
+ def accessible_attributes?
21
+ _accessible_attributes?
22
+ end
23
+ end
24
+
25
+ def attributes=(attrs={})
26
+ super(filter_inaccessible_attrs(attrs))
27
+ end
28
+
29
+ def update_attributes(attrs={})
30
+ super(filter_inaccessible_attrs(attrs))
31
+ end
32
+
33
+ def update_attributes!(attrs={})
34
+ super(filter_inaccessible_attrs(attrs))
35
+ end
36
+
37
+ def accessible_attributes(*args)
38
+ self.class.accessible_attributes(*args)
39
+ end
40
+
41
+ def accessible_attributes?
42
+ self.class.accessible_attributes?
43
+ end
44
+
45
+ protected
46
+ def filter_inaccessible_attrs(attrs)
47
+ return attrs if !accessible_attributes? || attrs.blank?
48
+ attrs.dup.delete_if { |key, val| !accessible_attributes.include?(key.to_sym) }
49
+ end
50
+ end
51
+ end
52
+ end
@@ -0,0 +1,18 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module ActiveModel
5
+ extend ActiveSupport::Concern
6
+
7
+ include ::ActiveModel::Conversion
8
+ include ::ActiveModel::Serialization
9
+ include ::ActiveModel::Serializers::Xml
10
+ include ::ActiveModel::Serializers::JSON
11
+
12
+ included do
13
+ extend ::ActiveModel::Naming
14
+ extend ::ActiveModel::Translation
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,90 @@
1
+ # encoding: UTF-8
2
+ module MongoMapper
3
+ module Plugins
4
+ module Associations
5
+ extend ActiveSupport::Concern
6
+
7
+ module ClassMethods
8
+ def inherited(subclass)
9
+ subclass.associations = associations.dup
10
+ super
11
+ end
12
+
13
+ def belongs_to(association_id, options={}, &extension)
14
+ create_association(BelongsToAssociation.new(association_id, options, &extension))
15
+ end
16
+
17
+ def many(association_id, options={}, &extension)
18
+ create_association(ManyAssociation.new(association_id, options, &extension))
19
+ end
20
+
21
+ def one(association_id, options={}, &extension)
22
+ create_association(OneAssociation.new(association_id, options, &extension))
23
+ end
24
+
25
+ def associations
26
+ @associations ||= {}
27
+ end
28
+
29
+ def associations=(hash)
30
+ @associations = hash
31
+ end
32
+
33
+ def associations_module_defined?
34
+ if method(:const_defined?).arity == 1 # Ruby 1.9 compat check
35
+ const_defined?('MongoMapperAssociations')
36
+ else
37
+ const_defined?('MongoMapperAssociations', false)
38
+ end
39
+ end
40
+
41
+ def associations_module
42
+ if associations_module_defined?
43
+ const_get 'MongoMapperAssociations'
44
+ else
45
+ Module.new.tap do |m|
46
+ const_set 'MongoMapperAssociations', m
47
+ include m
48
+ end
49
+ end
50
+ end
51
+
52
+ private
53
+ def create_association(association)
54
+ associations[association.name] = association
55
+ association.setup(self)
56
+ end
57
+ end
58
+
59
+ def associations
60
+ self.class.associations
61
+ end
62
+
63
+ def embedded_associations
64
+ associations.values.select { |assoc| assoc.embeddable? }
65
+ end
66
+
67
+ def build_proxy(association)
68
+ proxy = association.proxy_class.new(self, association)
69
+ self.instance_variable_set(association.ivar, proxy)
70
+
71
+ proxy
72
+ end
73
+
74
+ def get_proxy(association)
75
+ unless proxy = self.instance_variable_get(association.ivar)
76
+ proxy = build_proxy(association)
77
+ end
78
+ proxy
79
+ end
80
+
81
+ def save_to_collection(options={})
82
+ super if defined?(super)
83
+ associations.each do |association_name, association|
84
+ proxy = get_proxy(association)
85
+ proxy.save_to_collection(options) if proxy.proxy_respond_to?(:save_to_collection) && association.autosave?
86
+ end
87
+ end
88
+ end
89
+ end
90
+ end