crnixon-mongomapper 0.2.0 → 0.3.4

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 (68) hide show
  1. data/.gitignore +1 -0
  2. data/History +48 -0
  3. data/README.rdoc +5 -3
  4. data/Rakefile +6 -4
  5. data/VERSION +1 -1
  6. data/bin/mmconsole +56 -0
  7. data/lib/mongomapper.rb +29 -18
  8. data/lib/mongomapper/associations.rb +53 -38
  9. data/lib/mongomapper/associations/base.rb +53 -20
  10. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -0
  11. data/lib/mongomapper/associations/belongs_to_proxy.rb +10 -14
  12. data/lib/mongomapper/associations/many_documents_as_proxy.rb +27 -0
  13. data/lib/mongomapper/associations/many_documents_proxy.rb +103 -0
  14. data/lib/mongomapper/associations/many_embedded_polymorphic_proxy.rb +33 -0
  15. data/lib/mongomapper/associations/{has_many_embedded_proxy.rb → many_embedded_proxy.rb} +6 -8
  16. data/lib/mongomapper/associations/many_polymorphic_proxy.rb +11 -0
  17. data/lib/mongomapper/associations/{array_proxy.rb → many_proxy.rb} +1 -1
  18. data/lib/mongomapper/associations/proxy.rb +24 -21
  19. data/lib/mongomapper/callbacks.rb +1 -1
  20. data/lib/mongomapper/document.rb +160 -74
  21. data/lib/mongomapper/dynamic_finder.rb +38 -0
  22. data/lib/mongomapper/embedded_document.rb +154 -105
  23. data/lib/mongomapper/finder_options.rb +11 -7
  24. data/lib/mongomapper/key.rb +15 -21
  25. data/lib/mongomapper/pagination.rb +52 -0
  26. data/lib/mongomapper/rails_compatibility/document.rb +15 -0
  27. data/lib/mongomapper/rails_compatibility/embedded_document.rb +25 -0
  28. data/lib/mongomapper/serialization.rb +1 -1
  29. data/lib/mongomapper/serializers/json_serializer.rb +15 -0
  30. data/lib/mongomapper/support.rb +30 -0
  31. data/mongomapper.gemspec +87 -46
  32. data/test/NOTE_ON_TESTING +1 -0
  33. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -0
  34. data/test/functional/associations/test_belongs_to_proxy.rb +45 -0
  35. data/test/functional/associations/test_many_documents_as_proxy.rb +253 -0
  36. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +131 -0
  37. data/test/functional/associations/test_many_embedded_proxy.rb +106 -0
  38. data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -0
  39. data/test/functional/associations/test_many_proxy.rb +295 -0
  40. data/test/functional/test_associations.rb +47 -0
  41. data/test/{test_callbacks.rb → functional/test_callbacks.rb} +2 -1
  42. data/test/functional/test_document.rb +952 -0
  43. data/test/functional/test_pagination.rb +81 -0
  44. data/test/functional/test_rails_compatibility.rb +30 -0
  45. data/test/functional/test_validations.rb +172 -0
  46. data/test/models.rb +169 -0
  47. data/test/test_helper.rb +7 -2
  48. data/test/unit/serializers/test_json_serializer.rb +189 -0
  49. data/test/unit/test_association_base.rb +144 -0
  50. data/test/unit/test_document.rb +123 -0
  51. data/test/unit/test_embedded_document.rb +526 -0
  52. data/test/{test_finder_options.rb → unit/test_finder_options.rb} +36 -1
  53. data/test/{test_key.rb → unit/test_key.rb} +59 -12
  54. data/test/{test_mongomapper.rb → unit/test_mongomapper.rb} +0 -0
  55. data/test/{test_observing.rb → unit/test_observing.rb} +0 -0
  56. data/test/unit/test_pagination.rb +113 -0
  57. data/test/unit/test_rails_compatibility.rb +34 -0
  58. data/test/{test_serializations.rb → unit/test_serializations.rb} +0 -2
  59. data/test/{test_validations.rb → unit/test_validations.rb} +0 -134
  60. metadata +81 -43
  61. data/lib/mongomapper/associations/has_many_proxy.rb +0 -28
  62. data/lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb +0 -31
  63. data/lib/mongomapper/rails_compatibility.rb +0 -23
  64. data/test/serializers/test_json_serializer.rb +0 -104
  65. data/test/test_associations.rb +0 -174
  66. data/test/test_document.rb +0 -944
  67. data/test/test_embedded_document.rb +0 -253
  68. data/test/test_rails_compatibility.rb +0 -29
data/test/test_helper.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  require 'pathname'
2
+ require 'pp'
2
3
  require 'rubygems'
3
4
  require 'test/unit'
4
5
  require 'shoulda'
5
6
 
6
- gem 'mocha', '~> 0.9.4'
7
+ gem 'mocha', '0.9.4'
7
8
  gem 'jnunemaker-matchy', '0.4.0'
8
9
 
9
10
  require 'matchy'
@@ -13,7 +14,11 @@ $LOAD_PATH.unshift(File.dirname(__FILE__))
13
14
  dir = (Pathname(__FILE__).dirname + '..' + 'lib').expand_path
14
15
  require dir + 'mongomapper'
15
16
 
16
- class Test::Unit::TestCase
17
+ class Test::Unit::TestCase
18
+ def clear_all_collections
19
+ MongoMapper::Document.descendants.map(&:delete_all)
20
+ end
21
+
17
22
  custom_matcher :be_nil do |receiver, matcher, args|
18
23
  matcher.positive_failure_message = "Expected #{receiver} to be nil but it wasn't"
19
24
  matcher.negative_failure_message = "Expected #{receiver} not to be nil but it was"
@@ -0,0 +1,189 @@
1
+ require 'test_helper'
2
+
3
+ class JsonSerializationTest < Test::Unit::TestCase
4
+ class Tag
5
+ include MongoMapper::EmbeddedDocument
6
+ key :name, String
7
+ end
8
+
9
+ class Contact
10
+ include MongoMapper::Document
11
+ key :name, String
12
+ key :age, Integer
13
+ key :created_at, Time
14
+ key :awesome, Boolean
15
+ key :preferences, Hash
16
+
17
+ many :tags, :class_name => 'JsonSerializationTest::Tag'
18
+ end
19
+
20
+ def setup
21
+ Contact.include_root_in_json = false
22
+ @contact = Contact.new(
23
+ :name => 'Konata Izumi',
24
+ :age => 16,
25
+ :created_at => Time.utc(2006, 8, 1),
26
+ :awesome => true,
27
+ :preferences => { :shows => 'anime' }
28
+ )
29
+ end
30
+
31
+ should "include demodulized root" do
32
+ Contact.include_root_in_json = true
33
+ assert_match %r{^\{"contact": \{}, @contact.to_json
34
+ end
35
+
36
+ should "encode all encodable attributes" do
37
+ json = @contact.to_json
38
+
39
+ assert_no_match %r{"_id"}, json
40
+ assert_match %r{"name":"Konata Izumi"}, json
41
+ assert_match %r{"age":16}, json
42
+ assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
43
+ assert_match %r{"awesome":true}, json
44
+ assert_match %r{"preferences":\{"shows":"anime"\}}, json
45
+ end
46
+
47
+ should "allow attribute filtering with only" do
48
+ json = @contact.to_json(:only => [:name, :age])
49
+
50
+ assert_no_match %r{"_id"}, json
51
+ assert_match %r{"name":"Konata Izumi"}, json
52
+ assert_match %r{"age":16}, json
53
+ assert_no_match %r{"awesome"}, json
54
+ assert_no_match %r{"created_at"}, json
55
+ assert_no_match %r{"preferences"}, json
56
+ end
57
+
58
+ should "allow attribute filtering with except" do
59
+ json = @contact.to_json(:except => [:name, :age])
60
+
61
+ assert_no_match %r{"_id"}, json
62
+ assert_no_match %r{"name"}, json
63
+ assert_no_match %r{"age"}, json
64
+ assert_match %r{"awesome"}, json
65
+ assert_match %r{"created_at"}, json
66
+ assert_match %r{"preferences"}, json
67
+ end
68
+
69
+ context "_id key" do
70
+ should "not be included by default" do
71
+ json = @contact.to_json
72
+ assert_no_match %r{"_id":}, json
73
+ end
74
+
75
+ should "not be included even if :except is used" do
76
+ json = @contact.to_json(:except => :name)
77
+ assert_no_match %r{"_id":}, json
78
+ end
79
+ end
80
+
81
+ context "id method" do
82
+ setup do
83
+ def @contact.label; "Has cheezburger"; end
84
+ def @contact.favorite_quote; "Constraints are liberating"; end
85
+ end
86
+
87
+ should "be included by default" do
88
+ json = @contact.to_json
89
+ assert_match %r{"id"}, json
90
+ end
91
+
92
+ should "be included when single method included" do
93
+ json = @contact.to_json(:methods => :label)
94
+ assert_match %r{"id"}, json
95
+ assert_match %r{"label":"Has cheezburger"}, json
96
+ assert_match %r{"name":"Konata Izumi"}, json
97
+ assert_no_match %r{"favorite_quote":"Constraints are liberating"}, json
98
+ end
99
+
100
+ should "be included when multiple methods included" do
101
+ json = @contact.to_json(:methods => [:label, :favorite_quote])
102
+ assert_match %r{"id"}, json
103
+ assert_match %r{"label":"Has cheezburger"}, json
104
+ assert_match %r{"favorite_quote":"Constraints are liberating"}, json
105
+ assert_match %r{"name":"Konata Izumi"}, json
106
+ end
107
+
108
+ should "not be included if :only is present" do
109
+ json = @contact.to_json(:only => :name)
110
+ assert_no_match %r{"id":}, json
111
+ end
112
+ end
113
+
114
+ context "including methods" do
115
+ setup do
116
+ def @contact.label; "Has cheezburger"; end
117
+ def @contact.favorite_quote; "Constraints are liberating"; end
118
+ end
119
+
120
+ should "include single method" do
121
+ json = @contact.to_json(:methods => :label)
122
+ assert_match %r{"label":"Has cheezburger"}, json
123
+ end
124
+
125
+ should "include multiple methods" do
126
+ json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
127
+ assert_match %r{"label":"Has cheezburger"}, json
128
+ assert_match %r{"favorite_quote":"Constraints are liberating"}, json
129
+ assert_match %r{"name":"Konata Izumi"}, json
130
+ assert_no_match %r{"age":16}, json
131
+ assert_no_match %r{"awesome"}, json
132
+ assert_no_match %r{"created_at"}, json
133
+ assert_no_match %r{"preferences"}, json
134
+ end
135
+ end
136
+
137
+ context "array of records" do
138
+ setup do
139
+ @contacts = [
140
+ Contact.new(:name => 'David', :age => 39),
141
+ Contact.new(:name => 'Mary', :age => 14)
142
+ ]
143
+ end
144
+
145
+ should "allow attribute filtering with only" do
146
+ json = @contacts.to_json(:only => :name)
147
+ assert_match %r{\{"name":"David"\}}, json
148
+ assert_match %r{\{"name":"Mary"\}}, json
149
+ end
150
+
151
+ should "allow attribute filtering with except" do
152
+ json = @contacts.to_json(:except => [:name, :preferences, :awesome, :created_at, :updated_at])
153
+ assert_match %r{"age":39}, json
154
+ assert_match %r{"age":14}, json
155
+ assert_no_match %r{"name":}, json
156
+ assert_no_match %r{"preferences":}, json
157
+ assert_no_match %r{"awesome":}, json
158
+ assert_no_match %r{"created_at":}, json
159
+ assert_no_match %r{"updated_at":}, json
160
+ end
161
+ end
162
+
163
+ should "allow options for hash of records" do
164
+ contacts = {
165
+ 1 => Contact.new(:name => 'David', :age => 39),
166
+ 2 => Contact.new(:name => 'Mary', :age => 14)
167
+ }
168
+ json = contacts.to_json(:only => [1, :name])
169
+ assert_match %r{"1":}, json
170
+ assert_match %r{\{"name":"David"\}}, json
171
+ assert_no_match %r{"2":}, json
172
+ end
173
+
174
+ should "include embedded attributes" do
175
+ contact = Contact.new(:name => 'John', :age => 27)
176
+ contact.tags = [Tag.new(:name => 'awesome'), Tag.new(:name => 'ruby')]
177
+ json = contact.to_json
178
+ assert_match %r{"tags":}, json
179
+ assert_match %r{"name":"awesome"}, json
180
+ assert_match %r{"name":"ruby"}, json
181
+ end
182
+
183
+ should "include dynamic attributes" do
184
+ contact = Contact.new(:name => 'John', :age => 27, :foo => 'bar')
185
+ contact['smell'] = 'stinky'
186
+ json = contact.to_json
187
+ assert_match %r{"smell":"stinky"}, json
188
+ end
189
+ end
@@ -0,0 +1,144 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class FooMonster; end
5
+
6
+ class AssociationBaseTest < Test::Unit::TestCase
7
+ include MongoMapper::Associations
8
+
9
+ should "initialize with type and name" do
10
+ base = Base.new(:many, :foos)
11
+ base.type.should == :many
12
+ base.name.should == :foos
13
+ end
14
+
15
+ should "also allow options when initializing" do
16
+ base = Base.new(:many, :foos, :polymorphic => true)
17
+ base.options[:polymorphic].should be_true
18
+ end
19
+
20
+ context "class_name" do
21
+ should "work for belongs_to" do
22
+ Base.new(:belongs_to, :user).class_name.should == 'User'
23
+ end
24
+
25
+ should "work for many" do
26
+ Base.new(:many, :smart_people).class_name.should == 'SmartPerson'
27
+ end
28
+
29
+ should "be changeable using class_name option" do
30
+ base = Base.new(:many, :smart_people, :class_name => 'IntelligentPerson')
31
+ base.class_name.should == 'IntelligentPerson'
32
+ end
33
+ end
34
+
35
+ context "klass" do
36
+ should "be class_name constantized" do
37
+ Base.new(:belongs_to, :foo_monster).klass.should == FooMonster
38
+ end
39
+ end
40
+
41
+ context "many?" do
42
+ should "be true if many" do
43
+ Base.new(:many, :foos).many?.should be_true
44
+ end
45
+
46
+ should "be false if not many" do
47
+ Base.new(:belongs_to, :foo).many?.should be_false
48
+ end
49
+ end
50
+
51
+ context "belongs_to?" do
52
+ should "be true if belongs_to" do
53
+ Base.new(:belongs_to, :foo).belongs_to?.should be_true
54
+ end
55
+
56
+ should "be false if not belongs_to" do
57
+ Base.new(:many, :foos).belongs_to?.should be_false
58
+ end
59
+ end
60
+
61
+ context "polymorphic?" do
62
+ should "be true if polymorphic" do
63
+ Base.new(:many, :foos, :polymorphic => true).polymorphic?.should be_true
64
+ end
65
+
66
+ should "be false if not polymorphic" do
67
+ Base.new(:many, :bars).polymorphic?.should be_false
68
+ end
69
+ end
70
+
71
+ context "type_key_name" do
72
+ should "be _type for many" do
73
+ Base.new(:many, :foos).type_key_name.should == '_type'
74
+ end
75
+
76
+ should "be association name _ type for belongs_to" do
77
+ Base.new(:belongs_to, :foo).type_key_name.should == 'foo_type'
78
+ end
79
+ end
80
+
81
+ context "foreign_key" do
82
+ should "default to assocation_name_id" do
83
+ base = Base.new(:belongs_to, :foo)
84
+ base.foreign_key.should == 'foo_id'
85
+ end
86
+
87
+ should "be overridable with :foreign_key option" do
88
+ base = Base.new(:belongs_to, :foo, :foreign_key => 'foobar_id')
89
+ base.foreign_key.should == 'foobar_id'
90
+ end
91
+ end
92
+
93
+ should "have ivar that is association name" do
94
+ Base.new(:belongs_to, :foo).ivar.should == '@_foo'
95
+ end
96
+
97
+ context "embeddable?" do
98
+ should "be true if class is embeddable" do
99
+ base = Base.new(:many, :medias)
100
+ base.embeddable?.should be_true
101
+ end
102
+
103
+ should "be false if class is not embeddable" do
104
+ base = Base.new(:many, :statuses)
105
+ base.embeddable?.should be_false
106
+
107
+ base = Base.new(:belongs_to, :project)
108
+ base.embeddable?.should be_false
109
+ end
110
+ end
111
+
112
+ context "proxy_class" do
113
+ should "be ManyProxy for many" do
114
+ base = Base.new(:many, :statuses)
115
+ base.proxy_class.should == ManyProxy
116
+ end
117
+
118
+ should "be ManyPolymorphicProxy for polymorphic many" do
119
+ base = Base.new(:many, :messages, :polymorphic => true)
120
+ base.proxy_class.should == ManyPolymorphicProxy
121
+ end
122
+
123
+ should "be ManyEmbeddedProxy for many embedded" do
124
+ base = Base.new(:many, :medias)
125
+ base.proxy_class.should == ManyEmbeddedProxy
126
+ end
127
+
128
+ should "be ManyEmbeddedPolymorphicProxy for polymorphic many embedded" do
129
+ base = Base.new(:many, :medias, :polymorphic => true)
130
+ base.proxy_class.should == ManyEmbeddedPolymorphicProxy
131
+ end
132
+
133
+ should "be BelongsToProxy for belongs_to" do
134
+ base = Base.new(:belongs_to, :project)
135
+ base.proxy_class.should == BelongsToProxy
136
+ end
137
+
138
+ should "be BelongsToPolymorphicProxy for polymorphic belongs_to" do
139
+ base = Base.new(:belongs_to, :target, :polymorphic => true)
140
+ base.proxy_class.should == BelongsToPolymorphicProxy
141
+ end
142
+ end
143
+
144
+ end
@@ -0,0 +1,123 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class DocumentTest < Test::Unit::TestCase
5
+ context "The Document Class" do
6
+ setup do
7
+ @document = Class.new do
8
+ include MongoMapper::Document
9
+ end
10
+ end
11
+
12
+ should "track its descendants" do
13
+ MongoMapper::Document.descendants.should include(@document)
14
+ end
15
+
16
+ should "use default database by default" do
17
+ @document.database.should == MongoMapper.database
18
+ end
19
+
20
+ should "have a connection" do
21
+ @document.connection.should be_instance_of(XGen::Mongo::Driver::Mongo)
22
+ end
23
+
24
+ should "allow setting different connection without affecting the default" do
25
+ conn = XGen::Mongo::Driver::Mongo.new
26
+ @document.connection conn
27
+ @document.connection.should == conn
28
+ @document.connection.should_not == MongoMapper.connection
29
+ end
30
+
31
+ should "allow setting a different database without affecting the default" do
32
+ @document.database AlternateDatabase
33
+ @document.database.name.should == AlternateDatabase
34
+
35
+ another_document = Class.new do
36
+ include MongoMapper::Document
37
+ end
38
+ another_document.database.should == MongoMapper.database
39
+ end
40
+
41
+ should "default collection name to class name tableized" do
42
+ class Item
43
+ include MongoMapper::Document
44
+ end
45
+
46
+ Item.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
47
+ Item.collection.name.should == 'items'
48
+ end
49
+
50
+ should "allow setting the collection name" do
51
+ @document.collection('foobar')
52
+ @document.collection.should be_instance_of(XGen::Mongo::Driver::Collection)
53
+ @document.collection.name.should == 'foobar'
54
+ end
55
+ end # Document class
56
+
57
+ context "Documents that inherit from other documents" do
58
+ should "default collection to inherited class" do
59
+ Message.collection.name.should == 'messages'
60
+ Enter.collection.name.should == 'messages'
61
+ Exit.collection.name.should == 'messages'
62
+ Chat.collection.name.should == 'messages'
63
+ end
64
+
65
+ should "track subclasses" do
66
+ Message.subclasses.should == [Enter, Exit, Chat]
67
+ end
68
+ end
69
+
70
+ context "An instance of a document" do
71
+ setup do
72
+ @document = Class.new do
73
+ include MongoMapper::Document
74
+
75
+ key :name, String
76
+ key :age, Integer
77
+ end
78
+ @document.collection.clear
79
+ end
80
+
81
+ should "have access to the class's collection" do
82
+ doc = @document.new
83
+ doc.collection.should == @document.collection
84
+ end
85
+
86
+ should "use default values if defined for keys" do
87
+ @document.key :active, Boolean, :default => true
88
+
89
+ @document.new.active.should be_true
90
+ @document.new(:active => false).active.should be_false
91
+ end
92
+
93
+ context "new?" do
94
+ should "be true if no id" do
95
+ @document.new.new?.should be_true
96
+ end
97
+
98
+ should "be true if id but using custom id and not saved yet" do
99
+ doc = @document.new
100
+ doc.id = '1234'
101
+ doc.new?.should be_true
102
+ end
103
+ end
104
+
105
+ context "equality" do
106
+ should "be equal if id and class are the same" do
107
+ (@document.new('_id' => 1) == @document.new('_id' => 1)).should be(true)
108
+ end
109
+
110
+ should "not be equal if class same but id different" do
111
+ (@document.new('_id' => 1) == @document.new('_id' => 2)).should be(false)
112
+ end
113
+
114
+ should "not be equal if id same but class different" do
115
+ @another_document = Class.new do
116
+ include MongoMapper::Document
117
+ end
118
+
119
+ (@document.new('_id' => 1) == @another_document.new('_id' => 1)).should be(false)
120
+ end
121
+ end
122
+ end # instance of a document
123
+ end # DocumentTest