numon 0.0.1

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 (99) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +31 -0
  4. data/Rakefile +52 -0
  5. data/bin/mmconsole +60 -0
  6. data/lib/mongo_mapper.rb +138 -0
  7. data/lib/mongo_mapper/document.rb +359 -0
  8. data/lib/mongo_mapper/embedded_document.rb +61 -0
  9. data/lib/mongo_mapper/plugins.rb +34 -0
  10. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  11. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  12. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  13. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  14. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  15. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +39 -0
  16. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +144 -0
  17. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  18. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +120 -0
  19. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  20. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  21. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  22. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  23. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  24. data/lib/mongo_mapper/plugins/callbacks.rb +234 -0
  25. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  26. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  27. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  28. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  29. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  30. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  31. data/lib/mongo_mapper/plugins/keys.rb +336 -0
  32. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  33. data/lib/mongo_mapper/plugins/modifiers.rb +87 -0
  34. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  35. data/lib/mongo_mapper/plugins/pagination/proxy.rb +72 -0
  36. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  37. data/lib/mongo_mapper/plugins/rails.rb +53 -0
  38. data/lib/mongo_mapper/plugins/serialization.rb +75 -0
  39. data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
  40. data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
  41. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  42. data/lib/mongo_mapper/query.rb +130 -0
  43. data/lib/mongo_mapper/support.rb +216 -0
  44. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  45. data/lib/mongo_mapper/support/find.rb +77 -0
  46. data/lib/mongo_mapper/version.rb +3 -0
  47. data/numon.gemspec +207 -0
  48. data/performance/read_write.rb +52 -0
  49. data/specs.watchr +51 -0
  50. data/test/NOTE_ON_TESTING +1 -0
  51. data/test/active_model_lint_test.rb +11 -0
  52. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  53. data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
  54. data/test/functional/associations/test_in_array_proxy.rb +325 -0
  55. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  56. data/test/functional/associations/test_many_documents_proxy.rb +453 -0
  57. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  58. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  59. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  60. data/test/functional/associations/test_one_proxy.rb +161 -0
  61. data/test/functional/test_associations.rb +44 -0
  62. data/test/functional/test_binary.rb +27 -0
  63. data/test/functional/test_callbacks.rb +151 -0
  64. data/test/functional/test_dirty.rb +163 -0
  65. data/test/functional/test_document.rb +1165 -0
  66. data/test/functional/test_embedded_document.rb +130 -0
  67. data/test/functional/test_identity_map.rb +508 -0
  68. data/test/functional/test_indexing.rb +44 -0
  69. data/test/functional/test_logger.rb +20 -0
  70. data/test/functional/test_modifiers.rb +322 -0
  71. data/test/functional/test_pagination.rb +93 -0
  72. data/test/functional/test_protected.rb +161 -0
  73. data/test/functional/test_string_id_compatibility.rb +67 -0
  74. data/test/functional/test_timestamps.rb +64 -0
  75. data/test/functional/test_userstamps.rb +28 -0
  76. data/test/functional/test_validations.rb +329 -0
  77. data/test/models.rb +232 -0
  78. data/test/support/custom_matchers.rb +55 -0
  79. data/test/support/timing.rb +16 -0
  80. data/test/test_helper.rb +61 -0
  81. data/test/unit/associations/test_base.rb +207 -0
  82. data/test/unit/associations/test_proxy.rb +105 -0
  83. data/test/unit/serializers/test_json_serializer.rb +202 -0
  84. data/test/unit/test_descendant_appends.rb +71 -0
  85. data/test/unit/test_document.rb +231 -0
  86. data/test/unit/test_dynamic_finder.rb +123 -0
  87. data/test/unit/test_embedded_document.rb +663 -0
  88. data/test/unit/test_keys.rb +173 -0
  89. data/test/unit/test_mongo_mapper.rb +155 -0
  90. data/test/unit/test_pagination.rb +160 -0
  91. data/test/unit/test_plugins.rb +50 -0
  92. data/test/unit/test_query.rb +340 -0
  93. data/test/unit/test_rails.rb +123 -0
  94. data/test/unit/test_rails_compatibility.rb +52 -0
  95. data/test/unit/test_serialization.rb +51 -0
  96. data/test/unit/test_support.rb +366 -0
  97. data/test/unit/test_time_zones.rb +39 -0
  98. data/test/unit/test_validations.rb +544 -0
  99. metadata +305 -0
@@ -0,0 +1,144 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class InArrayProxy < Collection
5
+ include Support::Find
6
+
7
+ def find(*args)
8
+ options = args.extract_options!
9
+
10
+ case args.first
11
+ when :first
12
+ first(options)
13
+ when :last
14
+ last(options)
15
+ when :all
16
+ all(options)
17
+ else
18
+ klass.find(*scoped_ids(args) << scoped_options(options))
19
+ end
20
+ end
21
+
22
+ def find!(*args)
23
+ options = args.extract_options!
24
+
25
+ case args.first
26
+ when :first
27
+ first(options)
28
+ when :last
29
+ last(options)
30
+ when :all
31
+ all(options)
32
+ else
33
+ klass.find!(*scoped_ids(args) << scoped_options(options))
34
+ end
35
+ end
36
+
37
+ def paginate(options)
38
+ klass.paginate(scoped_options(options))
39
+ end
40
+
41
+ def all(options={})
42
+ klass.all(scoped_options(options))
43
+ end
44
+
45
+ def first(options={})
46
+ klass.first(scoped_options(options))
47
+ end
48
+
49
+ def last(options={})
50
+ klass.last(scoped_options(options))
51
+ end
52
+
53
+ def count(options={})
54
+ options.blank? ? ids.size : klass.count(scoped_options(options))
55
+ end
56
+
57
+ def destroy_all(options={})
58
+ all(options).each do |doc|
59
+ ids.delete(doc.id)
60
+ doc.destroy
61
+ end
62
+ reset
63
+ end
64
+
65
+ def delete_all(options={})
66
+ docs = all(options.merge(:select => ['_id']))
67
+ docs.each { |doc| ids.delete(doc.id) }
68
+ klass.delete(docs.map(&:id))
69
+ reset
70
+ end
71
+
72
+ def nullify
73
+ replace([])
74
+ reset
75
+ end
76
+
77
+ def create(attrs={})
78
+ doc = klass.create(attrs)
79
+ unless doc.new?
80
+ ids << doc.id
81
+ owner.save
82
+ reset
83
+ end
84
+ doc
85
+ end
86
+
87
+ def create!(attrs={})
88
+ doc = klass.create!(attrs)
89
+ unless doc.new?
90
+ ids << doc.id
91
+ owner.save
92
+ reset
93
+ end
94
+ doc
95
+ end
96
+
97
+ def <<(*docs)
98
+ flatten_deeper(docs).each do |doc|
99
+ doc.save if doc.new?
100
+ unless ids.include?(doc.id)
101
+ ids << doc.id
102
+ end
103
+ end
104
+ reset
105
+ end
106
+ alias_method :push, :<<
107
+ alias_method :concat, :<<
108
+
109
+ def replace(docs)
110
+ doc_ids = docs.map do |doc|
111
+ doc.save if doc.new?
112
+ doc.id
113
+ end
114
+ ids.replace(doc_ids.uniq)
115
+ reset
116
+ end
117
+
118
+ private
119
+ def scoped_conditions
120
+ {:_id => ids}
121
+ end
122
+
123
+ def scoped_options(options)
124
+ association.query_options.merge(options).merge(scoped_conditions)
125
+ end
126
+
127
+ def scoped_ids(args)
128
+ args.flatten.select do |id|
129
+ id = ObjectId.to_mongo(id) if klass.using_object_id?
130
+ ids.include?(id)
131
+ end
132
+ end
133
+
134
+ def find_target
135
+ ids.blank? ? [] : all
136
+ end
137
+
138
+ def ids
139
+ owner[options[:in]]
140
+ end
141
+ end
142
+ end
143
+ end
144
+ end
@@ -0,0 +1,28 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyDocumentsAsProxy < ManyDocumentsProxy
5
+ protected
6
+ def scoped_conditions
7
+ {type_key_name => owner.class.name, id_key_name => owner.id}
8
+ end
9
+
10
+ def apply_scope(doc)
11
+ ensure_owner_saved
12
+ doc[type_key_name] = owner.class.name
13
+ doc[id_key_name] = owner.id
14
+ doc
15
+ end
16
+
17
+ private
18
+ def type_key_name
19
+ "#{options[:as]}_type"
20
+ end
21
+
22
+ def id_key_name
23
+ "#{options[:as]}_id"
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,120 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyDocumentsProxy < Collection
5
+ include Support::Find
6
+
7
+ def find(*args)
8
+ options = args.extract_options!
9
+ klass.find(*args << scoped_options(options))
10
+ end
11
+
12
+ def find!(*args)
13
+ options = args.extract_options!
14
+ klass.find!(*args << scoped_options(options))
15
+ end
16
+
17
+ def paginate(options)
18
+ klass.paginate(scoped_options(options))
19
+ end
20
+
21
+ def all(options={})
22
+ klass.all(scoped_options(options))
23
+ end
24
+
25
+ def first(options={})
26
+ klass.first(scoped_options(options))
27
+ end
28
+
29
+ def last(options={})
30
+ klass.last(scoped_options(options))
31
+ end
32
+
33
+ def count(options={})
34
+ klass.count(scoped_options(options))
35
+ end
36
+
37
+ def replace(docs)
38
+ load_target
39
+ target.map(&:destroy)
40
+ docs.each { |doc| apply_scope(doc).save }
41
+ reset
42
+ end
43
+
44
+ def <<(*docs)
45
+ ensure_owner_saved
46
+ flatten_deeper(docs).each { |doc| apply_scope(doc).save }
47
+ reset
48
+ end
49
+ alias_method :push, :<<
50
+ alias_method :concat, :<<
51
+
52
+ def build(attrs={})
53
+ doc = klass.new(attrs)
54
+ apply_scope(doc)
55
+ reset
56
+ doc
57
+ end
58
+
59
+ def create(attrs={})
60
+ doc = klass.new(attrs)
61
+ apply_scope(doc).save
62
+ reset
63
+ doc
64
+ end
65
+
66
+ def create!(attrs={})
67
+ doc = klass.new(attrs)
68
+ apply_scope(doc).save!
69
+ reset
70
+ doc
71
+ end
72
+
73
+ def destroy_all(options={})
74
+ all(options).map(&:destroy)
75
+ reset
76
+ end
77
+
78
+ def delete_all(options={})
79
+ klass.delete_all(options.merge(scoped_conditions))
80
+ reset
81
+ end
82
+
83
+ def nullify
84
+ criteria = Query.new(klass, scoped_conditions).criteria
85
+ all(criteria).each do |doc|
86
+ doc.update_attributes(self.foreign_key => nil)
87
+ end
88
+ reset
89
+ end
90
+
91
+ protected
92
+ def scoped_conditions
93
+ {self.foreign_key => owner.id}
94
+ end
95
+
96
+ def scoped_options(options)
97
+ association.query_options.merge(options).merge(scoped_conditions)
98
+ end
99
+
100
+ def find_target
101
+ all
102
+ end
103
+
104
+ def ensure_owner_saved
105
+ owner.save if owner.new?
106
+ end
107
+
108
+ def apply_scope(doc)
109
+ ensure_owner_saved
110
+ doc[foreign_key] = owner.id
111
+ doc
112
+ end
113
+
114
+ def foreign_key
115
+ options[:foreign_key] || owner.class.name.to_s.underscore.gsub("/", "_") + "_id"
116
+ end
117
+ end
118
+ end
119
+ end
120
+ end
@@ -0,0 +1,31 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyEmbeddedPolymorphicProxy < EmbeddedCollection
5
+ def replace(values)
6
+ @_values = values.map do |v|
7
+ v.respond_to?(:attributes) ? v.attributes.merge(association.type_key_name => v.class.name) : v
8
+ end
9
+ reset
10
+ end
11
+
12
+ protected
13
+ def find_target
14
+ (@_values || []).map do |hash|
15
+ child = polymorphic_class(hash).load(hash)
16
+ assign_references(child)
17
+ child
18
+ end
19
+ end
20
+
21
+ def polymorphic_class(doc)
22
+ if class_name = doc[association.type_key_name]
23
+ class_name.constantize
24
+ else
25
+ klass
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyEmbeddedProxy < EmbeddedCollection
5
+ def replace(values)
6
+ @_values = values.map do |v|
7
+ v.respond_to?(:attributes) ? v.attributes : v
8
+ end
9
+ reset
10
+ end
11
+
12
+ private
13
+ def find_target
14
+ (@_values || []).map do |v|
15
+ child = klass.load(v)
16
+ assign_references(child)
17
+ child
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,13 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class ManyPolymorphicProxy < ManyDocumentsProxy
5
+ private
6
+ def apply_scope(doc)
7
+ doc[association.type_key_name] = doc.class.name
8
+ super
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,68 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class OneProxy < Proxy
5
+ undef_method :object_id
6
+
7
+ def build(attrs={})
8
+ instantiate_target(:new, attrs)
9
+ end
10
+
11
+ def create(attrs={})
12
+ instantiate_target(:create, attrs)
13
+ end
14
+
15
+ def create!(attrs={})
16
+ instantiate_target(:create!, attrs)
17
+ end
18
+
19
+ def replace(doc)
20
+ load_target
21
+
22
+ if !target.nil? && target != doc
23
+ if options[:dependent] && !target.new?
24
+ case options[:dependent]
25
+ when :delete
26
+ target.delete
27
+ when :destroy
28
+ target.destroy
29
+ when :nullify
30
+ target[foreign_key] = nil
31
+ target.save
32
+ end
33
+ end
34
+ end
35
+
36
+ reset
37
+
38
+ unless doc.nil?
39
+ owner.save if owner.new?
40
+ doc[foreign_key] = owner.id
41
+ doc.save if doc.new?
42
+ loaded
43
+ @target = doc
44
+ end
45
+ end
46
+
47
+ protected
48
+ def find_target
49
+ target_class.first(association.query_options.merge(foreign_key => owner.id))
50
+ end
51
+
52
+ def instantiate_target(instantiator, attrs={})
53
+ @target = target_class.send(instantiator, attrs.update(foreign_key => owner.id))
54
+ loaded
55
+ @target
56
+ end
57
+
58
+ def target_class
59
+ @target_class ||= options[:class] || (options[:class_name] || association.name.to_s.camelize).constantize
60
+ end
61
+
62
+ def foreign_key
63
+ options[:foreign_key] || owner.class.name.foreign_key
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,118 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Associations
4
+ class Proxy
5
+ alias :proxy_respond_to? :respond_to?
6
+ alias :proxy_extend :extend
7
+
8
+ instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|proxy_|^object_id$)/ }
9
+
10
+ attr_reader :owner, :association, :target
11
+
12
+ alias :proxy_owner :owner
13
+ alias :proxy_target :target
14
+ alias :proxy_association :association
15
+
16
+ delegate :klass, :to => :proxy_association
17
+ delegate :options, :to => :proxy_association
18
+ delegate :collection, :to => :klass
19
+
20
+ def initialize(owner, association)
21
+ @owner, @association, @loaded = owner, association, false
22
+ Array(association.options[:extend]).each { |ext| proxy_extend(ext) }
23
+ reset
24
+ end
25
+
26
+ def inspect
27
+ load_target
28
+ target.inspect
29
+ end
30
+
31
+ def loaded?
32
+ @loaded
33
+ end
34
+
35
+ def loaded
36
+ @loaded = true
37
+ end
38
+
39
+ def nil?
40
+ load_target
41
+ target.nil?
42
+ end
43
+
44
+ def blank?
45
+ load_target
46
+ target.blank?
47
+ end
48
+
49
+ def present?
50
+ load_target
51
+ target.present?
52
+ end
53
+
54
+ def reload
55
+ reset
56
+ load_target
57
+ self unless target.nil?
58
+ end
59
+
60
+ def replace(v)
61
+ raise NotImplementedError
62
+ end
63
+
64
+ def reset
65
+ @loaded = false
66
+ @target = nil
67
+ end
68
+
69
+ def respond_to?(*args)
70
+ proxy_respond_to?(*args) || (load_target && target.respond_to?(*args))
71
+ end
72
+
73
+ def send(method, *args)
74
+ if proxy_respond_to?(method)
75
+ super
76
+ else
77
+ load_target
78
+ target.send(method, *args)
79
+ end
80
+ end
81
+
82
+ def ===(other)
83
+ load_target
84
+ other === target
85
+ end
86
+
87
+ protected
88
+ def method_missing(method, *args, &block)
89
+ if load_target
90
+ if block_given?
91
+ target.send(method, *args) { |*block_args| block.call(*block_args) }
92
+ else
93
+ target.send(method, *args)
94
+ end
95
+ end
96
+ end
97
+
98
+ def load_target
99
+ @target = find_target unless loaded?
100
+ loaded
101
+ @target
102
+ rescue MongoMapper::DocumentNotFound
103
+ reset
104
+ end
105
+
106
+ def find_target
107
+ raise NotImplementedError
108
+ end
109
+
110
+ def flatten_deeper(array)
111
+ array.collect do |element|
112
+ (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element
113
+ end.flatten
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end