fcoury-mongomapper 0.2.0

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 (42) hide show
  1. data/.gitignore +7 -0
  2. data/History +30 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +39 -0
  5. data/Rakefile +71 -0
  6. data/VERSION +1 -0
  7. data/lib/mongomapper.rb +70 -0
  8. data/lib/mongomapper/associations.rb +69 -0
  9. data/lib/mongomapper/associations/array_proxy.rb +6 -0
  10. data/lib/mongomapper/associations/base.rb +54 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +26 -0
  12. data/lib/mongomapper/associations/has_many_embedded_proxy.rb +19 -0
  13. data/lib/mongomapper/associations/has_many_proxy.rb +29 -0
  14. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +31 -0
  15. data/lib/mongomapper/associations/proxy.rb +66 -0
  16. data/lib/mongomapper/callbacks.rb +106 -0
  17. data/lib/mongomapper/document.rb +276 -0
  18. data/lib/mongomapper/document_rails_compatibility.rb +13 -0
  19. data/lib/mongomapper/embedded_document.rb +248 -0
  20. data/lib/mongomapper/embedded_document_rails_compatibility.rb +22 -0
  21. data/lib/mongomapper/finder_options.rb +81 -0
  22. data/lib/mongomapper/key.rb +82 -0
  23. data/lib/mongomapper/observing.rb +50 -0
  24. data/lib/mongomapper/save_with_validation.rb +19 -0
  25. data/lib/mongomapper/serialization.rb +55 -0
  26. data/lib/mongomapper/serializers/json_serializer.rb +77 -0
  27. data/lib/mongomapper/validations.rb +47 -0
  28. data/mongomapper.gemspec +105 -0
  29. data/test/serializers/test_json_serializer.rb +104 -0
  30. data/test/test_associations.rb +444 -0
  31. data/test/test_callbacks.rb +84 -0
  32. data/test/test_document.rb +1002 -0
  33. data/test/test_embedded_document.rb +253 -0
  34. data/test/test_finder_options.rb +148 -0
  35. data/test/test_helper.rb +62 -0
  36. data/test/test_key.rb +200 -0
  37. data/test/test_mongomapper.rb +28 -0
  38. data/test/test_observing.rb +101 -0
  39. data/test/test_rails_compatibility.rb +73 -0
  40. data/test/test_serializations.rb +54 -0
  41. data/test/test_validations.rb +409 -0
  42. metadata +155 -0
data/test/test_key.rb ADDED
@@ -0,0 +1,200 @@
1
+ require 'test_helper'
2
+
3
+ class Address
4
+ include MongoMapper::EmbeddedDocument
5
+
6
+ key :address, String
7
+ key :city, String
8
+ key :state, String
9
+ key :zip, Integer
10
+ end
11
+
12
+ class KeyTest < Test::Unit::TestCase
13
+ include MongoMapper
14
+
15
+ context "The Key Class" do
16
+ should "have the native types defined" do
17
+ Key::NativeTypes.should == [String, Float, Time, Integer, Boolean, Array, Hash, Ref]
18
+ end
19
+ end
20
+
21
+ context "Initializing a new key" do
22
+ should "allow setting the name" do
23
+ Key.new(:foo, String).name.should == 'foo'
24
+ end
25
+
26
+ should "allow setting the type" do
27
+ Key.new(:foo, Integer).type.should be(Integer)
28
+ end
29
+
30
+ should "allow setting options" do
31
+ Key.new(:foo, Integer, :required => true).options[:required].should be(true)
32
+ end
33
+
34
+ should "symbolize option keys" do
35
+ Key.new(:foo, Integer, 'required' => true).options[:required].should be(true)
36
+ end
37
+ end
38
+
39
+ context "A key" do
40
+ should "be equal to another key with same name and type" do
41
+ Key.new(:name, String).should == Key.new(:name, String)
42
+ end
43
+
44
+ should "not be equal to another key with different name" do
45
+ Key.new(:name, String).should_not == Key.new(:foo, String)
46
+ end
47
+
48
+ should "not be equal to another key with different type" do
49
+ Key.new(:name, String).should_not == Key.new(:name, Integer)
50
+ end
51
+
52
+ should "know if it is native" do
53
+ Key.new(:name, String).native?.should be_true
54
+ end
55
+
56
+ should "know if it is not native" do
57
+ klass = Class.new
58
+ Key.new(:name, klass).native?.should be_false
59
+ end
60
+
61
+ should "know if it is a embedded_document" do
62
+ klass = Class.new do
63
+ include MongoMapper::EmbeddedDocument
64
+ end
65
+ Key.new(:name, klass).embedded_document?.should be_true
66
+ end
67
+
68
+ should "know if it is not a embedded_document" do
69
+ Key.new(:name, String).embedded_document?.should be_false
70
+ end
71
+ end
72
+
73
+ context "setting a value" do
74
+ should "correctly typecast Strings" do
75
+ key = Key.new(:foo, String)
76
+ [21, '21'].each do |a|
77
+ key.set(a).should == '21'
78
+ end
79
+ end
80
+
81
+ should "correctly typecast Integers" do
82
+ key = Key.new(:foo, Integer)
83
+ [21, 21.0, '21'].each do |a|
84
+ key.set(a).should == 21
85
+ end
86
+ end
87
+
88
+ should "correctly typecast Floats" do
89
+ key = Key.new(:foo, Float)
90
+ [21, 21.0, '21'].each do |a|
91
+ key.set(a).should == 21.0
92
+ end
93
+ end
94
+
95
+ should "correctly typecast Times" do
96
+ key = Key.new(:foo, Time)
97
+ key.set('2000-01-01 01:01:01.123456').should == Time.local(2000, 1, 1, 1, 1, 1, 123456)
98
+ end
99
+
100
+ should_eventually "correctly typecast Dates" do
101
+ key = Key.new(:foo, Date)
102
+ key.set('2000-01-01').should == Date.new(2000, 1, 1)
103
+ end
104
+
105
+ should "correctly typecast Boolean" do
106
+ key = Key.new(:foo, Boolean)
107
+ ['false', false, 'f', '0', 0].each do |b|
108
+ key.set(b).should == false
109
+ end
110
+
111
+ ['true', true, 't', '1', 1].each do |b|
112
+ key.set(b).should == true
113
+ end
114
+ end
115
+
116
+ should "correctly typecast Array" do
117
+ key = Key.new(:foo, Array)
118
+ key.set([1,2,3,4]).should == [1,2,3,4]
119
+ key.set({'1' => '2', '3' => '4'}).should == [['1', '2'], ['3', '4']]
120
+ key.set('1').should == ['1']
121
+ end
122
+
123
+ should "correctly typecast Hash using indifferent access" do
124
+ key = Key.new(:foo, Hash)
125
+ key.set(:foo => 'bar')[:foo].should == 'bar'
126
+ key.set(:foo => 'bar')['foo'].should == 'bar'
127
+ key.set(:foo => {:bar => 'baz'})[:foo][:bar].should == 'baz'
128
+ key.set(:foo => {:bar => 'baz'})['foo']['bar'].should == 'baz'
129
+ end
130
+ end
131
+
132
+ context "getting a value" do
133
+ should "work" do
134
+ key = Key.new(:foo, String)
135
+ key.get('bar').should == 'bar'
136
+ end
137
+
138
+ context "for a key with a default value set" do
139
+ setup do
140
+ @key = Key.new(:foo, String, :default => 'baz')
141
+ end
142
+
143
+ should "return default value if value nil" do
144
+ @key.get(nil).should == 'baz'
145
+ end
146
+
147
+ should "return value if not blank" do
148
+ @key.get('foobar').should == 'foobar'
149
+ end
150
+ end
151
+
152
+ context "for a boolean key" do
153
+ should "allow setting default to false" do
154
+ Key.new(:active, Boolean, :default => false).get(nil).should be_false
155
+ end
156
+
157
+ should "allow setting default to true" do
158
+ Key.new(:active, Boolean, :default => true).get(nil).should be_true
159
+ end
160
+ end
161
+
162
+ context "for an array" do
163
+ should "return array" do
164
+ key = Key.new(:foo, Array)
165
+ key.get([1,2]).should == [1,2]
166
+ end
167
+
168
+ should "default to empty array" do
169
+ key = Key.new(:foo, Array)
170
+ key.get(nil).should == []
171
+ end
172
+ end
173
+
174
+ context "for a hash" do
175
+ should "default to empty hash" do
176
+ key = Key.new(:foo, Hash)
177
+ key.get(nil).should == {}
178
+ end
179
+
180
+ should "use hash with indifferent access" do
181
+ key = Key.new(:foo, Hash)
182
+ key.get({:foo => 'bar'})['foo'].should == 'bar'
183
+ key.get({:foo => 'bar'})[:foo].should == 'bar'
184
+ end
185
+ end
186
+
187
+ context "for a embedded_document" do
188
+ should "default to nil" do
189
+ key = Key.new(:foo, Address)
190
+ key.get(nil).should be_nil
191
+ end
192
+
193
+ should "return instance if instance" do
194
+ address = Address.new(:city => 'South Bend', :state => 'IN', :zip => 46544)
195
+ key = Key.new(:foo, Address)
196
+ key.get(address).should == address
197
+ end
198
+ end
199
+ end
200
+ end # KeyTest
@@ -0,0 +1,28 @@
1
+ require 'test_helper'
2
+
3
+ class Address; end
4
+
5
+ class MongoMapperTest < Test::Unit::TestCase
6
+ should "be able to write and read connection" do
7
+ conn = XGen::Mongo::Driver::Mongo.new
8
+ MongoMapper.connection = conn
9
+ MongoMapper.connection.should == conn
10
+ end
11
+
12
+ should "default connection to new mongo ruby driver" do
13
+ MongoMapper.connection = nil
14
+ MongoMapper.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
15
+ end
16
+
17
+ should "be able to write and read default database" do
18
+ MongoMapper.database = DefaultDatabase
19
+ MongoMapper.database.should be_instance_of(XGen::Mongo::Driver::DB)
20
+ MongoMapper.database.name.should == DefaultDatabase
21
+ end
22
+
23
+ should "have document not found error" do
24
+ lambda {
25
+ MongoMapper::DocumentNotFound
26
+ }.should_not raise_error
27
+ end
28
+ end
@@ -0,0 +1,101 @@
1
+ require 'test_helper'
2
+
3
+ class Comment
4
+ include MongoMapper::Document
5
+
6
+ key :name, String
7
+ key :body, String
8
+
9
+ attr_accessor :callers
10
+ before_validation :record_callers
11
+
12
+ def after_validation
13
+ record_callers
14
+ end
15
+
16
+ def record_callers
17
+ callers << self.class if callers
18
+ end
19
+ end
20
+
21
+ class Article
22
+ include MongoMapper::Document
23
+
24
+ key :title, String
25
+ key :body, String
26
+ end
27
+
28
+ class CommentObserver < MongoMapper::Observer
29
+ attr_accessor :callers
30
+
31
+ def after_validation(model)
32
+ callers << self.class if callers
33
+ end
34
+ end
35
+
36
+ class AuditObserver < MongoMapper::Observer
37
+ observe Article, Comment
38
+ attr_reader :document
39
+
40
+ def after_validation(document)
41
+ @document = document
42
+ end
43
+ end
44
+
45
+ class GlobalObserver < MongoMapper::Observer
46
+ observe Article, Comment
47
+ attr_reader :document
48
+
49
+ def before_save(document)
50
+ @document = document
51
+ end
52
+ end
53
+
54
+ class NonAutomaticObserver < MongoMapper::Observer
55
+ observe Comment
56
+ attr_reader :comment
57
+
58
+ def after_validation(comment)
59
+ @comment = comment
60
+ end
61
+ end
62
+
63
+ class ObserverTest < Test::Unit::TestCase
64
+ should "fire model callbacks before observer" do
65
+ callers = []
66
+ comment = Comment.new
67
+ comment.callers = callers
68
+
69
+ CommentObserver.instance.callers = callers
70
+
71
+ comment.valid?
72
+ callers.should == [Comment, Comment, CommentObserver]
73
+ end
74
+
75
+ should "automatically observe model based on name when possible" do
76
+ CommentObserver.observed_class.should == Comment
77
+ end
78
+
79
+ should "be able to observe other models using observe" do
80
+ obs = NonAutomaticObserver.instance
81
+ comment = Comment.new(:name => 'John Nunemaker', :body => 'is awesome')
82
+ comment.valid?
83
+ obs.comment.name.should == 'John Nunemaker'
84
+ obs.comment.body.should == 'is awesome'
85
+ end
86
+
87
+ should "be able to observe multiple models" do
88
+ obs = AuditObserver.instance
89
+ comment = Comment.new(:name => 'Steve Smith', :body => 'is awesome')
90
+ comment.valid?
91
+
92
+ obs.document.name.should == 'Steve Smith'
93
+ obs.document.body.should == 'is awesome'
94
+
95
+ article = Article.new(:title => 'Ordered List Is Awesome', :body => 'Learn to accept it!')
96
+ article.valid?
97
+
98
+ obs.document.title.should == 'Ordered List Is Awesome'
99
+ obs.document.body.should == 'Learn to accept it!'
100
+ end
101
+ end
@@ -0,0 +1,73 @@
1
+ require 'test_helper'
2
+
3
+ class Item
4
+ include MongoMapper::EmbeddedDocument
5
+ key :for_all, String
6
+ end
7
+
8
+ class FirstItem < Item
9
+ key :first_only, String
10
+ end
11
+
12
+ class SecondItem < Item
13
+ key :second_only, String
14
+ end
15
+
16
+ class Order
17
+ include MongoMapper::Document
18
+ many :items, :polymorphic => true, :class_name => "Item"
19
+ key :order_only, String
20
+ end
21
+
22
+ class TestRailsCompatibility < Test::Unit::TestCase
23
+ def setup
24
+ @document = Class.new do
25
+ include MongoMapper::Document
26
+ end
27
+ end
28
+
29
+ context "EmbeddedDocument" do
30
+ should "have to_param that returns id" do
31
+ first_item = FirstItem.new
32
+ second_item = SecondItem.new
33
+
34
+ order = Order.create('_id' => '1234')
35
+ order.items = [
36
+ first_item,
37
+ second_item
38
+ ]
39
+ order.to_param.should == '1234'
40
+
41
+ lambda { first_item.to_param }.should raise_error
42
+ lambda { second_item.to_param }.should raise_error
43
+ end
44
+
45
+ should "have column names" do
46
+ Order.column_names.sort.should == ['_id', 'created_at', 'order_only', 'updated_at']
47
+ FirstItem.column_names.sort.should == ['first_only', 'for_all']
48
+ SecondItem.column_names.sort.should == ['for_all', 'second_only']
49
+ end
50
+ end
51
+
52
+ context "Document" do
53
+ should "have to_param that returns id" do
54
+ instance = @document.create('_id' => '1234')
55
+ instance.to_param.should == '1234'
56
+ end
57
+
58
+ should "alias new to new_record?" do
59
+ instance = @document.new
60
+ instance.new_record?.should == instance.new?
61
+ end
62
+
63
+ should "alias many to has_many" do
64
+ @document.should respond_to(:has_many)
65
+ @document.method(:has_many).should == @document.method(:many)
66
+ end
67
+
68
+ should "have column names" do
69
+ @document.key :fname, String
70
+ @document.column_names.sort.should == ['_id', 'created_at', 'fname', 'updated_at']
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,54 @@
1
+ require 'test_helper'
2
+
3
+ class SerializationTest < Test::Unit::TestCase
4
+ def setup
5
+ @document = Class.new do
6
+ include MongoMapper::EmbeddedDocument
7
+ key :name, String
8
+ key :age, Integer
9
+ key :awesome, Boolean
10
+ key :preferences, Hash
11
+ key :created_at, Time
12
+ end
13
+
14
+ @instance = @document.new(
15
+ :name => 'John Doe',
16
+ :age => 25,
17
+ :awesome => true,
18
+ :preferences => {:language => 'Ruby'},
19
+ :created_at => Time.now.change(:usec => 0)
20
+ )
21
+ end
22
+
23
+ # [:xml, :json].each do |format|
24
+ [:json].each do |format|
25
+ context format do
26
+ should "be reversable" do
27
+ serialized = @instance.send("to_#{format}")
28
+ unserialized = @document.new.send("from_#{format}", serialized)
29
+
30
+ assert_equal @instance, unserialized
31
+ end
32
+
33
+ should "allow attribute only filtering" do
34
+ serialized = @instance.send("to_#{format}", :only => [ :age, :name ])
35
+ unserialized = @document.new.send("from_#{format}", serialized)
36
+
37
+ assert_equal @instance.name, unserialized.name
38
+ assert_equal @instance.age, unserialized.age
39
+ assert_nil unserialized.awesome
40
+ assert_nil unserialized.created_at
41
+ end
42
+
43
+ should "allow attribute except filtering" do
44
+ serialized = @instance.send("to_#{format}", :except => [ :age, :name ])
45
+ unserialized = @document.new.send("from_#{format}", serialized)
46
+
47
+ assert_nil unserialized.name
48
+ assert_nil unserialized.age
49
+ assert_equal @instance.awesome, unserialized.awesome
50
+ end
51
+
52
+ end
53
+ end
54
+ end