mongo_mapper-unstable 2010.1.27 → 2010.1.28

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/Rakefile CHANGED
@@ -12,7 +12,7 @@ Jeweler::Tasks.new do |gem|
12
12
  gem.authors = ["John Nunemaker"]
13
13
 
14
14
  gem.add_dependency('activesupport', '>= 2.3')
15
- gem.add_dependency('mongo', '0.18.2')
15
+ gem.add_dependency('mongo', '0.18.3')
16
16
  gem.add_dependency('jnunemaker-validatable', '1.8.1')
17
17
 
18
18
  gem.add_development_dependency('jnunemaker-matchy', '0.4.0')
data/VERSION CHANGED
@@ -1 +1 @@
1
- 2010.01.27
1
+ 2010.01.28
@@ -7,8 +7,8 @@ module MongoMapper
7
7
  include InstanceMethods
8
8
  extend ClassMethods
9
9
  extend Finders
10
-
11
10
  extend Plugins
11
+
12
12
  plugin Plugins::Associations
13
13
  plugin Plugins::Clone
14
14
  plugin Plugins::Descendants
@@ -18,6 +18,7 @@ module MongoMapper
18
18
  plugin Plugins::Dirty # for now dirty needs to be after keys
19
19
  plugin Plugins::Logger
20
20
  plugin Plugins::Pagination
21
+ plugin Plugins::Protected
21
22
  plugin Plugins::Rails
22
23
  plugin Plugins::Serialization
23
24
  plugin Plugins::Validations
@@ -69,6 +70,21 @@ module MongoMapper
69
70
  end
70
71
  end
71
72
 
73
+ def find_or_create(arg)
74
+ first(arg) || create(arg)
75
+ end
76
+
77
+ def find_each(options={})
78
+ criteria, options = to_finder_options(options)
79
+ collection.find(criteria, options).each do |doc|
80
+ yield load(doc)
81
+ end
82
+ end
83
+
84
+ def find_by_id(id)
85
+ find(id)
86
+ end
87
+
72
88
  def first(options={})
73
89
  find_one(options)
74
90
  end
@@ -82,21 +98,10 @@ module MongoMapper
82
98
  find_many(options)
83
99
  end
84
100
 
85
- def find_by_id(id)
86
- find(id)
87
- end
88
-
89
101
  def count(options={})
90
102
  collection.find(to_criteria(options)).count
91
103
  end
92
104
 
93
- def find_each(options={})
94
- criteria, options = to_finder_options(options)
95
- collection.find(criteria, options).each do |doc|
96
- yield load(doc)
97
- end
98
- end
99
-
100
105
  def exists?(options={})
101
106
  !count(options).zero?
102
107
  end
@@ -1,13 +1,13 @@
1
1
  module MongoMapper
2
2
  module EmbeddedDocument
3
3
  extend DescendantAppends
4
-
4
+
5
5
  def self.included(model)
6
6
  model.class_eval do
7
7
  include InstanceMethods
8
8
  extend ClassMethods
9
-
10
9
  extend Plugins
10
+
11
11
  plugin Plugins::Associations
12
12
  plugin Plugins::Clone
13
13
  plugin Plugins::Descendants
@@ -15,13 +15,14 @@ module MongoMapper
15
15
  plugin Plugins::Inspect
16
16
  plugin Plugins::Keys
17
17
  plugin Plugins::Logger
18
+ plugin Plugins::Protected
18
19
  plugin Plugins::Rails
19
20
  plugin Plugins::Serialization
20
21
  plugin Plugins::Validations
21
22
 
22
- attr_accessor :_root_document
23
+ attr_accessor :_root_document, :_parent_document
23
24
  end
24
-
25
+
25
26
  super
26
27
  end
27
28
 
@@ -29,6 +30,12 @@ module MongoMapper
29
30
  def embeddable?
30
31
  true
31
32
  end
33
+
34
+ def embedded_in(owner_name)
35
+ define_method(owner_name) do
36
+ self._parent_document
37
+ end
38
+ end
32
39
  end
33
40
 
34
41
  module InstanceMethods
@@ -38,7 +45,7 @@ module MongoMapper
38
45
  end
39
46
  result
40
47
  end
41
-
48
+
42
49
  def save!(options={})
43
50
  if result = _root_document.try(:save!, options)
44
51
  @new = false
@@ -41,6 +41,7 @@ module MongoMapper
41
41
  def assign_root_document(*docs)
42
42
  docs.each do |doc|
43
43
  doc._root_document = _root_document
44
+ doc._parent_document = owner
44
45
  end
45
46
  end
46
47
  end
@@ -122,6 +122,14 @@ module MongoMapper
122
122
  validates_format_of(attribute, :with => key.options[:format])
123
123
  end
124
124
 
125
+ if key.options[:in]
126
+ validates_inclusion_of(attribute, :within => key.options[:in])
127
+ end
128
+
129
+ if key.options[:not_in]
130
+ validates_exclusion_of(attribute, :within => key.options[:not_in])
131
+ end
132
+
125
133
  if key.options[:length]
126
134
  length_options = case key.options[:length]
127
135
  when Integer
@@ -289,4 +297,4 @@ module MongoMapper
289
297
  end
290
298
  end
291
299
  end
292
- end
300
+ end
@@ -0,0 +1,41 @@
1
+ module MongoMapper
2
+ module Plugins
3
+ module Protected
4
+ module ClassMethods
5
+ def attr_protected(*attrs)
6
+ self.write_inheritable_attribute(:attr_protected, Set.new(attrs) + (protected_attributes || []))
7
+ end
8
+
9
+ def protected_attributes
10
+ self.read_inheritable_attribute(:attr_protected)
11
+ end
12
+
13
+ def key(*args)
14
+ key = super
15
+ attr_protected key.name.to_sym if key.options[:protected]
16
+ key
17
+ end
18
+ end
19
+
20
+ module InstanceMethods
21
+ def update_attributes(attrs={})
22
+ super(filter_protected_attrs(attrs))
23
+ end
24
+
25
+ def update_attributes!(attrs={})
26
+ super(filter_protected_attrs(attrs))
27
+ end
28
+
29
+ def protected_attributes
30
+ self.class.protected_attributes
31
+ end
32
+
33
+ protected
34
+ def filter_protected_attrs(attrs)
35
+ return attrs if protected_attributes.blank?
36
+ attrs.dup.delete_if { |key, val| protected_attributes.include?(key) }
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
@@ -205,8 +205,9 @@ class Time
205
205
  end
206
206
  end
207
207
 
208
- # TODO: Remove when patch accepted into driver
209
208
  class Mongo::ObjectID
209
+ alias_method :original_to_json, :to_json
210
+
210
211
  def to_json(options = nil)
211
212
  %Q("#{to_s}")
212
213
  end
data/lib/mongo_mapper.rb CHANGED
@@ -6,7 +6,7 @@ require 'set'
6
6
  # if there is a better way to do this, please enlighten me!
7
7
  if self.class.const_defined?(:Gem)
8
8
  gem 'activesupport', '>= 2.3'
9
- gem 'mongo', '0.18.2'
9
+ gem 'mongo', '0.18.3'
10
10
  gem 'jnunemaker-validatable', '1.8.1'
11
11
  end
12
12
 
@@ -117,6 +117,7 @@ require 'mongo_mapper/plugins/inspect'
117
117
  require 'mongo_mapper/plugins/keys'
118
118
  require 'mongo_mapper/plugins/logger'
119
119
  require 'mongo_mapper/plugins/pagination'
120
+ require 'mongo_mapper/plugins/protected'
120
121
  require 'mongo_mapper/plugins/rails'
121
122
  require 'mongo_mapper/plugins/serialization'
122
123
  require 'mongo_mapper/plugins/validations'
@@ -15,6 +15,7 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
15
15
  @pet_class = EDoc do
16
16
  key :name, String
17
17
  end
18
+ @pet_class.embedded_in :person
18
19
  @person_class = EDoc do
19
20
  key :name, String
20
21
  end
@@ -133,6 +134,17 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
133
134
  doc.people.first._root_document.should == doc
134
135
  doc.people.first.pets.first._root_document.should == doc
135
136
  end
137
+ should "create a reference to the owning document for all embedded documents before save" do
138
+ doc = @klass.new
139
+ meg = @person_class.new(:name => 'Meg')
140
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
141
+
142
+ doc.people << meg
143
+ meg.pets << pet
144
+
145
+ doc.people.first._parent_document.should == doc
146
+ doc.people.first.pets.first._parent_document.should == doc.people.first
147
+ end
136
148
 
137
149
  should "create a reference to the root document for all embedded documents" do
138
150
  sparky = @pet_class.new(:name => 'Sparky', :species => 'Dog')
@@ -145,6 +157,32 @@ class ManyEmbeddedProxyTest < Test::Unit::TestCase
145
157
  doc.people.first._root_document.should == doc
146
158
  doc.people.first.pets.first._root_document.should == doc
147
159
  end
160
+ should "create a reference to the owning document for all embedded documents" do
161
+ doc = @klass.new
162
+ meg = @person_class.new(:name => 'Meg')
163
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
164
+
165
+ doc.people << meg
166
+ meg.pets << pet
167
+ doc.save
168
+
169
+ doc.reload
170
+ doc.people.first._parent_document.should == doc
171
+ doc.people.first.pets.first._parent_document.should == doc.people.first
172
+ end
173
+
174
+ should "create embedded_in relationship for embedded docs" do
175
+ doc = @klass.new
176
+ meg = @person_class.new(:name => 'Meg')
177
+ pet = @pet_class.new(:name => 'Sparky', :species => 'Dog')
178
+
179
+ doc.people << meg
180
+ meg.pets << pet
181
+ doc.save
182
+
183
+ doc.reload
184
+ doc.people.first.pets.first.person.should == doc.people.first
185
+ end
148
186
  end
149
187
 
150
188
  should "allow finding by id" do
@@ -13,7 +13,7 @@ class DocumentTest < Test::Unit::TestCase
13
13
  end
14
14
  end
15
15
 
16
- context "Using key with type Array" do
16
+ context "array key" do
17
17
  setup do
18
18
  @document.key :tags, Array
19
19
  end
@@ -60,7 +60,7 @@ class DocumentTest < Test::Unit::TestCase
60
60
  end
61
61
  end
62
62
 
63
- context "Using key with type Hash" do
63
+ context "hash key" do
64
64
  setup do
65
65
  @document.key :foo, Hash
66
66
  end
@@ -95,7 +95,7 @@ class DocumentTest < Test::Unit::TestCase
95
95
  end
96
96
  end
97
97
 
98
- context "Using key with custom type with default" do
98
+ context "custom type key with default" do
99
99
  setup do
100
100
  @document.key :window, WindowSize, :default => WindowSize.new(600, 480)
101
101
  end
@@ -407,6 +407,24 @@ class DocumentTest < Test::Unit::TestCase
407
407
  end
408
408
  end
409
409
 
410
+ context "find_or_create" do
411
+ should "find if exists" do
412
+ created = @document.create(:first_name => 'John', :last_name => 'Nunemaker')
413
+ lambda {
414
+ found = @document.find_or_create(:first_name => 'John', :last_name => 'Nunemaker')
415
+ found.should == created
416
+ }.should_not change { @document.count }
417
+ end
418
+
419
+ should "create if not found" do
420
+ lambda {
421
+ created = @document.find_or_create(:first_name => 'John', :last_name => 'Nunemaker')
422
+ created.first_name.should == 'John'
423
+ created.last_name.should == 'Nunemaker'
424
+ }.should change { @document.count }.by(1)
425
+ end
426
+ end
427
+
410
428
  context "ClassMethods#delete (single document)" do
411
429
  setup do
412
430
  @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
@@ -568,10 +586,10 @@ class DocumentTest < Test::Unit::TestCase
568
586
  @document.new.database.should == @document.database
569
587
  end
570
588
 
571
- context "#save (new document)" do
589
+ context "#update_attributes (new document)" do
572
590
  setup do
573
591
  @doc = @document.new(:first_name => 'John', :age => '27')
574
- @doc.save
592
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
575
593
  end
576
594
 
577
595
  should "insert document into the collection" do
@@ -583,54 +601,27 @@ class DocumentTest < Test::Unit::TestCase
583
601
  end
584
602
 
585
603
  should "save attributes" do
586
- @doc.first_name.should == 'John'
587
- @doc.age.should == 27
604
+ @doc.first_name.should == 'Johnny'
605
+ @doc.age.should == 30
588
606
  end
589
607
 
590
608
  should "update attributes in the database" do
591
609
  doc = @doc.reload
592
610
  doc.should == @doc
593
- doc.first_name.should == 'John'
594
- doc.age.should == 27
595
- end
596
-
597
- should "allow to add custom attributes to the document" do
598
- @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
599
- @doc.save
600
- doc = @doc.reload
601
- doc.gender.should == 'male'
602
- doc.tags.should == [1, "2"]
603
- end
604
-
605
- should "allow to use custom methods to assign properties" do
606
- klass = Doc do
607
- key :name, String
608
-
609
- def realname=(value)
610
- self.name = value
611
- end
612
- end
613
-
614
- person = klass.new(:realname => 'David')
615
- person.save
616
- person.reload.name.should == 'David'
611
+ doc.first_name.should == 'Johnny'
612
+ doc.age.should == 30
617
613
  end
618
614
 
619
- context "with key of type date" do
620
- should "save the date value as a Time object" do
621
- doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
622
- doc.save
623
- doc.date.should == Date.new(2009, 12, 1)
624
- end
615
+ should "allow updating custom attributes" do
616
+ @doc.update_attributes(:gender => 'mALe')
617
+ @doc.reload.gender.should == 'mALe'
625
618
  end
626
619
  end
627
620
 
628
- context "#save (existing document)" do
621
+ context "#update_attributes (existing document)" do
629
622
  setup do
630
623
  @doc = @document.create(:first_name => 'John', :age => '27')
631
- @doc.first_name = 'Johnny'
632
- @doc.age = 30
633
- @doc.save
624
+ @doc.update_attributes(:first_name => 'Johnny', :age => 30)
634
625
  end
635
626
 
636
627
  should "not insert document into collection" do
@@ -647,19 +638,26 @@ class DocumentTest < Test::Unit::TestCase
647
638
  doc.first_name.should == 'Johnny'
648
639
  doc.age.should == 30
649
640
  end
641
+ end
650
642
 
651
- should "allow updating custom attributes" do
652
- @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
653
- @doc.gender = 'Male'
654
- @doc.save
655
- @doc.reload.gender.should == 'Male'
643
+ context "#update_attributes (return value)" do
644
+ setup do
645
+ @document.key :foo, String, :required => true
656
646
  end
657
- end
658
647
 
659
- context "#update_attributes (new document)" do
648
+ should "be true if document valid" do
649
+ @document.new.update_attributes(:foo => 'bar').should be_true
650
+ end
651
+
652
+ should "be false if document not valid" do
653
+ @document.new.update_attributes({}).should be_false
654
+ end
655
+ end
656
+
657
+ context "#save (new document)" do
660
658
  setup do
661
659
  @doc = @document.new(:first_name => 'John', :age => '27')
662
- @doc.update_attributes(:first_name => 'Johnny', :age => 30)
660
+ @doc.save
663
661
  end
664
662
 
665
663
  should "insert document into the collection" do
@@ -671,27 +669,54 @@ class DocumentTest < Test::Unit::TestCase
671
669
  end
672
670
 
673
671
  should "save attributes" do
674
- @doc.first_name.should == 'Johnny'
675
- @doc.age.should == 30
672
+ @doc.first_name.should == 'John'
673
+ @doc.age.should == 27
676
674
  end
677
675
 
678
676
  should "update attributes in the database" do
679
677
  doc = @doc.reload
680
678
  doc.should == @doc
681
- doc.first_name.should == 'Johnny'
682
- doc.age.should == 30
679
+ doc.first_name.should == 'John'
680
+ doc.age.should == 27
683
681
  end
684
682
 
685
- should "allow updating custom attributes" do
686
- @doc.update_attributes(:gender => 'mALe')
687
- @doc.reload.gender.should == 'mALe'
683
+ should "allow to add custom attributes to the document" do
684
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
685
+ @doc.save
686
+ doc = @doc.reload
687
+ doc.gender.should == 'male'
688
+ doc.tags.should == [1, "2"]
689
+ end
690
+
691
+ should "allow to use custom methods to assign properties" do
692
+ klass = Doc do
693
+ key :name, String
694
+
695
+ def realname=(value)
696
+ self.name = value
697
+ end
698
+ end
699
+
700
+ person = klass.new(:realname => 'David')
701
+ person.save
702
+ person.reload.name.should == 'David'
703
+ end
704
+
705
+ context "with key of type date" do
706
+ should "save the date value as a Time object" do
707
+ doc = @document.new(:first_name => 'John', :age => '27', :date => "12/01/2009")
708
+ doc.save
709
+ doc.date.should == Date.new(2009, 12, 1)
710
+ end
688
711
  end
689
712
  end
690
713
 
691
- context "#update_attributes (existing document)" do
714
+ context "#save (existing document)" do
692
715
  setup do
693
716
  @doc = @document.create(:first_name => 'John', :age => '27')
694
- @doc.update_attributes(:first_name => 'Johnny', :age => 30)
717
+ @doc.first_name = 'Johnny'
718
+ @doc.age = 30
719
+ @doc.save
695
720
  end
696
721
 
697
722
  should "not insert document into collection" do
@@ -708,22 +733,15 @@ class DocumentTest < Test::Unit::TestCase
708
733
  doc.first_name.should == 'Johnny'
709
734
  doc.age.should == 30
710
735
  end
711
- end
712
-
713
- context "#update_attributes" do
714
- setup do
715
- @document.key :foo, String, :required => true
716
- end
717
-
718
- should "return true if document valid" do
719
- @document.new.update_attributes(:foo => 'bar').should be_true
720
- end
721
736
 
722
- should "return false if document not valid" do
723
- @document.new.update_attributes({}).should be_false
737
+ should "allow updating custom attributes" do
738
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
739
+ @doc.gender = 'Male'
740
+ @doc.save
741
+ @doc.reload.gender.should == 'Male'
724
742
  end
725
743
  end
726
-
744
+
727
745
  context "#save (with validations off)" do
728
746
  setup do
729
747
  @document = Doc do
@@ -1091,7 +1109,7 @@ class DocumentTest < Test::Unit::TestCase
1091
1109
  end
1092
1110
  end
1093
1111
 
1094
- context "#exist?" do
1112
+ context "#exists?" do
1095
1113
  setup do
1096
1114
  @doc = @document.create(:first_name => "James", :age => 27)
1097
1115
  end
@@ -1162,7 +1180,7 @@ class DocumentTest < Test::Unit::TestCase
1162
1180
  end
1163
1181
  end
1164
1182
 
1165
- context "Loading a document from the database with keys that are not defined" do
1183
+ context "database has keys not defined in model" do
1166
1184
  setup do
1167
1185
  @id = Mongo::ObjectID.new
1168
1186
  @document.collection.insert({