fcoury-mongomapper 0.2.0 → 0.3.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.
data/.gitignore CHANGED
@@ -4,4 +4,3 @@ coverage
4
4
  rdoc
5
5
  pkg
6
6
  *~
7
- *.gem
data/History CHANGED
@@ -1,8 +1,6 @@
1
1
  0.2.1(working)
2
2
  * 1 major addition
3
- * Added Document#paginate which works just like find but adds pagination (dcu did basics and I pimped)
4
- * Added a basic console for playing around with MongoMapper (dcu)
5
- * Embedded associations can now be deeply nested (Keith Hanson)
3
+ * Added Document#paginate which works just like find but adds pagination
6
4
 
7
5
  0.2.0 7/7/2009
8
6
  * 2 major additions (observers, associations), several minor additions, and a few bug fixes
data/README.rdoc CHANGED
@@ -2,18 +2,16 @@
2
2
 
3
3
  Awesome gem for modeling your domain and storing it in mongo.
4
4
 
5
- Releases are tagged on github and also released as gems on github and rubyforge. Master is pushed to whenever I add a patch or a new feature. To build from master, you can clone the code, generate the updated gemspec, build the gem and install.
5
+ == Note on Releases
6
6
 
7
- * rake gemspec
8
- * gem build mongomapper.gemspec
9
- * gem install the gem that was built
7
+ Releases are tagged on github and also released as gems on github and rubyforge. Master is pushed to whenever I add a patch or a new feature. To build from master, you can clone the code and run 'rake install' to install the gem.
10
8
 
11
9
  == Note on Patches/Pull Requests
12
10
 
13
11
  * Fork the project.
14
12
  * Make your feature addition or bug fix.
15
13
  * Add tests for it. This is important so I don't break it in a future version unintentionally.
16
- * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself in another branch so I can ignore when I pull)
14
+ * Commit, do not mess with rakefile, version, or history. (if you want to have your own version, that is fine but bump version in a commit by itself I can ignore when I pull)
17
15
  * Send me a pull request. Bonus points for topic branches.
18
16
 
19
17
  == Dependencies
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -9,11 +9,11 @@ module MongoMapper
9
9
  end
10
10
 
11
11
  protected
12
- def find_target
13
- (@_values || []).map do |e|
14
- @association.klass.new(e)
15
- end
12
+ def find_target
13
+ (@_values || []).map do |e|
14
+ @association.klass.new(e)
16
15
  end
16
+ end
17
17
  end
18
18
  end
19
19
  end
@@ -12,18 +12,17 @@ module MongoMapper
12
12
  o.save
13
13
  o
14
14
  end
15
-
16
15
  reload_target
17
16
  end
18
17
 
19
18
  protected
20
- def find_target
21
- @association.klass.find(:all, {:conditions => {self.foreign_key => @owner.id}})
22
- end
19
+ def find_target
20
+ @association.klass.find(:all, {:conditions => {self.foreign_key => @owner.id}})
21
+ end
23
22
 
24
- def foreign_key
25
- @association.options[:foreign_key] || @owner.class.name.underscore.gsub("/", "_") + "_id"
26
- end
23
+ def foreign_key
24
+ @association.options[:foreign_key] || @owner.class.name.underscore.gsub("/", "_") + "_id"
25
+ end
27
26
  end
28
27
  end
29
28
  end
@@ -19,13 +19,13 @@ module MongoMapper
19
19
  end
20
20
 
21
21
  protected
22
- def find_target
23
- ref_id = @owner.__send__(:read_attribute, "#{@association.name}_id")
24
- ref_type = @owner.__send__(:read_attribute, "#{@association.name}_type")
25
- if ref_id && ref_type
26
- ref_type.constantize.find(ref_id)
27
- end
22
+ def find_target
23
+ ref_id = @owner.__send__(:read_attribute, "#{@association.name}_id")
24
+ ref_type = @owner.__send__(:read_attribute, "#{@association.name}_type")
25
+ if ref_id && ref_type
26
+ ref_type.constantize.find(ref_id)
28
27
  end
28
+ end
29
29
  end
30
30
  end
31
31
  end
@@ -0,0 +1,31 @@
1
+ module MongoMapper
2
+ module Associations
3
+ class PolymorphicHasManyEmbeddedProxy < Proxy
4
+ def replace(v)
5
+ @_values = v.map do |e|
6
+ ref_type = "#{@association.name}_type"
7
+ if e.kind_of?(EmbeddedDocument)
8
+ e.class.send(:key, ref_type, String)
9
+ {ref_type => e.class.name}.merge(e.attributes)
10
+ else
11
+ e
12
+ end
13
+ end
14
+
15
+ @target = nil
16
+
17
+ reload_target
18
+ end
19
+
20
+ protected
21
+ def find_target
22
+ (@_values || []).map do |e|
23
+ ref_type = "#{@association.name}_type"
24
+ class_name = e[ref_type]
25
+ klass = class_name ? Kernel.const_get(class_name) : @association.klass
26
+ klass.new(e)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -38,29 +38,23 @@ module MongoMapper
38
38
  end
39
39
 
40
40
  protected
41
- def method_missing(method, *args)
42
- if load_target
43
- if block_given?
44
- @target.send(method, *args) { |*block_args| yield(*block_args) }
45
- else
46
- @target.send(method, *args)
47
- end
41
+ def method_missing(method, *args)
42
+ if load_target
43
+ if block_given?
44
+ @target.send(method, *args) { |*block_args| yield(*block_args) }
45
+ else
46
+ @target.send(method, *args)
48
47
  end
49
48
  end
49
+ end
50
50
 
51
- def load_target
52
- @target ||= find_target
53
- end
51
+ def load_target
52
+ @target ||= find_target
53
+ end
54
54
 
55
- def find_target
56
- raise NotImplementedError
57
- end
58
-
59
- # Array#flatten has problems with recursive arrays. Going one level
60
- # deeper solves the majority of the problems.
61
- def flatten_deeper(array)
62
- array.collect { |element| (element.respond_to?(:flatten) && !element.is_a?(Hash)) ? element.flatten : element }.flatten
63
- end
55
+ def find_target
56
+ raise NotImplementedError
57
+ end
64
58
  end
65
59
  end
66
60
  end
@@ -9,7 +9,7 @@ module MongoMapper
9
9
  include Observing
10
10
  include Callbacks
11
11
  include SaveWithValidation
12
- include DocumentRailsCompatibility
12
+ include RailsCompatibility
13
13
  extend ClassMethods
14
14
 
15
15
  key :_id, String
@@ -8,11 +8,10 @@ module MongoMapper
8
8
  model.class_eval do
9
9
  extend ClassMethods
10
10
  include InstanceMethods
11
-
11
+
12
12
  extend Associations::ClassMethods
13
13
  include Associations::InstanceMethods
14
14
 
15
- include EmbeddedDocumentRailsCompatibility
16
15
  include Validatable
17
16
  include Serialization
18
17
  end
@@ -215,25 +214,14 @@ module MongoMapper
215
214
  end
216
215
 
217
216
  def embedded_association_attributes
218
- embedded_attributes = HashWithIndifferentAccess.new
217
+ attributes = HashWithIndifferentAccess.new
219
218
  self.class.associations.each_pair do |name, association|
220
-
221
- if association.type == :many && association.klass.embeddable?
222
- if documents = instance_variable_get(association.ivar)
223
- embedded_attributes[name] = documents.collect do |item|
224
- attributes_hash = item.attributes
225
-
226
- item.send(:embedded_association_attributes).each_pair do |association_name, association_value|
227
- attributes_hash[association_name] = association_value
228
- end
229
-
230
- attributes_hash
231
- end
232
- end
219
+ if association.type == :many && association.klass.embeddable?
220
+ vals = instance_variable_get(association.ivar)
221
+ attributes[name] = vals.collect { |item| item.attributes } if vals
233
222
  end
234
223
  end
235
-
236
- embedded_attributes
224
+ attributes
237
225
  end
238
226
 
239
227
  def initialize_associations(attrs={})
@@ -0,0 +1,52 @@
1
+ module MongoMapper
2
+ module Pagination
3
+ class PaginationProxy < BlankSlate
4
+ attr_accessor :subject
5
+ attr_reader :total_entries, :per_page, :current_page
6
+ alias limit per_page
7
+
8
+ def initialize(total_entries, current_page, per_page=nil)
9
+ @total_entries = total_entries.to_i
10
+ self.per_page = per_page
11
+ self.current_page = current_page
12
+ end
13
+
14
+ def total_pages
15
+ (total_entries / per_page.to_f).ceil
16
+ end
17
+
18
+ def out_of_bounds?
19
+ current_page > total_pages
20
+ end
21
+
22
+ def previous_page
23
+ current_page > 1 ? (current_page - 1) : nil
24
+ end
25
+
26
+ def next_page
27
+ current_page < total_pages ? (current_page + 1) : nil
28
+ end
29
+
30
+ def skip
31
+ (current_page - 1) * per_page
32
+ end
33
+ alias offset skip
34
+
35
+ def method_missing(name, *args, &block)
36
+ @subject.send(name, *args, &block)
37
+ end
38
+
39
+ private
40
+ def per_page=(value)
41
+ value = 25 if value.blank?
42
+ @per_page = value.to_i
43
+ end
44
+
45
+ def current_page=(value)
46
+ value = value.to_i
47
+ value = 1 if value < 1
48
+ @current_page = value
49
+ end
50
+ end
51
+ end
52
+ end
@@ -1,7 +1,8 @@
1
1
  module MongoMapper
2
- module EmbeddedDocumentRailsCompatibility
2
+ module RailsCompatibility
3
3
  def self.included(model)
4
4
  model.class_eval do
5
+ alias_method :new_record?, :new?
5
6
  extend ClassMethods
6
7
  end
7
8
  class << model
@@ -16,7 +17,7 @@ module MongoMapper
16
17
  end
17
18
 
18
19
  def to_param
19
- raise "Missing to_param method in #{self.class.name}. You should implement it to return the unique identifier of this document within a collection."
20
+ id
20
21
  end
21
22
  end
22
23
  end
data/lib/mongomapper.rb CHANGED
@@ -24,8 +24,7 @@ require dir + 'finder_options'
24
24
  require dir + 'key'
25
25
  require dir + 'observing'
26
26
  require dir + 'pagination'
27
- require dir + 'document_rails_compatibility'
28
- require dir + 'embedded_document_rails_compatibility'
27
+ require dir + 'rails_compatibility'
29
28
  require dir + 'save_with_validation'
30
29
  require dir + 'serialization'
31
30
  require dir + 'validations'
data/mongomapper.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{mongomapper}
5
- s.version = "0.2.0"
5
+ s.version = "0.3.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["John Nunemaker"]
9
- s.date = %q{2009-07-07}
9
+ s.date = %q{2009-07-19}
10
10
  s.email = %q{nunemaker@gmail.com}
11
11
  s.extra_rdoc_files = [
12
12
  "LICENSE",
@@ -27,6 +27,7 @@ Gem::Specification.new do |s|
27
27
  "lib/mongomapper/associations/has_many_embedded_proxy.rb",
28
28
  "lib/mongomapper/associations/has_many_proxy.rb",
29
29
  "lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb",
30
+ "lib/mongomapper/associations/polymorphic_has_many_embedded_proxy.rb",
30
31
  "lib/mongomapper/associations/proxy.rb",
31
32
  "lib/mongomapper/callbacks.rb",
32
33
  "lib/mongomapper/document.rb",
@@ -34,8 +35,8 @@ Gem::Specification.new do |s|
34
35
  "lib/mongomapper/finder_options.rb",
35
36
  "lib/mongomapper/key.rb",
36
37
  "lib/mongomapper/observing.rb",
37
- "lib/mongomapper/document_rails_compatibility.rb",
38
- "lib/mongomapper/embedded_document_rails_compatibility.rb",
38
+ "lib/mongomapper/pagination.rb",
39
+ "lib/mongomapper/rails_compatibility.rb",
39
40
  "lib/mongomapper/save_with_validation.rb",
40
41
  "lib/mongomapper/serialization.rb",
41
42
  "lib/mongomapper/serializers/json_serializer.rb",
@@ -51,16 +52,16 @@ Gem::Specification.new do |s|
51
52
  "test/test_key.rb",
52
53
  "test/test_mongomapper.rb",
53
54
  "test/test_observing.rb",
55
+ "test/test_pagination.rb",
54
56
  "test/test_rails_compatibility.rb",
55
57
  "test/test_serializations.rb",
56
58
  "test/test_validations.rb"
57
59
  ]
58
- s.has_rdoc = true
59
60
  s.homepage = %q{http://github.com/jnunemaker/mongomapper}
60
61
  s.rdoc_options = ["--charset=UTF-8"]
61
62
  s.require_paths = ["lib"]
62
63
  s.rubyforge_project = %q{mongomapper}
63
- s.rubygems_version = %q{1.3.1}
64
+ s.rubygems_version = %q{1.3.3}
64
65
  s.summary = %q{Awesome gem for modeling your domain and storing it in mongo}
65
66
  s.test_files = [
66
67
  "test/serializers/test_json_serializer.rb",
@@ -73,6 +74,7 @@ Gem::Specification.new do |s|
73
74
  "test/test_key.rb",
74
75
  "test/test_mongomapper.rb",
75
76
  "test/test_observing.rb",
77
+ "test/test_pagination.rb",
76
78
  "test/test_rails_compatibility.rb",
77
79
  "test/test_serializations.rb",
78
80
  "test/test_validations.rb"
@@ -80,7 +82,7 @@ Gem::Specification.new do |s|
80
82
 
81
83
  if s.respond_to? :specification_version then
82
84
  current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
83
- s.specification_version = 2
85
+ s.specification_version = 3
84
86
 
85
87
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
86
88
  s.add_runtime_dependency(%q<activesupport>, [">= 0"])
@@ -27,34 +27,10 @@ class Status
27
27
  key :name, String
28
28
  end
29
29
 
30
- class RealPerson
31
- include MongoMapper::Document
32
- many :pets
33
-
34
- key :name, String
35
-
36
- def pets_attributes=(pets_attributes)
37
- self.pets = []
38
- pets_attributes.each do |attributes|
39
- self.pets << Pet.new(attributes)
40
- end
41
- end
42
- end
43
-
44
30
  class Person
45
31
  include MongoMapper::EmbeddedDocument
46
32
  key :name, String
47
33
  key :child, Person
48
-
49
- many :pets
50
-
51
- end
52
-
53
- class Pet
54
- include MongoMapper::EmbeddedDocument
55
-
56
- key :name, String
57
- key :species, String
58
34
  end
59
35
 
60
36
  class Media
@@ -81,154 +57,35 @@ class Catalog
81
57
  many :medias, :polymorphic => true
82
58
  end
83
59
 
84
- module TrModels
85
- class Transport
86
- include MongoMapper::EmbeddedDocument
87
- key :license_plate, String
88
- end
89
-
90
- class Car < TrModels::Transport
91
- include MongoMapper::EmbeddedDocument
92
- key :model, String
93
- key :year, Integer
94
- end
95
-
96
- class Bus < TrModels::Transport
97
- include MongoMapper::EmbeddedDocument
98
- key :max_passengers, Integer
99
- end
100
-
101
- class Ambulance < TrModels::Transport
102
- include MongoMapper::EmbeddedDocument
103
- key :icu, Boolean
104
- end
105
-
106
- class Fleet
107
- include MongoMapper::Document
108
- many :transports, :polymorphic => true, :class_name => "TrModels::Transport"
109
- key :name, String
110
-
111
- def transport_attributes=(transport_attributes)
112
- self.transports = []
113
- transport_attributes.each do |attributes|
114
- self.transports << attributes["_type"].constantize.new(attributes)
115
- end
116
- end
117
- end
118
- end
119
-
120
60
  class AssociationsTest < Test::Unit::TestCase
121
61
  def setup
122
62
  Project.collection.clear
123
63
  Status.collection.clear
124
- Catalog.collection.clear
125
- TrModels::Fleet.collection.clear
126
64
  end
127
65
 
128
- context "Nested Polymorphic Many" do
129
- should "set associations correctly" do
130
- fleet_attributes = {
131
- "name" => "My Fleet",
132
- "transport_attributes" => [
133
- {"_type" => "TrModels::Ambulance", "license_plate" => "GGG123", "icu" => true},
134
- {"_type" => "TrModels::Car", "license_plate" => "ABC123", "model" => "VW Golf", "year" => 2001},
135
- {"_type" => "TrModels::Car", "license_plate" => "DEF123", "model" => "Honda Accord", "year" => 2008},
136
- ]
137
- }
138
-
139
- fleet = TrModels::Fleet.new(fleet_attributes)
140
- fleet.transports.size.should == 3
141
- fleet.transports[0].class.should == TrModels::Ambulance
142
- fleet.transports[0].license_plate.should == "GGG123"
143
- fleet.transports[0].icu.should be_true
144
- fleet.transports[1].class.should == TrModels::Car
145
- fleet.transports[1].license_plate.should == "ABC123"
146
- fleet.transports[1].model.should == "VW Golf"
147
- fleet.transports[1].year.should == 2001
148
- fleet.transports[2].class.should == TrModels::Car
149
- fleet.transports[2].license_plate.should == "DEF123"
150
- fleet.transports[2].model.should == "Honda Accord"
151
- fleet.transports[2].year.should == 2008
152
- fleet.save.should be_true
153
-
154
- from_db = TrModels::Fleet.find(fleet.id)
155
- from_db.transports.size.should == 3
156
- from_db.transports[0].license_plate.should == "GGG123"
157
- from_db.transports[0].icu.should be_true
158
- from_db.transports[1].license_plate.should == "ABC123"
159
- from_db.transports[1].model.should == "VW Golf"
160
- from_db.transports[1].year.should == 2001
161
- from_db.transports[2].license_plate.should == "DEF123"
162
- from_db.transports[2].model.should == "Honda Accord"
163
- from_db.transports[2].year.should == 2008
164
- end
165
-
166
- should "default reader to empty array" do
167
- fleet = TrModels::Fleet.new
168
- fleet.transports.should == []
169
- end
170
-
171
- should "allow adding to association like it was an array" do
172
- fleet = TrModels::Fleet.new
173
- fleet.transports << TrModels::Car.new
174
- fleet.transports.push TrModels::Bus.new
175
- fleet.transports.size.should == 2
176
- end
177
-
178
- should "store the association" do
179
- fleet = TrModels::Fleet.new
180
- fleet.transports = [TrModels::Car.new("license_plate" => "DCU2013", "model" => "Honda Civic")]
181
- fleet.save.should be_true
182
-
183
- from_db = TrModels::Fleet.find(fleet.id)
184
- from_db.transports.size.should == 1
185
- from_db.transports[0].license_plate.should == "DCU2013"
186
- end
187
-
188
- should "store different associations" do
189
- fleet = TrModels::Fleet.new
190
- fleet.transports = [
191
- TrModels::Car.new("license_plate" => "ABC1223", "model" => "Honda Civic", "year" => 2003),
192
- TrModels::Bus.new("license_plate" => "XYZ9090", "max_passengers" => 51),
193
- TrModels::Ambulance.new("license_plate" => "HDD3030", "icu" => true)
194
- ]
195
- fleet.save.should be_true
196
-
197
- from_db = TrModels::Fleet.find(fleet.id)
198
- from_db.transports.size.should == 3
199
- from_db.transports[0].license_plate.should == "ABC1223"
200
- from_db.transports[0].model.should == "Honda Civic"
201
- from_db.transports[0].year.should == 2003
202
- from_db.transports[1].license_plate.should == "XYZ9090"
203
- from_db.transports[1].max_passengers.should == 51
204
- from_db.transports[2].license_plate.should == "HDD3030"
205
- from_db.transports[2].icu.should == true
206
- end
207
- end
208
-
209
66
  context "Polymorphic Many" do
210
67
  should "default reader to empty array" do
211
68
  catalog = Catalog.new
212
69
  catalog.medias.should == []
213
70
  end
214
-
71
+
215
72
  should "allow adding to association like it was an array" do
216
73
  catalog = Catalog.new
217
74
  catalog.medias << Video.new
218
75
  catalog.medias.push Video.new
219
76
  catalog.medias.size.should == 2
220
77
  end
221
-
78
+
222
79
  should "store the association" do
223
80
  catalog = Catalog.new
224
81
  catalog.medias = [Video.new("file" => "video.mpg", "length" => 3600)]
225
82
  catalog.save.should be_true
226
-
83
+
227
84
  from_db = Catalog.find(catalog.id)
228
85
  from_db.medias.size.should == 1
229
86
  from_db.medias[0].file.should == "video.mpg"
230
87
  end
231
-
88
+
232
89
  should "store different associations" do
233
90
  catalog = Catalog.new
234
91
  catalog.medias = [
@@ -237,7 +94,7 @@ class AssociationsTest < Test::Unit::TestCase
237
94
  Image.new("file" => "image.png", "width" => 800, "height" => 600)
238
95
  ]
239
96
  catalog.save.should be_true
240
-
97
+
241
98
  from_db = Catalog.find(catalog.id)
242
99
  from_db.medias.size.should == 3
243
100
  from_db.medias[0].file.should == "video.mpg"
@@ -249,32 +106,79 @@ class AssociationsTest < Test::Unit::TestCase
249
106
  from_db.medias[2].height.should == 600
250
107
  end
251
108
  end
252
-
109
+
110
+ context "Many embedded documents" do
111
+ should "default reader to empty array" do
112
+ project = Project.new
113
+ project.addresses.should == []
114
+ end
115
+
116
+ should "allow adding to association like it was an array" do
117
+ project = Project.new
118
+ project.addresses << Address.new
119
+ project.addresses.push Address.new
120
+ project.addresses.size.should == 2
121
+ end
122
+
123
+ should "be embedded in document on save" do
124
+ sb = Address.new(:city => 'South Bend', :state => 'IN')
125
+ chi = Address.new(:city => 'Chicago', :state => 'IL')
126
+ project = Project.new
127
+ project.addresses << sb
128
+ project.addresses << chi
129
+ project.save
130
+
131
+ from_db = Project.find(project.id)
132
+ from_db.addresses.size.should == 2
133
+ from_db.addresses[0].should == sb
134
+ from_db.addresses[1].should == chi
135
+ end
136
+
137
+ should "allow embedding arbitrarily deep" do
138
+ @document = Class.new do
139
+ include MongoMapper::Document
140
+ key :person, Person
141
+ end
142
+
143
+ meg = Person.new(:name => "Meg")
144
+ meg.child = Person.new(:name => "Steve")
145
+ meg.child.child = Person.new(:name => "Linda")
146
+
147
+ doc = @document.new(:person => meg)
148
+ doc.save
149
+
150
+ from_db = @document.find(doc.id)
151
+ from_db.person.name.should == 'Meg'
152
+ from_db.person.child.name.should == 'Steve'
153
+ from_db.person.child.child.name.should == 'Linda'
154
+ end
155
+ end
156
+
253
157
  context "Polymorphic Belongs To" do
254
158
  should "default to nil" do
255
159
  status = Status.new
256
160
  status.target.should be_nil
257
161
  end
258
-
162
+
259
163
  should "store the association" do
260
164
  status = Status.new
261
165
  project = Project.new(:name => "mongomapper")
262
166
  status.target = project
263
167
  status.save.should be_true
264
-
168
+
265
169
  from_db = Status.find(status.id)
266
170
  from_db.target.should_not be_nil
267
171
  from_db.target_id.should == project.id
268
172
  from_db.target_type.should == "Project"
269
173
  from_db.target.name.should == "mongomapper"
270
174
  end
271
-
175
+
272
176
  should "unset the association" do
273
177
  status = Status.new
274
178
  project = Project.new(:name => "mongomapper")
275
179
  status.target = project
276
180
  status.save.should be_true
277
-
181
+
278
182
  from_db = Status.find(status.id)
279
183
  from_db.target = nil
280
184
  from_db.target_type.should be_nil
@@ -282,79 +186,73 @@ class AssociationsTest < Test::Unit::TestCase
282
186
  from_db.target.should be_nil
283
187
  end
284
188
  end
285
-
189
+
286
190
  context "Belongs To" do
287
191
  should "default to nil" do
288
192
  status = Status.new
289
193
  status.project.should be_nil
290
194
  end
291
-
195
+
292
196
  should "store the association" do
293
197
  status = Status.new
294
198
  project = Project.new(:name => "mongomapper")
295
199
  status.project = project
296
200
  status.save.should be_true
297
-
201
+
298
202
  from_db = Status.find(status.id)
299
203
  from_db.project.should_not be_nil
300
204
  from_db.project.name.should == "mongomapper"
301
205
  end
302
-
206
+
303
207
  should "unset the association" do
304
208
  status = Status.new
305
209
  project = Project.new(:name => "mongomapper")
306
210
  status.project = project
307
211
  status.save.should be_true
308
-
212
+
309
213
  from_db = Status.find(status.id)
310
214
  from_db.project = nil
311
215
  from_db.project.should be_nil
312
216
  end
313
217
  end
314
-
218
+
315
219
  context "Many documents" do
316
- should "set children documents" do
317
- fleet_attributes = {
318
- "name" => "My Project",
319
- "statuses_attributes" => [
320
- {"status" => "Ready", "license_plate" => "GGG123", "icu" => true},
321
- {"_type" => "ACar", "license_plate" => "ABC123", "model" => "VW Golf", "year" => 2001},
322
- {"_type" => "TrModels::Car", "license_plate" => "DEF123", "model" => "Honda Accord", "year" => 2008},
323
- ]
324
- }
325
- end
326
-
327
220
  should "default reader to empty array" do
328
221
  project = Project.new
329
222
  project.statuses.should == []
330
223
  end
331
-
224
+
332
225
  should "allow adding to association like it was an array" do
333
226
  project = Project.new
334
227
  project.statuses << Status.new
335
228
  project.statuses.push Status.new
336
229
  project.statuses.size.should == 2
337
230
  end
338
-
231
+
339
232
  should "store the association" do
340
233
  project = Project.new
341
234
  project.statuses = [Status.new("name" => "ready")]
342
235
  project.save.should be_true
343
-
236
+
344
237
  from_db = Project.find(project.id)
345
238
  from_db.statuses.size.should == 1
346
239
  from_db.statuses[0].name.should == "ready"
347
240
  end
348
241
  end
349
-
242
+
350
243
  context "Many embedded documents" do
244
+ should "default reader to empty array" do
245
+ project = Project.new
246
+ project.addresses.should == []
247
+ end
248
+
351
249
  should "allow adding to association like it was an array" do
352
250
  project = Project.new
353
251
  project.addresses << Address.new
354
252
  project.addresses.push Address.new
355
253
  project.addresses.size.should == 2
356
254
  end
357
-
255
+
358
256
  should "be embedded in document on save" do
359
257
  sb = Address.new(:city => 'South Bend', :state => 'IN')
360
258
  chi = Address.new(:city => 'Chicago', :state => 'IL')
@@ -362,7 +260,7 @@ class AssociationsTest < Test::Unit::TestCase
362
260
  project.addresses << sb
363
261
  project.addresses << chi
364
262
  project.save
365
-
263
+
366
264
  from_db = Project.find(project.id)
367
265
  from_db.addresses.size.should == 2
368
266
  from_db.addresses[0].should == sb
@@ -387,58 +285,5 @@ class AssociationsTest < Test::Unit::TestCase
387
285
  from_db.person.child.name.should == 'Steve'
388
286
  from_db.person.child.child.name.should == 'Linda'
389
287
  end
390
-
391
- should "allow assignment of 'many' embedded documents using a hash" do
392
- person_attributes = {
393
- "name" => "Mr. Pet Lover",
394
- "pets_attributes" => [
395
- {"name" => "Jimmy", "species" => "Cocker Spainel"},
396
- {"name" => "Sasha", "species" => "Siberian Husky"},
397
- ]
398
- }
399
-
400
- pet_lover = RealPerson.new(person_attributes)
401
- pet_lover.name.should == "Mr. Pet Lover"
402
- pet_lover.pets[0].name.should == "Jimmy"
403
- pet_lover.pets[0].species.should == "Cocker Spainel"
404
- pet_lover.pets[1].name.should == "Sasha"
405
- pet_lover.pets[1].species.should == "Siberian Husky"
406
- pet_lover.save.should be_true
407
-
408
- from_db = RealPerson.find(pet_lover.id)
409
- from_db.name.should == "Mr. Pet Lover"
410
- from_db.pets[0].name.should == "Jimmy"
411
- from_db.pets[0].species.should == "Cocker Spainel"
412
- from_db.pets[1].name.should == "Sasha"
413
- from_db.pets[1].species.should == "Siberian Husky"
414
- end
415
-
416
- should "allow saving embedded documents in 'many' embedded documents" do
417
- @document = Class.new do
418
- include MongoMapper::Document
419
-
420
- many :people
421
- end
422
-
423
- meg = Person.new(:name => "Meg")
424
- sparky = Pet.new(:name => "Sparky", :species => "Dog")
425
- koda = Pet.new(:name => "Koda", :species => "Dog")
426
-
427
- doc = @document.new
428
-
429
- meg.pets << sparky
430
- meg.pets << koda
431
-
432
- doc.people << meg
433
- doc.save
434
-
435
- from_db = @document.find(doc.id)
436
- from_db.people.first.name.should == "Meg"
437
- from_db.people.first.pets.should_not == []
438
- from_db.people.first.pets.first.name.should == "Sparky"
439
- from_db.people.first.pets.first.species.should == "Dog"
440
- from_db.people.first.pets[1].name.should == "Koda"
441
- from_db.people.first.pets[1].species.should == "Dog"
442
- end
443
288
  end
444
289
  end
@@ -55,13 +55,6 @@ class DocumentTest < Test::Unit::TestCase
55
55
  @document.keys['age'].name.should == 'age'
56
56
  @document.keys['age'].type.should == Integer
57
57
  end
58
-
59
- should "allow redefining a key" do
60
- @document.key(:foo, String)
61
- @document.keys['foo'].type.should == String
62
- @document.key(:foo, Integer)
63
- @document.keys['foo'].type.should == Integer
64
- end
65
58
 
66
59
  should "use default database by default" do
67
60
  @document.database.should == MongoMapper.database
@@ -0,0 +1,113 @@
1
+ require 'test_helper'
2
+
3
+ class PaginationTest < Test::Unit::TestCase
4
+ include MongoMapper::Pagination
5
+
6
+ context "Pagination proxy" do
7
+ should "should have accessors for subject" do
8
+ subject = [1,2,3,4,5]
9
+ collection = PaginationProxy.new(25, 2)
10
+ collection.subject = subject
11
+ collection.subject.should == subject
12
+ end
13
+
14
+ should "delegate any methods not defined to the subject" do
15
+ subject = [1,2,3,4,5]
16
+ collection = PaginationProxy.new(25, 2, 10)
17
+ collection.subject = subject
18
+ collection.size.should == 5
19
+ collection.each_with_index do |value, i|
20
+ value.should == subject[i]
21
+ end
22
+ collection[0..2].should == [1,2,3]
23
+ collection.class.should == Array
24
+ end
25
+
26
+ should "return correct value for total_entries" do
27
+ PaginationProxy.new(25, 2, 10).total_entries.should == 25
28
+ PaginationProxy.new('25', 2, 10).total_entries.should == 25
29
+ end
30
+
31
+ should "return correct value for per_page" do
32
+ PaginationProxy.new(25, 2, 10).per_page.should == 10
33
+ PaginationProxy.new(25, 2, '10').per_page.should == 10
34
+ end
35
+
36
+ should "alias limit to per_page" do
37
+ PaginationProxy.new(100, 1, 300).limit.should == 300
38
+ end
39
+
40
+ should "set per_page to 25 if nil or blank" do
41
+ PaginationProxy.new(25, 2).per_page.should == 25
42
+ PaginationProxy.new(25, 2, '').per_page.should == 25
43
+ end
44
+
45
+ should "return correct value for current_page" do
46
+ PaginationProxy.new(25, 2, 10).current_page.should == 2
47
+ PaginationProxy.new(25, '2', 10).current_page.should == 2
48
+ end
49
+
50
+ should "not allow value less than 1 for current page" do
51
+ PaginationProxy.new(25, -1).current_page.should == 1
52
+ end
53
+
54
+ should "automatically calculate total_pages from total_entries and per page" do
55
+ PaginationProxy.new(25, 2, 10).total_pages.should == 3
56
+ end
57
+
58
+ should "know how many records to skip" do
59
+ PaginationProxy.new(25, 2, 10).skip.should == 10
60
+ end
61
+
62
+ should "alias offset to skip" do
63
+ PaginationProxy.new(25, 2, 10).offset.should == 10
64
+ end
65
+
66
+ context "previous_page" do
67
+ should "be nil if current page 1" do
68
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
69
+ end
70
+
71
+ should "be one less than current page if current is > 1" do
72
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
73
+ end
74
+ end
75
+
76
+ context "next_page" do
77
+ should "be nil if current page is last page" do
78
+ PaginationProxy.new(25, 3, 10).next_page.should be_nil
79
+ end
80
+
81
+ should "work for any page that is not last" do
82
+ PaginationProxy.new(25, 1, 10).next_page.should == 2
83
+ PaginationProxy.new(25, 2, 10).next_page.should == 3
84
+ end
85
+ end
86
+
87
+ context "previous_page" do
88
+ should "be nil if current page is first page" do
89
+ PaginationProxy.new(25, 1, 10).previous_page.should be_nil
90
+ end
91
+
92
+ should "work for any page other than first" do
93
+ PaginationProxy.new(25, 2, 10).previous_page.should == 1
94
+ PaginationProxy.new(25, 3, 10).previous_page.should == 2
95
+ end
96
+ end
97
+
98
+ context "out_of_bounds?" do
99
+ should "be true if current_page is greater than total_pages" do
100
+ PaginationProxy.new(25, 10, 4).out_of_bounds?.should be_true
101
+ end
102
+
103
+ should "be false if current_page is less than total_pages" do
104
+ PaginationProxy.new(25, 10, 1).out_of_bounds?.should be_false
105
+ PaginationProxy.new(25, 2, 10).out_of_bounds?.should be_false
106
+ end
107
+
108
+ should "be false if current_page is equal to total_pages" do
109
+ PaginationProxy.new(25, 3, 10).out_of_bounds?.should be_false
110
+ end
111
+ end
112
+ end # end of pagination proxy
113
+ end # end of test case
@@ -1,73 +1,29 @@
1
1
  require 'test_helper'
2
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
3
  class TestRailsCompatibility < Test::Unit::TestCase
23
4
  def setup
24
5
  @document = Class.new do
25
6
  include MongoMapper::Document
26
7
  end
27
8
  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
9
 
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
10
+ should "have to_param that returns id" do
11
+ instance = @document.create('_id' => '1234')
12
+ instance.to_param.should == '1234'
50
13
  end
51
14
 
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
15
+ should "alias new to new_record?" do
16
+ instance = @document.new
17
+ instance.new_record?.should == instance.new?
18
+ end
62
19
 
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
20
+ should "alias many to has_many" do
21
+ @document.should respond_to(:has_many)
22
+ @document.method(:has_many).should == @document.method(:many)
23
+ end
67
24
 
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
25
+ should "have column names" do
26
+ @document.key :fname, String
27
+ @document.column_names.sort.should == ['_id', 'created_at', 'fname', 'updated_at']
72
28
  end
73
29
  end
@@ -169,12 +169,6 @@ class ValidationsTest < Test::Unit::TestCase
169
169
  should "allow to update an object" do
170
170
  doc = @document.new("name" => "joe")
171
171
  doc.save
172
-
173
- @document \
174
- .stubs(:find) \
175
- .with(:first, :conditions => {:name => 'joe'}, :limit => 1) \
176
- .returns(doc)
177
-
178
172
  doc.name = "joe"
179
173
  doc.valid?.should be_true
180
174
  doc.should_not have_error_on(:name)
@@ -183,12 +177,7 @@ class ValidationsTest < Test::Unit::TestCase
183
177
  should "fail if object name is not unique" do
184
178
  doc = @document.new("name" => "joe")
185
179
  doc.save.should be_true
186
-
187
- @document \
188
- .stubs(:find) \
189
- .with(:first, :conditions => {:name => 'joe'}, :limit => 1) \
190
- .returns(doc)
191
-
180
+ sleep 0.2 # hack to avoid race condition
192
181
  doc2 = @document.new("name" => "joe")
193
182
  doc2.should have_error_on(:name)
194
183
  end
@@ -200,12 +189,7 @@ class ValidationsTest < Test::Unit::TestCase
200
189
 
201
190
  doc = @document.create(:name => 'John')
202
191
  doc.should_not have_error_on(:name)
203
-
204
- @document \
205
- .stubs(:find) \
206
- .with(:first, :conditions => {:name => 'John'}, :limit => 1) \
207
- .returns(doc)
208
-
192
+ sleep 0.2 # hack to avoid race condition
209
193
  second_john = @document.create(:name => 'John')
210
194
  second_john.should have_error_on(:name, 'has already been taken')
211
195
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fcoury-mongomapper
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Nunemaker
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-07 00:00:00 -07:00
12
+ date: 2009-07-19 00:00:00 -07:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -86,6 +86,7 @@ files:
86
86
  - lib/mongomapper/associations/has_many_embedded_proxy.rb
87
87
  - lib/mongomapper/associations/has_many_proxy.rb
88
88
  - lib/mongomapper/associations/polymorphic_belongs_to_proxy.rb
89
+ - lib/mongomapper/associations/polymorphic_has_many_embedded_proxy.rb
89
90
  - lib/mongomapper/associations/proxy.rb
90
91
  - lib/mongomapper/callbacks.rb
91
92
  - lib/mongomapper/document.rb
@@ -93,8 +94,8 @@ files:
93
94
  - lib/mongomapper/finder_options.rb
94
95
  - lib/mongomapper/key.rb
95
96
  - lib/mongomapper/observing.rb
96
- - lib/mongomapper/document_rails_compatibility.rb
97
- - lib/mongomapper/embedded_document_rails_compatibility.rb
97
+ - lib/mongomapper/pagination.rb
98
+ - lib/mongomapper/rails_compatibility.rb
98
99
  - lib/mongomapper/save_with_validation.rb
99
100
  - lib/mongomapper/serialization.rb
100
101
  - lib/mongomapper/serializers/json_serializer.rb
@@ -110,10 +111,11 @@ files:
110
111
  - test/test_key.rb
111
112
  - test/test_mongomapper.rb
112
113
  - test/test_observing.rb
114
+ - test/test_pagination.rb
113
115
  - test/test_rails_compatibility.rb
114
116
  - test/test_serializations.rb
115
117
  - test/test_validations.rb
116
- has_rdoc: true
118
+ has_rdoc: false
117
119
  homepage: http://github.com/jnunemaker/mongomapper
118
120
  post_install_message:
119
121
  rdoc_options:
@@ -137,7 +139,7 @@ requirements: []
137
139
  rubyforge_project: mongomapper
138
140
  rubygems_version: 1.2.0
139
141
  signing_key:
140
- specification_version: 2
142
+ specification_version: 3
141
143
  summary: Awesome gem for modeling your domain and storing it in mongo
142
144
  test_files:
143
145
  - test/serializers/test_json_serializer.rb
@@ -150,6 +152,7 @@ test_files:
150
152
  - test/test_key.rb
151
153
  - test/test_mongomapper.rb
152
154
  - test/test_observing.rb
155
+ - test/test_pagination.rb
153
156
  - test/test_rails_compatibility.rb
154
157
  - test/test_serializations.rb
155
158
  - test/test_validations.rb
@@ -1,13 +0,0 @@
1
- module MongoMapper
2
- module DocumentRailsCompatibility
3
- def self.included(model)
4
- model.class_eval do
5
- alias_method :new_record?, :new?
6
- end
7
- end
8
-
9
- def to_param
10
- id
11
- end
12
- end
13
- end