djsun-mongomapper 0.3.5.5 → 0.4.1.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/README.rdoc +38 -38
  2. data/Rakefile +87 -73
  3. data/VERSION +1 -1
  4. data/lib/mongomapper.rb +67 -71
  5. data/lib/mongomapper/associations.rb +86 -84
  6. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -34
  7. data/lib/mongomapper/associations/many_embedded_proxy.rb +67 -17
  8. data/lib/mongomapper/associations/proxy.rb +74 -73
  9. data/lib/mongomapper/document.rb +342 -348
  10. data/lib/mongomapper/embedded_document.rb +354 -274
  11. data/lib/mongomapper/finder_options.rb +84 -84
  12. data/lib/mongomapper/key.rb +32 -76
  13. data/lib/mongomapper/rails_compatibility/document.rb +14 -14
  14. data/lib/mongomapper/rails_compatibility/embedded_document.rb +26 -24
  15. data/lib/mongomapper/support.rb +156 -29
  16. data/lib/mongomapper/validations.rb +69 -47
  17. data/test/custom_matchers.rb +48 -0
  18. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -56
  19. data/test/functional/associations/test_belongs_to_proxy.rb +48 -49
  20. data/test/functional/associations/test_many_documents_as_proxy.rb +208 -253
  21. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +130 -130
  22. data/test/functional/associations/test_many_embedded_proxy.rb +168 -106
  23. data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -262
  24. data/test/functional/test_binary.rb +21 -0
  25. data/test/functional/test_document.rb +946 -952
  26. data/test/functional/test_embedded_document.rb +98 -0
  27. data/test/functional/test_pagination.rb +87 -80
  28. data/test/functional/test_rails_compatibility.rb +29 -29
  29. data/test/functional/test_validations.rb +262 -172
  30. data/test/models.rb +169 -169
  31. data/test/test_helper.rb +28 -66
  32. data/test/unit/serializers/test_json_serializer.rb +193 -193
  33. data/test/unit/test_document.rb +161 -123
  34. data/test/unit/test_embedded_document.rb +643 -547
  35. data/test/unit/test_finder_options.rb +183 -183
  36. data/test/unit/test_key.rb +175 -247
  37. data/test/unit/test_rails_compatibility.rb +38 -33
  38. data/test/unit/test_serializations.rb +52 -52
  39. data/test/unit/test_support.rb +268 -0
  40. data/test/unit/test_time_zones.rb +40 -0
  41. data/test/unit/test_validations.rb +499 -258
  42. metadata +22 -12
  43. data/History +0 -76
  44. data/mongomapper.gemspec +0 -145
@@ -1,85 +1,85 @@
1
- module MongoMapper
2
- class FinderOptions
3
- attr_reader :options
4
-
5
- def self.to_mongo_criteria(conditions, parent_key=nil)
6
- criteria = {}
7
- conditions.each_pair do |field, value|
8
- case value
9
- when Array
10
- operator_present = field.to_s =~ /^\$/
11
- criteria[field] = if operator_present
12
- value
13
- else
14
- {'$in' => value}
15
- end
16
- when Hash
17
- criteria[field] = to_mongo_criteria(value, field)
18
- else
19
- criteria[field] = value
20
- end
21
- end
22
-
23
- criteria
24
- end
25
-
26
- def self.to_mongo_options(options)
27
- options = options.dup
28
- {
29
- :fields => to_mongo_fields(options.delete(:fields) || options.delete(:select)),
30
- :offset => (options.delete(:offset) || 0).to_i,
31
- :limit => (options.delete(:limit) || 0).to_i,
32
- :sort => options.delete(:sort) || to_mongo_sort(options.delete(:order))
33
- }
34
- end
35
-
36
- def initialize(options)
37
- raise ArgumentError, "FinderOptions must be a hash" unless options.is_a?(Hash)
38
- @options = options.symbolize_keys
39
- @conditions = @options.delete(:conditions) || {}
40
- end
41
-
42
- def criteria
43
- self.class.to_mongo_criteria(@conditions)
44
- end
45
-
46
- def options
47
- self.class.to_mongo_options(@options)
48
- end
49
-
50
- def to_a
51
- [criteria, options]
52
- end
53
-
54
- private
55
- def self.to_mongo_fields(fields)
56
- return if fields.blank?
57
-
58
- if fields.is_a?(String)
59
- fields.split(',').map { |field| field.strip }
60
- else
61
- fields.flatten.compact
62
- end
63
- end
64
-
65
- def self.to_mongo_sort(sort)
66
- return if sort.blank?
67
- pieces = sort.split(',')
68
- pairs = pieces.map { |s| to_mongo_sort_piece(s) }
69
-
70
- hash = OrderedHash.new
71
- pairs.each do |pair|
72
- field, sort_direction = pair
73
- hash[field] = sort_direction
74
- end
75
- hash.symbolize_keys
76
- end
77
-
78
- def self.to_mongo_sort_piece(str)
79
- field, direction = str.strip.split(' ')
80
- direction ||= 'ASC'
81
- direction = direction.upcase == 'ASC' ? 1 : -1
82
- [field, direction]
83
- end
84
- end
1
+ module MongoMapper
2
+ class FinderOptions
3
+ attr_reader :options
4
+
5
+ def self.to_mongo_criteria(conditions, parent_key=nil)
6
+ criteria = {}
7
+ conditions.each_pair do |field, value|
8
+ case value
9
+ when Array
10
+ operator_present = field.to_s =~ /^\$/
11
+ criteria[field] = if operator_present
12
+ value
13
+ else
14
+ {'$in' => value}
15
+ end
16
+ when Hash
17
+ criteria[field] = to_mongo_criteria(value, field)
18
+ else
19
+ criteria[field] = value
20
+ end
21
+ end
22
+
23
+ criteria
24
+ end
25
+
26
+ def self.to_mongo_options(options)
27
+ options = options.dup
28
+ {
29
+ :fields => to_mongo_fields(options.delete(:fields) || options.delete(:select)),
30
+ :skip => (options.delete(:skip) || 0).to_i,
31
+ :limit => (options.delete(:limit) || 0).to_i,
32
+ :sort => options.delete(:sort) || to_mongo_sort(options.delete(:order))
33
+ }
34
+ end
35
+
36
+ def initialize(options)
37
+ raise ArgumentError, "FinderOptions must be a hash" unless options.is_a?(Hash)
38
+ @options = options.symbolize_keys
39
+ @conditions = @options.delete(:conditions) || {}
40
+ end
41
+
42
+ def criteria
43
+ self.class.to_mongo_criteria(@conditions)
44
+ end
45
+
46
+ def options
47
+ self.class.to_mongo_options(@options)
48
+ end
49
+
50
+ def to_a
51
+ [criteria, options]
52
+ end
53
+
54
+ private
55
+ def self.to_mongo_fields(fields)
56
+ return if fields.blank?
57
+
58
+ if fields.is_a?(String)
59
+ fields.split(',').map { |field| field.strip }
60
+ else
61
+ fields.flatten.compact
62
+ end
63
+ end
64
+
65
+ def self.to_mongo_sort(sort)
66
+ return if sort.blank?
67
+ pieces = sort.split(',')
68
+ pairs = pieces.map { |s| to_mongo_sort_piece(s) }
69
+
70
+ hash = OrderedHash.new
71
+ pairs.each do |pair|
72
+ field, sort_direction = pair
73
+ hash[field] = sort_direction
74
+ end
75
+ hash.symbolize_keys
76
+ end
77
+
78
+ def self.to_mongo_sort_piece(str)
79
+ field, direction = str.strip.split(' ')
80
+ direction ||= 'ASC'
81
+ direction = direction.upcase == 'ASC' ? 1 : -1
82
+ [field, direction]
83
+ end
84
+ end
85
85
  end
@@ -1,76 +1,32 @@
1
- module MongoMapper
2
- class Key
3
- # DateTime and Date are currently not supported by mongo's bson so just use Time
4
- NativeTypes = [String, Float, Time, Integer, Boolean, Array, Hash]
5
-
6
- attr_accessor :name, :type, :options, :default_value
7
-
8
- def initialize(*args)
9
- options = args.extract_options!
10
- @name, @type = args.shift.to_s, args.shift
11
- self.options = (options || {}).symbolize_keys
12
- self.default_value = self.options.delete(:default)
13
- end
14
-
15
- def ==(other)
16
- @name == other.name && @type == other.type
17
- end
18
-
19
- def set(value)
20
- typecast(value)
21
- end
22
-
23
- def native?
24
- @native ||= NativeTypes.include?(type) || type.nil?
25
- end
26
-
27
- def embedded_document?
28
- type.respond_to?(:embeddable?) && type.embeddable?
29
- end
30
-
31
- def get(value)
32
- return default_value if value.nil? && !default_value.nil?
33
- if type == Array
34
- value || []
35
- elsif type == Hash
36
- HashWithIndifferentAccess.new(value || {})
37
- else
38
- value
39
- end
40
- end
41
-
42
- private
43
- def typecast(value)
44
- return value if type.nil?
45
- return HashWithIndifferentAccess.new(value) if value.is_a?(Hash) && type == Hash
46
- return value.utc if type == Time && value.kind_of?(type)
47
- return value if value.kind_of?(type) || value.nil?
48
- begin
49
- if type == String then value.to_s
50
- elsif type == Float then value.to_f
51
- elsif type == Array then value.to_a
52
- elsif type == Time then Time.parse(value.to_s).utc
53
- elsif type == Boolean then Boolean.mm_typecast(value)
54
- elsif type == Integer
55
- # ganked from datamapper
56
- value_to_i = value.to_i
57
- if value_to_i == 0
58
- value.to_s =~ /^(0x|0b)?0+/ ? 0 : nil
59
- else
60
- value_to_i
61
- end
62
- elsif embedded_document?
63
- typecast_embedded_document(value)
64
- else
65
- value
66
- end
67
- rescue
68
- value
69
- end
70
- end
71
-
72
- def typecast_embedded_document(value)
73
- value.is_a?(type) ? value : type.new(value)
74
- end
75
- end
76
- end
1
+ module MongoMapper
2
+ class Key
3
+ attr_accessor :name, :type, :options, :default_value
4
+
5
+ def initialize(*args)
6
+ options = args.extract_options!
7
+ @name, @type = args.shift.to_s, args.shift
8
+ self.options = (options || {}).symbolize_keys
9
+ self.default_value = self.options.delete(:default)
10
+ end
11
+
12
+ def ==(other)
13
+ @name == other.name && @type == other.type
14
+ end
15
+
16
+ def set(value)
17
+ type.to_mongo(value)
18
+ end
19
+
20
+ def embeddable?
21
+ type.respond_to?(:embeddable?) && type.embeddable? ? true : false
22
+ end
23
+
24
+ def get(value)
25
+ if value.nil? && !default_value.nil?
26
+ return default_value
27
+ end
28
+
29
+ type.from_mongo(value)
30
+ end
31
+ end
32
+ end
@@ -1,15 +1,15 @@
1
- module MongoMapper
2
- module RailsCompatibility
3
- module Document
4
- def self.included(model)
5
- model.class_eval do
6
- alias_method :new_record?, :new?
7
- end
8
- end
9
-
10
- def to_param
11
- id
12
- end
13
- end
14
- end
1
+ module MongoMapper
2
+ module RailsCompatibility
3
+ module Document
4
+ def self.included(model)
5
+ model.class_eval do
6
+ alias_method :new_record?, :new?
7
+ end
8
+ end
9
+
10
+ def to_param
11
+ id
12
+ end
13
+ end
14
+ end
15
15
  end
@@ -1,25 +1,27 @@
1
- module MongoMapper
2
- module RailsCompatibility
3
- module EmbeddedDocument
4
- def self.included(model)
5
- model.class_eval do
6
- extend ClassMethods
7
- end
8
-
9
- class << model
10
- alias has_many many
11
- end
12
- end
13
-
14
- module ClassMethods
15
- def column_names
16
- keys.keys
17
- end
18
- end
19
-
20
- def to_param
21
- raise "Missing to_param method in #{self.class}. You should implement it to return the unique identifier of this embedded document within a document."
22
- end
23
- end
24
- end
1
+ module MongoMapper
2
+ module RailsCompatibility
3
+ module EmbeddedDocument
4
+ def self.included(model)
5
+ model.class_eval do
6
+ extend ClassMethods
7
+
8
+ alias_method :new_record?, :new?
9
+ end
10
+
11
+ class << model
12
+ alias has_many many
13
+ end
14
+ end
15
+
16
+ module ClassMethods
17
+ def column_names
18
+ keys.keys
19
+ end
20
+ end
21
+
22
+ def to_param
23
+ raise "Missing to_param method in #{self.class}. You should implement it to return the unique identifier of this embedded document within a document."
24
+ end
25
+ end
26
+ end
25
27
  end
@@ -1,30 +1,157 @@
1
- class BasicObject #:nodoc:
2
- instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|instance_eval|proxy_|^object_id$)/ }
3
- end unless defined?(BasicObject)
4
-
5
- class Boolean
6
- def self.mm_typecast(value)
7
- ['true', 't', '1'].include?(value.to_s.downcase)
8
- end
9
- end
10
-
11
- class Object
12
- # The hidden singleton lurks behind everyone
13
- def metaclass
14
- class << self; self end
15
- end
16
-
17
- def meta_eval(&blk)
18
- metaclass.instance_eval(&blk)
19
- end
20
-
21
- # Adds methods to a metaclass
22
- def meta_def(name, &blk)
23
- meta_eval { define_method(name, &blk) }
24
- end
25
-
26
- # Defines an instance method within a class
27
- def class_def(name, &blk)
28
- class_eval { define_method(name, &blk) }
29
- end
1
+ class BasicObject #:nodoc:
2
+ instance_methods.each { |m| undef_method m unless m =~ /(^__|^nil\?$|^send$|^methods$|instance_eval|proxy_|^object_id$)/ }
3
+ end unless defined?(BasicObject)
4
+
5
+ class Array
6
+ def self.to_mongo(value)
7
+ value.to_a
8
+ end
9
+
10
+ def self.from_mongo(value)
11
+ value || []
12
+ end
13
+ end
14
+
15
+ class Binary
16
+ def self.to_mongo(value)
17
+ if value.is_a?(ByteBuffer)
18
+ value
19
+ else
20
+ ByteBuffer.new(value)
21
+ end
22
+ end
23
+
24
+ def self.from_mongo(value)
25
+ value
26
+ end
27
+ end
28
+
29
+ class Boolean
30
+ def self.to_mongo(value)
31
+ if value.is_a?(Boolean)
32
+ value
33
+ else
34
+ ['true', 't', '1'].include?(value.to_s.downcase)
35
+ end
36
+ end
37
+
38
+ def self.from_mongo(value)
39
+ !!value
40
+ end
41
+ end
42
+
43
+ class Date
44
+ def self.to_mongo(value)
45
+ date = Date.parse(value.to_s)
46
+ Time.utc(date.year, date.month, date.day)
47
+ rescue
48
+ nil
49
+ end
50
+
51
+ def self.from_mongo(value)
52
+ value.to_date if value.present?
53
+ end
54
+ end
55
+
56
+ class Float
57
+ def self.to_mongo(value)
58
+ value.to_f
59
+ end
60
+ end
61
+
62
+ class Hash
63
+ def self.from_mongo(value)
64
+ HashWithIndifferentAccess.new(value || {})
65
+ end
66
+
67
+ def to_mongo
68
+ self
69
+ end
70
+ end
71
+
72
+ class Integer
73
+ def self.to_mongo(value)
74
+ value_to_i = value.to_i
75
+ if value_to_i == 0
76
+ value.to_s =~ /^(0x|0b)?0+/ ? 0 : nil
77
+ else
78
+ value_to_i
79
+ end
80
+ end
81
+ end
82
+
83
+ class NilClass
84
+ def to_mongo(value)
85
+ value
86
+ end
87
+
88
+ def from_mongo(value)
89
+ value
90
+ end
91
+ end
92
+
93
+ class Object
94
+ # The hidden singleton lurks behind everyone
95
+ def metaclass
96
+ class << self; self end
97
+ end
98
+
99
+ def meta_eval(&blk)
100
+ metaclass.instance_eval(&blk)
101
+ end
102
+
103
+ # Adds methods to a metaclass
104
+ def meta_def(name, &blk)
105
+ meta_eval { define_method(name, &blk) }
106
+ end
107
+
108
+ # Defines an instance method within a class
109
+ def class_def(name, &blk)
110
+ class_eval { define_method(name, &blk) }
111
+ end
112
+
113
+ def self.to_mongo(value)
114
+ value
115
+ end
116
+
117
+ def self.from_mongo(value)
118
+ value
119
+ end
120
+ end
121
+
122
+ class String
123
+ def self.to_mongo(value)
124
+ value.nil? ? nil : value.to_s
125
+ end
126
+
127
+ def self.from_mongo(value)
128
+ value.present? ? value : nil
129
+ end
130
+ end
131
+
132
+ class Time
133
+ def self.to_mongo(value)
134
+ to_utc_time(value)
135
+ end
136
+
137
+ def self.from_mongo(value)
138
+ if Time.respond_to?(:zone) && Time.zone && value.present?
139
+ value.in_time_zone(Time.zone)
140
+ else
141
+ value
142
+ end
143
+ end
144
+
145
+ def self.to_utc_time(value)
146
+ to_local_time(value).try(:utc)
147
+ end
148
+
149
+ # make sure we have a time and that it is local
150
+ def self.to_local_time(value)
151
+ if Time.respond_to?(:zone) && Time.zone
152
+ Time.zone.parse(value.to_s)
153
+ else
154
+ Time.parse(value.to_s)
155
+ end
156
+ end
30
157
  end