mongomodel 0.4.1 → 0.4.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.
- data/Appraisals +0 -5
- data/Guardfile +5 -0
- data/gemfiles/rails-3.1.gemfile.lock +10 -4
- data/gemfiles/rails-edge.gemfile.lock +10 -4
- data/lib/mongomodel.rb +1 -0
- data/lib/mongomodel/concerns/associations/base/definition.rb +4 -0
- data/lib/mongomodel/concerns/associations/belongs_to.rb +4 -0
- data/lib/mongomodel/concerns/attribute_methods/nested.rb +103 -0
- data/lib/mongomodel/concerns/attribute_methods/protected.rb +6 -2
- data/lib/mongomodel/concerns/attributes.rb +7 -1
- data/lib/mongomodel/concerns/validations.rb +2 -6
- data/lib/mongomodel/concerns/validations/associated.rb +8 -7
- data/lib/mongomodel/document/persistence.rb +17 -5
- data/lib/mongomodel/document/validations.rb +15 -14
- data/lib/mongomodel/embedded_document.rb +1 -0
- data/lib/mongomodel/support/collection.rb +20 -3
- data/lib/mongomodel/support/configuration.rb +11 -7
- data/lib/mongomodel/support/exceptions.rb +2 -0
- data/lib/mongomodel/version.rb +1 -1
- data/mongomodel.gemspec +5 -4
- data/spec/mongomodel/concerns/attribute_methods/nested_spec.rb +180 -0
- data/spec/mongomodel/concerns/validations_spec.rb +15 -8
- data/spec/mongomodel/document/validations_spec.rb +38 -5
- data/spec/mongomodel/support/collection_spec.rb +21 -0
- data/spec/support/helpers/validations.rb +5 -0
- metadata +33 -21
- data/autotest/discover.rb +0 -1
- data/gemfiles/rails-3.0.gemfile +0 -11
- data/gemfiles/rails-3.0.gemfile.lock +0 -75
data/Appraisals
CHANGED
data/Guardfile
ADDED
@@ -1,9 +1,9 @@
|
|
1
1
|
PATH
|
2
|
-
remote: /Users/sam/
|
2
|
+
remote: /Users/sam/Development/MongoDB/mongomodel
|
3
3
|
specs:
|
4
|
-
mongomodel (0.4.
|
5
|
-
activemodel (~> 3.
|
6
|
-
activesupport (~> 3.
|
4
|
+
mongomodel (0.4.1)
|
5
|
+
activemodel (~> 3.1)
|
6
|
+
activesupport (~> 3.1)
|
7
7
|
mongo (~> 1.4)
|
8
8
|
will_paginate (~> 2.3.15)
|
9
9
|
|
@@ -25,6 +25,10 @@ GEM
|
|
25
25
|
bson_ext (1.4.0)
|
26
26
|
builder (3.0.0)
|
27
27
|
diff-lcs (1.1.3)
|
28
|
+
guard (0.8.6)
|
29
|
+
thor (~> 0.14.6)
|
30
|
+
guard-rspec (0.5.0)
|
31
|
+
guard (>= 0.8.4)
|
28
32
|
i18n (0.6.0)
|
29
33
|
mongo (1.4.0)
|
30
34
|
bson (= 1.4.0)
|
@@ -38,6 +42,7 @@ GEM
|
|
38
42
|
rspec-expectations (2.6.0)
|
39
43
|
diff-lcs (~> 1.1.2)
|
40
44
|
rspec-mocks (2.6.0)
|
45
|
+
thor (0.14.6)
|
41
46
|
tzinfo (0.3.29)
|
42
47
|
will_paginate (2.3.16)
|
43
48
|
|
@@ -50,6 +55,7 @@ DEPENDENCIES
|
|
50
55
|
appraisal (~> 0.3.6)
|
51
56
|
bson_ext (~> 1.4)
|
52
57
|
bundler (>= 1.0.0)
|
58
|
+
guard-rspec (~> 0.5.0)
|
53
59
|
mongomodel!
|
54
60
|
rspec (~> 2.6.0)
|
55
61
|
tzinfo
|
@@ -12,11 +12,11 @@ GIT
|
|
12
12
|
multi_json (~> 1.0)
|
13
13
|
|
14
14
|
PATH
|
15
|
-
remote: /Users/sam/
|
15
|
+
remote: /Users/sam/Development/MongoDB/mongomodel
|
16
16
|
specs:
|
17
|
-
mongomodel (0.4.
|
18
|
-
activemodel (~> 3.
|
19
|
-
activesupport (~> 3.
|
17
|
+
mongomodel (0.4.1)
|
18
|
+
activemodel (~> 3.1)
|
19
|
+
activesupport (~> 3.1)
|
20
20
|
mongo (~> 1.4)
|
21
21
|
will_paginate (~> 2.3.15)
|
22
22
|
|
@@ -31,6 +31,10 @@ GEM
|
|
31
31
|
bson_ext (1.4.0)
|
32
32
|
builder (3.0.0)
|
33
33
|
diff-lcs (1.1.2)
|
34
|
+
guard (0.8.6)
|
35
|
+
thor (~> 0.14.6)
|
36
|
+
guard-rspec (0.5.0)
|
37
|
+
guard (>= 0.8.4)
|
34
38
|
i18n (0.6.0)
|
35
39
|
mongo (1.4.0)
|
36
40
|
bson (= 1.4.0)
|
@@ -44,6 +48,7 @@ GEM
|
|
44
48
|
rspec-expectations (2.6.0)
|
45
49
|
diff-lcs (~> 1.1.2)
|
46
50
|
rspec-mocks (2.6.0)
|
51
|
+
thor (0.14.6)
|
47
52
|
tzinfo (0.3.29)
|
48
53
|
will_paginate (2.3.16)
|
49
54
|
|
@@ -56,6 +61,7 @@ DEPENDENCIES
|
|
56
61
|
appraisal (~> 0.3.6)
|
57
62
|
bson_ext (~> 1.4)
|
58
63
|
bundler (>= 1.0.0)
|
64
|
+
guard-rspec (~> 0.5.0)
|
59
65
|
mongomodel!
|
60
66
|
rspec (~> 2.6.0)
|
61
67
|
tzinfo
|
data/lib/mongomodel.rb
CHANGED
@@ -51,6 +51,7 @@ module MongoModel
|
|
51
51
|
autoload :BeforeTypeCast, 'mongomodel/concerns/attribute_methods/before_type_cast'
|
52
52
|
autoload :Protected, 'mongomodel/concerns/attribute_methods/protected'
|
53
53
|
autoload :Dirty, 'mongomodel/concerns/attribute_methods/dirty'
|
54
|
+
autoload :Nested, 'mongomodel/concerns/attribute_methods/nested'
|
54
55
|
autoload :MultiParameterAssignment, 'mongomodel/concerns/attribute_methods/multi_parameter_assignment'
|
55
56
|
end
|
56
57
|
|
@@ -9,6 +9,10 @@ module MongoModel
|
|
9
9
|
@type_key ||= :"#{name}_type"
|
10
10
|
end
|
11
11
|
|
12
|
+
def collection?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
12
16
|
properties do |association|
|
13
17
|
property association.foreign_key, MongoModel::Reference, :internal => true
|
14
18
|
property association.type_key, String, :internal => true if association.polymorphic?
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module MongoModel
|
2
|
+
module AttributeMethods
|
3
|
+
module Nested
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
class_attribute :nested_attributes_options, :instance_writer => false
|
8
|
+
self.nested_attributes_options = {}
|
9
|
+
end
|
10
|
+
|
11
|
+
module ClassMethods
|
12
|
+
def accepts_nested_attributes_for(*attr_names)
|
13
|
+
options = attr_names.extract_options!
|
14
|
+
|
15
|
+
attr_names.each do |attr_name|
|
16
|
+
type = property_type(attr_name)
|
17
|
+
|
18
|
+
nested_attributes_options = self.nested_attributes_options.dup
|
19
|
+
nested_attributes_options[attr_name.to_sym] = options
|
20
|
+
self.nested_attributes_options = nested_attributes_options
|
21
|
+
|
22
|
+
class_eval <<-EORUBY, __FILE__, __LINE__ + 1
|
23
|
+
if method_defined?(:#{attr_name}_attributes=)
|
24
|
+
remove_method(:#{attr_name}_attributes=)
|
25
|
+
end
|
26
|
+
|
27
|
+
def #{attr_name}_attributes=(attributes)
|
28
|
+
assign_nested_attributes_for_#{type}(:#{attr_name}, attributes)
|
29
|
+
end
|
30
|
+
EORUBY
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
private
|
35
|
+
def property_type(attr_name)
|
36
|
+
if property = properties[attr_name]
|
37
|
+
property.type <= Array ? :collection : :property
|
38
|
+
elsif association = associations[attr_name]
|
39
|
+
association.collection? ? :association_collection : :association
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
private
|
45
|
+
def assign_nested_attributes_for_property(property, attributes)
|
46
|
+
if obj = send(property)
|
47
|
+
obj.attributes = attributes
|
48
|
+
else
|
49
|
+
send("#{property}=", attributes)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def assign_nested_attributes_for_collection(property, attributes_collection)
|
54
|
+
attributes_collection = convert_to_array(attributes_collection)
|
55
|
+
options = self.nested_attributes_options[property]
|
56
|
+
|
57
|
+
if options[:limit] && attributes_collection.size > options[:limit]
|
58
|
+
raise TooManyDocuments, "Maximum #{options[:limit]} documents are allowed. Got #{attributes_collection.size} documents instead."
|
59
|
+
end
|
60
|
+
|
61
|
+
collection = send(property)
|
62
|
+
attributes_collection.each_with_index do |attributes, index|
|
63
|
+
if collection[index]
|
64
|
+
collection[index].attributes = attributes
|
65
|
+
else
|
66
|
+
collection[index] = attributes
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
def assign_nested_attributes_for_association(association, attributes)
|
72
|
+
if obj = send(association)
|
73
|
+
obj.attributes = attributes
|
74
|
+
else
|
75
|
+
send("build_#{association}", attributes)
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
def assign_nested_attributes_for_association_collection(association, attributes_collection)
|
80
|
+
attributes_collection = convert_to_array(attributes_collection)
|
81
|
+
options = self.nested_attributes_options[association]
|
82
|
+
|
83
|
+
if options[:limit] && attributes_collection.size > options[:limit]
|
84
|
+
raise TooManyDocuments, "Maximum #{options[:limit]} documents are allowed. Got #{attributes_collection.size} documents instead."
|
85
|
+
end
|
86
|
+
|
87
|
+
association = send(association)
|
88
|
+
attributes_collection.each do |attributes|
|
89
|
+
association.build(attributes)
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def convert_to_array(params)
|
94
|
+
case params
|
95
|
+
when Hash
|
96
|
+
params.sort.map(&:last)
|
97
|
+
else
|
98
|
+
Array(params)
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
@@ -16,8 +16,12 @@ module MongoModel
|
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
19
|
-
def
|
20
|
-
|
19
|
+
def assign_attributes(attrs, options={})
|
20
|
+
if options[:without_protection]
|
21
|
+
super
|
22
|
+
else
|
23
|
+
super(sanitize_for_mass_assignment(attrs, options[:as] || :default))
|
24
|
+
end
|
21
25
|
end
|
22
26
|
end
|
23
27
|
end
|
@@ -13,7 +13,9 @@ module MongoModel
|
|
13
13
|
@attributes ||= Attributes::Store.new(self)
|
14
14
|
end
|
15
15
|
|
16
|
-
def
|
16
|
+
def assign_attributes(attrs, options={})
|
17
|
+
return unless attrs
|
18
|
+
|
17
19
|
attrs.each do |attr, value|
|
18
20
|
if respond_to?("#{attr}=")
|
19
21
|
send("#{attr}=", value)
|
@@ -23,6 +25,10 @@ module MongoModel
|
|
23
25
|
end
|
24
26
|
end
|
25
27
|
|
28
|
+
def attributes=(attrs)
|
29
|
+
assign_attributes(attrs)
|
30
|
+
end
|
31
|
+
|
26
32
|
def freeze
|
27
33
|
attributes.freeze; self
|
28
34
|
end
|
@@ -17,12 +17,8 @@ module MongoModel
|
|
17
17
|
end
|
18
18
|
|
19
19
|
def valid?(context=nil)
|
20
|
-
|
21
|
-
|
22
|
-
self.validation_context = new_record? ? :create : :update
|
23
|
-
run_callbacks(:validate)
|
24
|
-
|
25
|
-
errors.empty?
|
20
|
+
context ||= new_record? ? :create : :update
|
21
|
+
super
|
26
22
|
end
|
27
23
|
end
|
28
24
|
end
|
@@ -1,5 +1,12 @@
|
|
1
1
|
module MongoModel
|
2
2
|
module Validations
|
3
|
+
class AssociatedValidator < ActiveModel::EachValidator
|
4
|
+
def validate_each(record, attribute, value)
|
5
|
+
return if Array(value).map { |r| r.nil? || r.valid?(record.validation_context) }.all?
|
6
|
+
record.errors.add(attribute, :invalid, options.merge(:value => value))
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
3
10
|
module ClassMethods
|
4
11
|
# Validates whether the associated object or objects are all valid themselves. Works with any kind of association.
|
5
12
|
#
|
@@ -33,13 +40,7 @@ module MongoModel
|
|
33
40
|
# not occur (e.g. <tt>:unless => :skip_validation</tt>, or <tt>:unless => Proc.new { |user| user.signup_step <= 2 }</tt>). The
|
34
41
|
# method, proc or string should return or evaluate to a true or false value.
|
35
42
|
def validates_associated(*attr_names)
|
36
|
-
|
37
|
-
|
38
|
-
validates_each(attr_names, configuration) do |record, attr_name, value|
|
39
|
-
unless (value.is_a?(Array) ? value : [value]).collect { |r| r.nil? || r.valid? }.all?
|
40
|
-
record.errors.add(attr_name, :invalid, :default => configuration[:message], :value => value)
|
41
|
-
end
|
42
|
-
end
|
43
|
+
validates_with AssociatedValidator, _merge_attributes(attr_names)
|
43
44
|
end
|
44
45
|
end
|
45
46
|
end
|
@@ -24,12 +24,12 @@ module MongoModel
|
|
24
24
|
end
|
25
25
|
|
26
26
|
# Save the document to the database. Returns +true+ on success.
|
27
|
-
def save
|
27
|
+
def save(*)
|
28
28
|
create_or_update
|
29
29
|
end
|
30
30
|
|
31
31
|
# Save the document to the database. Raises a DocumentNotSaved exception if it fails.
|
32
|
-
def save!
|
32
|
+
def save!(*)
|
33
33
|
create_or_update || raise(DocumentNotSaved)
|
34
34
|
end
|
35
35
|
|
@@ -46,16 +46,28 @@ module MongoModel
|
|
46
46
|
|
47
47
|
# Updates all the attributes from the passed-in Hash and saves the document.
|
48
48
|
# If the object is invalid, the saving will fail and false will be returned.
|
49
|
-
|
50
|
-
|
49
|
+
#
|
50
|
+
# When updating model attributes, mass-assignment security protection is respected.
|
51
|
+
# If no +:as+ option is supplied then the +:default+ role will be used.
|
52
|
+
# If you want to bypass the protection given by +attr_protected+ and
|
53
|
+
# +attr_accessible+ then you can do so using the +:without_protection+ option.
|
54
|
+
def update_attributes(attributes, options={})
|
55
|
+
self.assign_attributes(attributes, options)
|
51
56
|
save
|
52
57
|
end
|
53
58
|
|
59
|
+
# Updates its receiver just like +update_attributes+ but calls <tt>save!</tt> instead
|
60
|
+
# of +save+, so an exception is raised if the docuemnt is invalid.
|
61
|
+
def update_attributes!(attributes, options={})
|
62
|
+
self.assign_attributes(attributes, options)
|
63
|
+
save!
|
64
|
+
end
|
65
|
+
|
54
66
|
# Updates a single attribute and saves the document without going through the normal validation procedure.
|
55
67
|
# This is especially useful for boolean flags on existing documents.
|
56
68
|
def update_attribute(name, value)
|
57
69
|
send("#{name}=", value)
|
58
|
-
save(false)
|
70
|
+
save(:validate => false)
|
59
71
|
end
|
60
72
|
|
61
73
|
def collection
|
@@ -2,12 +2,7 @@ module MongoModel
|
|
2
2
|
module DocumentExtensions
|
3
3
|
module Validations
|
4
4
|
extend ActiveSupport::Concern
|
5
|
-
|
6
|
-
included do
|
7
|
-
alias_method_chain :save, :validation
|
8
|
-
alias_method_chain :save!, :validation
|
9
|
-
end
|
10
|
-
|
5
|
+
|
11
6
|
module ClassMethods
|
12
7
|
def property(name, *args, &block) #:nodoc:
|
13
8
|
property = super
|
@@ -30,12 +25,12 @@ module MongoModel
|
|
30
25
|
end
|
31
26
|
end
|
32
27
|
|
33
|
-
# The validation process on save can be skipped by passing false
|
28
|
+
# The validation process on save can be skipped by passing <tt>:validate => false</tt>. The regular Document#save method is
|
34
29
|
# replaced with this when the validations module is mixed in, which it is by default.
|
35
|
-
def
|
36
|
-
if perform_validation
|
30
|
+
def save(options={})
|
31
|
+
if perform_validation(options)
|
37
32
|
begin
|
38
|
-
|
33
|
+
super
|
39
34
|
rescue DocumentNotSaved
|
40
35
|
valid?
|
41
36
|
false
|
@@ -47,17 +42,23 @@ module MongoModel
|
|
47
42
|
|
48
43
|
# Attempts to save the document just like Document#save but will raise a DocumentInvalid exception
|
49
44
|
# instead of returning false if the document is not valid.
|
50
|
-
def
|
51
|
-
if
|
45
|
+
def save!(options={})
|
46
|
+
if perform_validation(options)
|
52
47
|
begin
|
53
|
-
|
48
|
+
super
|
54
49
|
rescue DocumentNotSaved => e
|
55
|
-
|
50
|
+
valid? ? raise : raise(DocumentInvalid.new(self))
|
56
51
|
end
|
57
52
|
else
|
58
53
|
raise DocumentInvalid.new(self)
|
59
54
|
end
|
60
55
|
end
|
56
|
+
|
57
|
+
protected
|
58
|
+
def perform_validation(options={})
|
59
|
+
perform_validation = options != false && options[:validate] != false
|
60
|
+
perform_validation ? valid?(options[:context]) : true
|
61
|
+
end
|
61
62
|
end
|
62
63
|
end
|
63
64
|
end
|
@@ -119,7 +119,7 @@ module MongoModel
|
|
119
119
|
def [](type)
|
120
120
|
@collection_class_cache ||= {}
|
121
121
|
@collection_class_cache[type] ||= begin
|
122
|
-
collection = Class.new(
|
122
|
+
collection = Class.new(self)
|
123
123
|
collection.type = type
|
124
124
|
collection
|
125
125
|
end
|
@@ -127,8 +127,25 @@ module MongoModel
|
|
127
127
|
|
128
128
|
alias of []
|
129
129
|
|
130
|
-
def
|
131
|
-
|
130
|
+
def cast(value)
|
131
|
+
case value
|
132
|
+
when Array
|
133
|
+
new(value)
|
134
|
+
when Hash
|
135
|
+
value.stringify_keys!
|
136
|
+
value['_collection'] ? cast(value['items']) : new([value])
|
137
|
+
else
|
138
|
+
new(Array(value))
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
def from_mongo(value)
|
143
|
+
case value
|
144
|
+
when Array
|
145
|
+
new(value.map { |i| instantiate(i) })
|
146
|
+
else
|
147
|
+
from_mongo([value])
|
148
|
+
end
|
132
149
|
end
|
133
150
|
|
134
151
|
def converter
|
@@ -8,23 +8,23 @@ module MongoModel
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def host
|
11
|
-
|
11
|
+
options['host']
|
12
12
|
end
|
13
13
|
|
14
14
|
def port
|
15
|
-
|
15
|
+
options['port']
|
16
16
|
end
|
17
17
|
|
18
18
|
def database
|
19
|
-
|
19
|
+
options['database']
|
20
20
|
end
|
21
21
|
|
22
22
|
def username
|
23
|
-
|
23
|
+
options['username']
|
24
24
|
end
|
25
25
|
|
26
26
|
def password
|
27
|
-
|
27
|
+
options['password']
|
28
28
|
end
|
29
29
|
|
30
30
|
def establish_connection
|
@@ -35,12 +35,16 @@ module MongoModel
|
|
35
35
|
end
|
36
36
|
|
37
37
|
def use_database(database)
|
38
|
-
|
38
|
+
options['database'] = database
|
39
39
|
establish_connection
|
40
40
|
end
|
41
41
|
|
42
42
|
def connection_options
|
43
|
-
|
43
|
+
options.except('host', 'port', 'database', 'username', 'password').symbolize_keys
|
44
|
+
end
|
45
|
+
|
46
|
+
def options
|
47
|
+
@options ||= {}
|
44
48
|
end
|
45
49
|
|
46
50
|
def set_options!(options)
|
data/lib/mongomodel/version.rb
CHANGED
data/mongomodel.gemspec
CHANGED
@@ -14,13 +14,14 @@ Gem::Specification.new do |s|
|
|
14
14
|
s.required_rubygems_version = ">= 1.3.6"
|
15
15
|
s.rubyforge_project = "mongomodel"
|
16
16
|
|
17
|
-
s.add_dependency "activesupport", "~> 3.
|
18
|
-
s.add_dependency "activemodel", "~> 3.
|
17
|
+
s.add_dependency "activesupport", "~> 3.1"
|
18
|
+
s.add_dependency "activemodel", "~> 3.1"
|
19
19
|
s.add_dependency "mongo", "~> 1.4"
|
20
20
|
s.add_dependency "will_paginate", "~> 2.3.15"
|
21
21
|
|
22
|
-
s.add_development_dependency "bundler",
|
23
|
-
s.add_development_dependency "rspec",
|
22
|
+
s.add_development_dependency "bundler", ">= 1.0.0"
|
23
|
+
s.add_development_dependency "rspec", "~> 2.6.0"
|
24
|
+
s.add_development_dependency "guard-rspec", "~> 0.5.0"
|
24
25
|
|
25
26
|
s.files = `git ls-files`.split("\n")
|
26
27
|
s.require_path = 'lib'
|
@@ -0,0 +1,180 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module MongoModel
|
4
|
+
specs_for(Document, EmbeddedDocument) do
|
5
|
+
def self.define_user(type)
|
6
|
+
define_class(:User, type) do
|
7
|
+
property :name, String
|
8
|
+
property :age, Integer
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe ".accepts_nested_attributes_for" do
|
13
|
+
describe "single embedded property" do
|
14
|
+
define_user(EmbeddedDocument)
|
15
|
+
define_class(:Account, described_class) do
|
16
|
+
property :owner, User
|
17
|
+
accepts_nested_attributes_for :owner
|
18
|
+
end
|
19
|
+
|
20
|
+
subject { Account.new }
|
21
|
+
|
22
|
+
it "creates new model when property is blank" do
|
23
|
+
subject.owner_attributes = { :name => "John Smith", :age => 35 }
|
24
|
+
subject.owner.name.should == "John Smith"
|
25
|
+
subject.owner.age.should == 35
|
26
|
+
end
|
27
|
+
|
28
|
+
it "sets existing model attributes when property exists" do
|
29
|
+
subject.owner = User.new(:name => "Jane Doe")
|
30
|
+
subject.owner_attributes = { :age => 22 }
|
31
|
+
subject.owner.name.should == "Jane Doe"
|
32
|
+
subject.owner.age.should == 22
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe "embedded collection" do
|
37
|
+
define_user(EmbeddedDocument)
|
38
|
+
define_class(:Account, described_class) do
|
39
|
+
property :owners, Collection[User]
|
40
|
+
accepts_nested_attributes_for :owners
|
41
|
+
end
|
42
|
+
|
43
|
+
subject { Account.new }
|
44
|
+
|
45
|
+
it "accepts an array of hashes" do
|
46
|
+
subject.owners_attributes = [
|
47
|
+
{ :name => "Fred", :age => 35 },
|
48
|
+
{ :name => "Mary", :age => 22 }
|
49
|
+
]
|
50
|
+
|
51
|
+
subject.owners[0].name.should == "Fred"
|
52
|
+
subject.owners[0].age.should == 35
|
53
|
+
subject.owners[1].name.should == "Mary"
|
54
|
+
subject.owners[1].age.should == 22
|
55
|
+
end
|
56
|
+
|
57
|
+
it "accepts a hash keyed by indexes" do
|
58
|
+
subject.owners_attributes = {
|
59
|
+
"1" => { :name => "Joe", :age => 15 },
|
60
|
+
"0" => { :name => "Peter", :age => 44 }
|
61
|
+
}
|
62
|
+
|
63
|
+
subject.owners[0].name.should == "Peter"
|
64
|
+
subject.owners[0].age.should == 44
|
65
|
+
subject.owners[1].name.should == "Joe"
|
66
|
+
subject.owners[1].age.should == 15
|
67
|
+
end
|
68
|
+
|
69
|
+
it "modifies existing collection" do
|
70
|
+
subject.owners << User.new(:name => "John")
|
71
|
+
subject.owners_attributes = [
|
72
|
+
{ :age => 18 },
|
73
|
+
{ :name => "Max", :age => 10 }
|
74
|
+
]
|
75
|
+
|
76
|
+
subject.owners[0].name.should == "John"
|
77
|
+
subject.owners[0].age.should == 18
|
78
|
+
subject.owners[1].name.should == "Max"
|
79
|
+
subject.owners[1].age.should == 10
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
describe "embedded collection with limit" do
|
84
|
+
define_user(EmbeddedDocument)
|
85
|
+
define_class(:Account, described_class) do
|
86
|
+
property :owners, Collection[User]
|
87
|
+
accepts_nested_attributes_for :owners, :limit => 2
|
88
|
+
end
|
89
|
+
|
90
|
+
subject { Account.new }
|
91
|
+
|
92
|
+
it "raises a TooManyDocuments error if number of documents exceeds limit" do
|
93
|
+
lambda {
|
94
|
+
subject.owners_attributes = [{}, {}, {}]
|
95
|
+
}.should raise_error(MongoModel::TooManyDocuments, "Maximum 2 documents are allowed. Got 3 documents instead.")
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
describe "belongs_to association" do
|
100
|
+
define_user(Document)
|
101
|
+
define_class(:Account, described_class) do
|
102
|
+
belongs_to :owner, :class => User
|
103
|
+
accepts_nested_attributes_for :owner
|
104
|
+
end
|
105
|
+
|
106
|
+
subject { Account.new }
|
107
|
+
|
108
|
+
it "creates new model when property is blank" do
|
109
|
+
subject.owner_attributes = { :name => "John Smith", :age => 35 }
|
110
|
+
subject.owner.name.should == "John Smith"
|
111
|
+
subject.owner.age.should == 35
|
112
|
+
end
|
113
|
+
|
114
|
+
it "sets existing model attributes when property exists" do
|
115
|
+
subject.owner = User.new(:name => "Jane Doe")
|
116
|
+
subject.owner_attributes = { :age => 22 }
|
117
|
+
subject.owner.name.should == "Jane Doe"
|
118
|
+
subject.owner.age.should == 22
|
119
|
+
end
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
124
|
+
specs_for(Document) do
|
125
|
+
define_class(:User, Document) do
|
126
|
+
property :name, String
|
127
|
+
property :age, Integer
|
128
|
+
end
|
129
|
+
|
130
|
+
describe ".accepts_nested_attributes_for" do
|
131
|
+
describe "has_many association" do
|
132
|
+
define_class(:Account, described_class) do
|
133
|
+
has_many :owners, :class => User
|
134
|
+
accepts_nested_attributes_for :owners
|
135
|
+
end
|
136
|
+
|
137
|
+
subject { Account.new }
|
138
|
+
|
139
|
+
it "accepts an array of hashes" do
|
140
|
+
subject.owners_attributes = [
|
141
|
+
{ :name => "Fred", :age => 35 },
|
142
|
+
{ :name => "Mary", :age => 22 }
|
143
|
+
]
|
144
|
+
|
145
|
+
subject.owners[0].name.should == "Fred"
|
146
|
+
subject.owners[0].age.should == 35
|
147
|
+
subject.owners[1].name.should == "Mary"
|
148
|
+
subject.owners[1].age.should == 22
|
149
|
+
end
|
150
|
+
|
151
|
+
it "accepts a hash keyed by indexes" do
|
152
|
+
subject.owners_attributes = {
|
153
|
+
"1" => { :name => "Joe", :age => 15 },
|
154
|
+
"0" => { :name => "Peter", :age => 44 }
|
155
|
+
}
|
156
|
+
|
157
|
+
subject.owners[0].name.should == "Peter"
|
158
|
+
subject.owners[0].age.should == 44
|
159
|
+
subject.owners[1].name.should == "Joe"
|
160
|
+
subject.owners[1].age.should == 15
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
describe "has_many association with limit" do
|
165
|
+
define_class(:Account, described_class) do
|
166
|
+
has_many :owners, :class => User
|
167
|
+
accepts_nested_attributes_for :owners, :limit => 2
|
168
|
+
end
|
169
|
+
|
170
|
+
subject { Account.new }
|
171
|
+
|
172
|
+
it "raises a TooManyDocuments error if number of documents exceeds limit" do
|
173
|
+
lambda {
|
174
|
+
subject.owners_attributes = [{}, {}, {}]
|
175
|
+
}.should raise_error(MongoModel::TooManyDocuments, "Maximum 2 documents are allowed. Got 3 documents instead.")
|
176
|
+
end
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
end
|
@@ -1,19 +1,13 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
3
|
module MongoModel
|
4
|
-
module ValidationHelpers
|
5
|
-
def clear_validations!
|
6
|
-
reset_callbacks(:validate)
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
4
|
specs_for(Document, EmbeddedDocument) do
|
11
5
|
describe "validations" do
|
12
6
|
define_class(:TestDocument, described_class) do
|
13
7
|
property :title, String
|
14
8
|
validates_presence_of :title
|
15
9
|
|
16
|
-
extend
|
10
|
+
extend ValidationHelpers
|
17
11
|
end
|
18
12
|
|
19
13
|
if specing?(EmbeddedDocument)
|
@@ -84,6 +78,19 @@ module MongoModel
|
|
84
78
|
it { should_not be_valid }
|
85
79
|
end
|
86
80
|
end
|
81
|
+
|
82
|
+
describe "validation on custom context" do
|
83
|
+
before(:each) do
|
84
|
+
TestDocument.clear_validations!
|
85
|
+
TestDocument.validates_presence_of :title, :on => :custom
|
86
|
+
end
|
87
|
+
|
88
|
+
it { should be_valid }
|
89
|
+
|
90
|
+
it "should not be valid in custom context" do
|
91
|
+
subject.valid?(:custom).should be_false
|
92
|
+
end
|
93
|
+
end
|
87
94
|
end
|
88
95
|
|
89
96
|
describe "validation shortcuts" do
|
@@ -111,7 +118,7 @@ module MongoModel
|
|
111
118
|
property :title, String
|
112
119
|
validates_presence_of :title
|
113
120
|
|
114
|
-
extend
|
121
|
+
extend ValidationHelpers
|
115
122
|
end
|
116
123
|
|
117
124
|
define_class(:ParentDocument, Document) do
|
@@ -6,6 +6,8 @@ module MongoModel
|
|
6
6
|
define_class(:TestDocument, Document) do
|
7
7
|
property :title, String
|
8
8
|
validates_presence_of :title
|
9
|
+
|
10
|
+
extend ValidationHelpers
|
9
11
|
end
|
10
12
|
|
11
13
|
context "when validations are not met" do
|
@@ -27,19 +29,50 @@ module MongoModel
|
|
27
29
|
end
|
28
30
|
end
|
29
31
|
|
30
|
-
|
32
|
+
shared_examples_for "saving without validation" do
|
31
33
|
it "should not validate the document" do
|
32
34
|
subject.should_not_receive(:valid?)
|
33
|
-
|
35
|
+
save
|
34
36
|
end
|
35
37
|
|
36
38
|
it "should save the document" do
|
37
|
-
subject.should_receive(:
|
38
|
-
|
39
|
+
subject.should_receive(:create_or_update).and_return(true)
|
40
|
+
save
|
39
41
|
end
|
40
42
|
|
41
43
|
it "should return true" do
|
42
|
-
|
44
|
+
save.should be_true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#save(false) [deprecated save without validations]" do
|
49
|
+
def save
|
50
|
+
subject.save(false)
|
51
|
+
end
|
52
|
+
|
53
|
+
it_should_behave_like "saving without validation"
|
54
|
+
end
|
55
|
+
|
56
|
+
describe "#save(:validate => false)" do
|
57
|
+
def save
|
58
|
+
subject.save(:validate => false)
|
59
|
+
end
|
60
|
+
|
61
|
+
it_should_behave_like "saving without validation"
|
62
|
+
end
|
63
|
+
|
64
|
+
describe "#save(:context => :custom)" do
|
65
|
+
before(:each) do
|
66
|
+
TestDocument.clear_validations!
|
67
|
+
TestDocument.validates_presence_of :title, :on => :custom
|
68
|
+
end
|
69
|
+
|
70
|
+
it "should save in default context" do
|
71
|
+
subject.save.should be_true
|
72
|
+
end
|
73
|
+
|
74
|
+
it "should not save in custom context" do
|
75
|
+
subject.save(:context => :custom).should be_false
|
43
76
|
end
|
44
77
|
end
|
45
78
|
end
|
@@ -194,6 +194,12 @@ module MongoModel
|
|
194
194
|
collection.should be_a(subject)
|
195
195
|
collection.should == [CustomClass.new("abc"), CustomClass.new("123")]
|
196
196
|
end
|
197
|
+
|
198
|
+
it "should load from mongo representation of single item" do
|
199
|
+
collection = subject.from_mongo({ :name => "abc" })
|
200
|
+
collection.should be_a(subject)
|
201
|
+
collection.should == [CustomClass.new("abc")]
|
202
|
+
end
|
197
203
|
end
|
198
204
|
end
|
199
205
|
|
@@ -249,6 +255,21 @@ module MongoModel
|
|
249
255
|
it "should include the elements in the collection in the embedded documents list" do
|
250
256
|
subject.embedded_documents.should include(embedded2, embedded3)
|
251
257
|
end
|
258
|
+
|
259
|
+
it "should cast items to embedded document class when assigning array of hashes" do
|
260
|
+
subject.embedded_collection = [ { :number => 5 }, { :number => 99 } ]
|
261
|
+
subject.embedded_collection.should == [ Embedded.new(:number => 5), Embedded.new(:number => 99) ]
|
262
|
+
end
|
263
|
+
|
264
|
+
it "should cast items to embedded document class when assigning collection hash" do
|
265
|
+
subject.embedded_collection = { :_collection => true, :items => [ { :number => 49 }, { :number => 64 } ] }
|
266
|
+
subject.embedded_collection.should == [ Embedded.new(:number => 49), Embedded.new(:number => 64) ]
|
267
|
+
end
|
268
|
+
|
269
|
+
it "should cast item to embedded document class when assigning attributes hash" do
|
270
|
+
subject.embedded_collection = { :number => 8 }
|
271
|
+
subject.embedded_collection.should == [ Embedded.new(:number => 8) ]
|
272
|
+
end
|
252
273
|
end
|
253
274
|
end
|
254
275
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mongomodel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.2
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,33 +9,33 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2011-
|
12
|
+
date: 2011-10-21 00:00:00.000000000Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activesupport
|
16
|
-
requirement: &
|
16
|
+
requirement: &70171471424760 !ruby/object:Gem::Requirement
|
17
17
|
none: false
|
18
18
|
requirements:
|
19
19
|
- - ~>
|
20
20
|
- !ruby/object:Gem::Version
|
21
|
-
version: '3.
|
21
|
+
version: '3.1'
|
22
22
|
type: :runtime
|
23
23
|
prerelease: false
|
24
|
-
version_requirements: *
|
24
|
+
version_requirements: *70171471424760
|
25
25
|
- !ruby/object:Gem::Dependency
|
26
26
|
name: activemodel
|
27
|
-
requirement: &
|
27
|
+
requirement: &70171471423920 !ruby/object:Gem::Requirement
|
28
28
|
none: false
|
29
29
|
requirements:
|
30
30
|
- - ~>
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '3.
|
32
|
+
version: '3.1'
|
33
33
|
type: :runtime
|
34
34
|
prerelease: false
|
35
|
-
version_requirements: *
|
35
|
+
version_requirements: *70171471423920
|
36
36
|
- !ruby/object:Gem::Dependency
|
37
37
|
name: mongo
|
38
|
-
requirement: &
|
38
|
+
requirement: &70171471423300 !ruby/object:Gem::Requirement
|
39
39
|
none: false
|
40
40
|
requirements:
|
41
41
|
- - ~>
|
@@ -43,10 +43,10 @@ dependencies:
|
|
43
43
|
version: '1.4'
|
44
44
|
type: :runtime
|
45
45
|
prerelease: false
|
46
|
-
version_requirements: *
|
46
|
+
version_requirements: *70171471423300
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: will_paginate
|
49
|
-
requirement: &
|
49
|
+
requirement: &70171471422520 !ruby/object:Gem::Requirement
|
50
50
|
none: false
|
51
51
|
requirements:
|
52
52
|
- - ~>
|
@@ -54,10 +54,10 @@ dependencies:
|
|
54
54
|
version: 2.3.15
|
55
55
|
type: :runtime
|
56
56
|
prerelease: false
|
57
|
-
version_requirements: *
|
57
|
+
version_requirements: *70171471422520
|
58
58
|
- !ruby/object:Gem::Dependency
|
59
59
|
name: bundler
|
60
|
-
requirement: &
|
60
|
+
requirement: &70171471421740 !ruby/object:Gem::Requirement
|
61
61
|
none: false
|
62
62
|
requirements:
|
63
63
|
- - ! '>='
|
@@ -65,10 +65,10 @@ dependencies:
|
|
65
65
|
version: 1.0.0
|
66
66
|
type: :development
|
67
67
|
prerelease: false
|
68
|
-
version_requirements: *
|
68
|
+
version_requirements: *70171471421740
|
69
69
|
- !ruby/object:Gem::Dependency
|
70
70
|
name: rspec
|
71
|
-
requirement: &
|
71
|
+
requirement: &70171471420620 !ruby/object:Gem::Requirement
|
72
72
|
none: false
|
73
73
|
requirements:
|
74
74
|
- - ~>
|
@@ -76,7 +76,18 @@ dependencies:
|
|
76
76
|
version: 2.6.0
|
77
77
|
type: :development
|
78
78
|
prerelease: false
|
79
|
-
version_requirements: *
|
79
|
+
version_requirements: *70171471420620
|
80
|
+
- !ruby/object:Gem::Dependency
|
81
|
+
name: guard-rspec
|
82
|
+
requirement: &70171471419380 !ruby/object:Gem::Requirement
|
83
|
+
none: false
|
84
|
+
requirements:
|
85
|
+
- - ~>
|
86
|
+
- !ruby/object:Gem::Version
|
87
|
+
version: 0.5.0
|
88
|
+
type: :development
|
89
|
+
prerelease: false
|
90
|
+
version_requirements: *70171471419380
|
80
91
|
description: MongoModel is a MongoDB ORM for Ruby/Rails similar to ActiveRecord and
|
81
92
|
DataMapper.
|
82
93
|
email:
|
@@ -88,13 +99,11 @@ files:
|
|
88
99
|
- .gitignore
|
89
100
|
- Appraisals
|
90
101
|
- Gemfile
|
102
|
+
- Guardfile
|
91
103
|
- LICENSE
|
92
104
|
- README.md
|
93
105
|
- Rakefile
|
94
|
-
- autotest/discover.rb
|
95
106
|
- bin/console
|
96
|
-
- gemfiles/rails-3.0.gemfile
|
97
|
-
- gemfiles/rails-3.0.gemfile.lock
|
98
107
|
- gemfiles/rails-3.1-edge.gemfile
|
99
108
|
- gemfiles/rails-3.1-edge.gemfile.lock
|
100
109
|
- gemfiles/rails-3.1-latest.gemfile
|
@@ -120,6 +129,7 @@ files:
|
|
120
129
|
- lib/mongomodel/concerns/attribute_methods/before_type_cast.rb
|
121
130
|
- lib/mongomodel/concerns/attribute_methods/dirty.rb
|
122
131
|
- lib/mongomodel/concerns/attribute_methods/multi_parameter_assignment.rb
|
132
|
+
- lib/mongomodel/concerns/attribute_methods/nested.rb
|
123
133
|
- lib/mongomodel/concerns/attribute_methods/protected.rb
|
124
134
|
- lib/mongomodel/concerns/attribute_methods/query.rb
|
125
135
|
- lib/mongomodel/concerns/attribute_methods/read.rb
|
@@ -200,6 +210,7 @@ files:
|
|
200
210
|
- spec/mongomodel/concerns/attribute_methods/before_type_cast_spec.rb
|
201
211
|
- spec/mongomodel/concerns/attribute_methods/dirty_spec.rb
|
202
212
|
- spec/mongomodel/concerns/attribute_methods/multi_parameter_assignment_spec.rb
|
213
|
+
- spec/mongomodel/concerns/attribute_methods/nested_spec.rb
|
203
214
|
- spec/mongomodel/concerns/attribute_methods/protected_spec.rb
|
204
215
|
- spec/mongomodel/concerns/attribute_methods/query_spec.rb
|
205
216
|
- spec/mongomodel/concerns/attribute_methods/read_spec.rb
|
@@ -240,6 +251,7 @@ files:
|
|
240
251
|
- spec/support/helpers/define_class.rb
|
241
252
|
- spec/support/helpers/document_finder_stubs.rb
|
242
253
|
- spec/support/helpers/specs_for.rb
|
254
|
+
- spec/support/helpers/validations.rb
|
243
255
|
- spec/support/matchers/be_a_subclass_of.rb
|
244
256
|
- spec/support/matchers/be_truthy.rb
|
245
257
|
- spec/support/matchers/find_with.rb
|
@@ -260,7 +272,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
260
272
|
version: '0'
|
261
273
|
segments:
|
262
274
|
- 0
|
263
|
-
hash:
|
275
|
+
hash: 3076200504632961352
|
264
276
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
265
277
|
none: false
|
266
278
|
requirements:
|
@@ -269,7 +281,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
269
281
|
version: 1.3.6
|
270
282
|
requirements: []
|
271
283
|
rubyforge_project: mongomodel
|
272
|
-
rubygems_version: 1.8.
|
284
|
+
rubygems_version: 1.8.6
|
273
285
|
signing_key:
|
274
286
|
specification_version: 3
|
275
287
|
summary: MongoDB ORM for Ruby/Rails
|
data/autotest/discover.rb
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
Autotest.add_discovery { "rspec" }
|
data/gemfiles/rails-3.0.gemfile
DELETED
@@ -1,75 +0,0 @@
|
|
1
|
-
PATH
|
2
|
-
remote: /Users/sam/Scratch/mongomodel
|
3
|
-
specs:
|
4
|
-
mongomodel (0.4.0)
|
5
|
-
activemodel (~> 3.0)
|
6
|
-
activesupport (~> 3.0)
|
7
|
-
mongo (~> 1.4)
|
8
|
-
will_paginate (~> 2.3.15)
|
9
|
-
|
10
|
-
GEM
|
11
|
-
remote: http://rubygems.org/
|
12
|
-
specs:
|
13
|
-
activemodel (3.0.10)
|
14
|
-
activesupport (= 3.0.10)
|
15
|
-
builder (~> 2.1.2)
|
16
|
-
i18n (~> 0.5.0)
|
17
|
-
activesupport (3.0.10)
|
18
|
-
appraisal (0.3.6)
|
19
|
-
aruba (~> 0.4.2)
|
20
|
-
bundler
|
21
|
-
rake
|
22
|
-
aruba (0.4.3)
|
23
|
-
bcat (>= 0.6.1)
|
24
|
-
childprocess (>= 0.1.9)
|
25
|
-
cucumber (>= 0.10.7)
|
26
|
-
rdiscount (>= 1.6.8)
|
27
|
-
rspec (>= 2.6.0)
|
28
|
-
bcat (0.6.1)
|
29
|
-
rack (~> 1.0)
|
30
|
-
bson (1.4.0)
|
31
|
-
bson_ext (1.4.0)
|
32
|
-
builder (2.1.2)
|
33
|
-
childprocess (0.1.9)
|
34
|
-
ffi (~> 1.0.6)
|
35
|
-
cucumber (1.0.0)
|
36
|
-
builder (>= 2.1.2)
|
37
|
-
diff-lcs (>= 1.1.2)
|
38
|
-
gherkin (~> 2.4.1)
|
39
|
-
json (>= 1.4.6)
|
40
|
-
term-ansicolor (>= 1.0.5)
|
41
|
-
diff-lcs (1.1.2)
|
42
|
-
ffi (1.0.9)
|
43
|
-
gherkin (2.4.1)
|
44
|
-
json (>= 1.4.6)
|
45
|
-
i18n (0.5.0)
|
46
|
-
json (1.5.3)
|
47
|
-
mongo (1.4.0)
|
48
|
-
bson (= 1.4.0)
|
49
|
-
rack (1.3.0)
|
50
|
-
rake (0.9.2)
|
51
|
-
rdiscount (1.6.8)
|
52
|
-
rspec (2.6.0)
|
53
|
-
rspec-core (~> 2.6.0)
|
54
|
-
rspec-expectations (~> 2.6.0)
|
55
|
-
rspec-mocks (~> 2.6.0)
|
56
|
-
rspec-core (2.6.4)
|
57
|
-
rspec-expectations (2.6.0)
|
58
|
-
diff-lcs (~> 1.1.2)
|
59
|
-
rspec-mocks (2.6.0)
|
60
|
-
term-ansicolor (1.0.5)
|
61
|
-
tzinfo (0.3.29)
|
62
|
-
will_paginate (2.3.16)
|
63
|
-
|
64
|
-
PLATFORMS
|
65
|
-
ruby
|
66
|
-
|
67
|
-
DEPENDENCIES
|
68
|
-
activemodel (= 3.0.10)
|
69
|
-
activesupport (= 3.0.10)
|
70
|
-
appraisal (~> 0.3.6)
|
71
|
-
bson_ext (~> 1.4)
|
72
|
-
bundler (>= 1.0.0)
|
73
|
-
mongomodel!
|
74
|
-
rspec (~> 2.6.0)
|
75
|
-
tzinfo
|