djsun-mongomapper 0.3.1.1 → 0.3.3

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 (34) hide show
  1. data/History +20 -1
  2. data/Rakefile +5 -3
  3. data/VERSION +1 -1
  4. data/lib/mongomapper/associations/base.rb +3 -5
  5. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +5 -3
  6. data/lib/mongomapper/associations/belongs_to_proxy.rb +4 -4
  7. data/lib/mongomapper/associations/many_documents_proxy.rb +32 -14
  8. data/lib/mongomapper/associations/proxy.rb +2 -6
  9. data/lib/mongomapper/associations.rb +38 -15
  10. data/lib/mongomapper/document.rb +165 -95
  11. data/lib/mongomapper/dynamic_finder.rb +38 -0
  12. data/lib/mongomapper/embedded_document.rb +116 -88
  13. data/lib/mongomapper/finder_options.rb +3 -14
  14. data/lib/mongomapper/key.rb +12 -16
  15. data/lib/mongomapper/serializers/json_serializer.rb +15 -12
  16. data/lib/mongomapper/support.rb +30 -0
  17. data/lib/mongomapper.rb +7 -33
  18. data/mongomapper.gemspec +10 -7
  19. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +14 -0
  20. data/test/functional/associations/test_belongs_to_proxy.rb +10 -0
  21. data/test/functional/associations/test_many_polymorphic_proxy.rb +46 -52
  22. data/test/functional/associations/test_many_proxy.rb +71 -12
  23. data/test/functional/test_associations.rb +9 -2
  24. data/test/functional/test_document.rb +281 -20
  25. data/test/functional/test_rails_compatibility.rb +2 -3
  26. data/test/models.rb +39 -8
  27. data/test/unit/serializers/test_json_serializer.rb +46 -12
  28. data/test/unit/test_association_base.rb +10 -2
  29. data/test/unit/test_document.rb +7 -9
  30. data/test/unit/test_embedded_document.rb +180 -24
  31. data/test/unit/test_finder_options.rb +7 -38
  32. data/test/unit/test_key.rb +54 -24
  33. metadata +5 -5
  34. data/test/unit/test_mongo_id.rb +0 -35
@@ -15,6 +15,38 @@ class DocumentTest < Test::Unit::TestCase
15
15
  @document.collection.clear
16
16
  end
17
17
 
18
+ context "Saving a document with a custom id" do
19
+ should "clear custom id flag when saved" do
20
+ doc = @document.new(:id => '1234')
21
+ doc.using_custom_id?.should be_true
22
+ doc.save.should be_true
23
+ doc.using_custom_id?.should be_false
24
+ end
25
+ end
26
+
27
+ context "Loading a document from the database with keys that are not defined" do
28
+ setup do
29
+ @id = XGen::Mongo::Driver::ObjectID.new.to_s
30
+ @document.collection.insert({
31
+ :_id => @id,
32
+ :first_name => 'John',
33
+ :last_name => 'Nunemaker',
34
+ :age => 27,
35
+ :favorite_color => 'red',
36
+ :skills => ['ruby', 'rails', 'javascript', 'xhtml', 'css']
37
+ })
38
+ end
39
+
40
+ should "assign all keys from database" do
41
+ doc = @document.find(@id)
42
+ doc.first_name.should == 'John'
43
+ doc.last_name.should == 'Nunemaker'
44
+ doc.age.should == 27
45
+ doc.favorite_color.should == 'red'
46
+ doc.skills.should == ['ruby', 'rails', 'javascript', 'xhtml', 'css']
47
+ end
48
+ end
49
+
18
50
  context "Document Class Methods" do
19
51
  context "Using key with type Array" do
20
52
  setup do
@@ -53,7 +85,7 @@ class DocumentTest < Test::Unit::TestCase
53
85
  doc.tags.should == ["foo"]
54
86
  end
55
87
 
56
- should_eventually "work with << then save" do
88
+ should "work with << then save" do
57
89
  doc = @document.new
58
90
  doc.tags << "foo"
59
91
  doc.tags << "bar"
@@ -61,7 +93,6 @@ class DocumentTest < Test::Unit::TestCase
61
93
  doc.tags.should == %w(foo bar)
62
94
  @document.find(doc.id).tags.should == %w(foo bar)
63
95
  end
64
-
65
96
  end
66
97
 
67
98
  context "Using key with type Hash" do
@@ -73,14 +104,14 @@ class DocumentTest < Test::Unit::TestCase
73
104
  doc = @document.new
74
105
  doc.foo.should == {}
75
106
  end
76
-
107
+
77
108
  should "work with []=" do
78
109
  doc = @document.new
79
110
  doc.foo["quux"] = "bar"
80
111
  doc.foo["quux"].should == "bar"
81
112
  doc.foo.should == { "quux" => "bar" }
82
113
  end
83
-
114
+
84
115
  should "work with indifferent access" do
85
116
  doc = @document.new
86
117
  doc.foo = {:baz => 'bar'}
@@ -92,6 +123,7 @@ class DocumentTest < Test::Unit::TestCase
92
123
  doc = @document.new
93
124
  doc.foo = {:baz => 'bar'}
94
125
  doc.save
126
+
95
127
  doc = @document.find(doc.id)
96
128
  doc.foo[:baz].should == 'bar'
97
129
  doc.foo['baz'].should == 'bar'
@@ -132,6 +164,10 @@ class DocumentTest < Test::Unit::TestCase
132
164
  @doc_instance.id.size.should == 24
133
165
  end
134
166
 
167
+ should "no longer be new?" do
168
+ @doc_instance.new?.should be_false
169
+ end
170
+
135
171
  should "return instance of document" do
136
172
  @doc_instance.should be_instance_of(@document)
137
173
  @doc_instance.first_name.should == 'John'
@@ -249,11 +285,7 @@ class DocumentTest < Test::Unit::TestCase
249
285
  end
250
286
 
251
287
  should "raise error if document not found" do
252
- lambda { @document.find(MongoID.new) }.should raise_error(MongoMapper::DocumentNotFound)
253
- end
254
-
255
- should_eventually "raise error if id is illegal" do
256
- lambda { @document.find(1) }.should raise_error(MongoMapper::IllegalID)
288
+ lambda { @document.find(123) }.should raise_error(MongoMapper::DocumentNotFound)
257
289
  end
258
290
  end
259
291
 
@@ -280,7 +312,7 @@ class DocumentTest < Test::Unit::TestCase
280
312
  context "with #all" do
281
313
  should "find all documents based on criteria" do
282
314
  @document.all(:order => 'first_name').should == [@doc1, @doc3, @doc2]
283
- @document.all(:conditions => {:last_name => 'Nunemaker'}).should == [@doc1, @doc3]
315
+ @document.all(:conditions => {:last_name => 'Nunemaker'}, :order => 'age desc').should == [@doc1, @doc3]
284
316
  end
285
317
  end
286
318
 
@@ -299,17 +331,75 @@ class DocumentTest < Test::Unit::TestCase
299
331
 
300
332
  context "with :last" do
301
333
  should "find last document" do
302
- @document.find(:last).should == @doc3
334
+ @document.find(:last, :order => 'age').should == @doc2
303
335
  end
304
336
  end
305
337
 
306
338
  context "with #last" do
307
339
  should "find last document based on criteria" do
308
- @document.last.should == @doc3
340
+ @document.last(:order => 'age').should == @doc2
309
341
  @document.last(:conditions => {:age => 28}).should == @doc2
310
342
  end
311
343
  end
312
344
 
345
+ context "with :find_by" do
346
+ should "find document based on argument" do
347
+ @document.find_by_first_name('John').should == @doc1
348
+ @document.find_by_last_name('Nunemaker', :order => 'age desc').should == @doc1
349
+ @document.find_by_age(27).should == @doc1
350
+ end
351
+
352
+ should "not raise error" do
353
+ @document.find_by_first_name('Mongo').should be_nil
354
+ end
355
+
356
+ should "define a method for each key" do
357
+ @document.methods(false).select { |e| e =~ /^find_by_/ }.size == @document.keys.size
358
+ end
359
+ end
360
+
361
+ context "with dynamic finders" do
362
+ should "find document based on all arguments" do
363
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 27).should == @doc1
364
+ end
365
+
366
+ should "not find the document if an argument is wrong" do
367
+ @document.find_by_first_name_and_last_name_and_age('John', 'Nunemaker', 28).should be_nil
368
+ end
369
+
370
+ should "find all documents based on arguments" do
371
+ docs = @document.find_all_by_last_name('Nunemaker')
372
+ docs.should be_kind_of(Array)
373
+ docs.should include(@doc1)
374
+ docs.should include(@doc3)
375
+ end
376
+
377
+ should "find last document based on arguments" do
378
+ doc = @document.find_last_by_last_name('Nunemaker', :order => 'age')
379
+ doc.should == @doc1
380
+ end
381
+
382
+ should "initialize document with given arguments" do
383
+ doc = @document.find_or_initialize_by_first_name_and_last_name('David', 'Cuadrado')
384
+ doc.should be_new
385
+ doc.first_name.should == 'David'
386
+ end
387
+
388
+ should "not initialize document if document is found" do
389
+ doc = @document.find_or_initialize_by_first_name('John')
390
+ doc.should_not be_new
391
+ end
392
+
393
+ should "create document with given arguments" do
394
+ doc = @document.find_or_create_by_first_name_and_last_name('David', 'Cuadrado')
395
+ doc.should_not be_new
396
+ doc.first_name.should == 'David'
397
+ end
398
+
399
+ should "raise error if document is not found" do
400
+ lambda {@document.find_by_first_name_and_last_name!(1,2)}.should raise_error(MongoMapper::DocumentNotFound)
401
+ end
402
+ end
313
403
  end # finding documents
314
404
 
315
405
  context "Finding document by id" do
@@ -324,7 +414,7 @@ class DocumentTest < Test::Unit::TestCase
324
414
  end
325
415
 
326
416
  should "return nil if document not found" do
327
- @document.find_by_id(MongoID.new).should be(nil)
417
+ @document.find_by_id(1234).should be(nil)
328
418
  end
329
419
  end
330
420
 
@@ -448,6 +538,123 @@ class DocumentTest < Test::Unit::TestCase
448
538
  end
449
539
  end
450
540
 
541
+ context ":dependent" do
542
+ setup do
543
+ # FIXME: make use of already defined models
544
+ class ::Property
545
+ include MongoMapper::Document
546
+ end
547
+ Property.delete_all
548
+
549
+ class ::Thing
550
+ include MongoMapper::Document
551
+ key :name, String
552
+ end
553
+ Thing.delete_all
554
+ end
555
+
556
+ teardown do
557
+ Object.send :remove_const, 'Property' if defined?(::Property)
558
+ Object.send :remove_const, 'Thing' if defined?(::Thing)
559
+ end
560
+
561
+ context "many" do
562
+ context "=> destroy" do
563
+ setup do
564
+ Property.key :thing_id, String
565
+ Property.belongs_to :thing, :dependent => :destroy
566
+ Thing.many :properties, :dependent => :destroy
567
+
568
+ @thing = Thing.create(:name => "Tree")
569
+ @property1 = Property.create
570
+ @property2 = Property.create
571
+ @property3 = Property.create
572
+ @thing.properties << @property1
573
+ @thing.properties << @property2
574
+ @thing.properties << @property3
575
+ end
576
+
577
+ should "should destroy the associated documents" do
578
+ @thing.properties.count.should == 3
579
+ @thing.destroy
580
+ @thing.properties.count.should == 0
581
+ Property.count.should == 0
582
+ end
583
+ end
584
+
585
+ context "=> delete_all" do
586
+ setup do
587
+ Property.key :thing_id, String
588
+ Property.belongs_to :thing
589
+ Thing.has_many :properties, :dependent => :delete_all
590
+
591
+ @thing = Thing.create(:name => "Tree")
592
+ @property1 = Property.create
593
+ @property2 = Property.create
594
+ @property3 = Property.create
595
+ @thing.properties << @property1
596
+ @thing.properties << @property2
597
+ @thing.properties << @property3
598
+ end
599
+
600
+ should "should delete associated documents" do
601
+ @thing.properties.count.should == 3
602
+ @thing.destroy
603
+ @thing.properties.count.should == 0
604
+ Property.count.should == 0
605
+ end
606
+ end
607
+
608
+ context "=> nullify" do
609
+ setup do
610
+ Property.key :thing_id, String
611
+ Property.belongs_to :thing
612
+ Thing.has_many :properties, :dependent => :nullify
613
+
614
+ @thing = Thing.create(:name => "Tree")
615
+ @property1 = Property.create
616
+ @property2 = Property.create
617
+ @property3 = Property.create
618
+ @thing.properties << @property1
619
+ @thing.properties << @property2
620
+ @thing.properties << @property3
621
+ end
622
+
623
+ should "should nullify relationship but not destroy associated documents" do
624
+ @thing.properties.count.should == 3
625
+ @thing.destroy
626
+ @thing.properties.count.should == 0
627
+ Property.count.should == 3
628
+ end
629
+ end
630
+ end
631
+
632
+ context "belongs_to" do
633
+ context "=> destroy" do
634
+ setup do
635
+ Property.key :thing_id, String
636
+ Property.belongs_to :thing, :dependent => :destroy
637
+ Thing.has_many :properties
638
+
639
+ @thing = Thing.create(:name => "Tree")
640
+ @property1 = Property.create
641
+ @property2 = Property.create
642
+ @property3 = Property.create
643
+ @thing.properties << @property1
644
+ @thing.properties << @property2
645
+ @thing.properties << @property3
646
+ end
647
+
648
+ should "destroy the thing" do
649
+ Thing.count.should == 1
650
+ @property1.destroy
651
+ Thing.count.should == 0
652
+ @property1.thing.should be_frozen
653
+ end
654
+ end
655
+ end
656
+ end
657
+
451
658
  context "Counting documents in collection" do
452
659
  setup do
453
660
  @doc1 = @document.create({:first_name => 'John', :last_name => 'Nunemaker', :age => '27'})
@@ -504,13 +711,13 @@ class DocumentTest < Test::Unit::TestCase
504
711
  @document.ensure_index :first_name, :unique => true
505
712
  end
506
713
 
507
- should_eventually "allow creating index on multiple keys" do
714
+ should "allow creating index on multiple keys" do
508
715
  index_name = nil
509
716
  lambda {
510
717
  index_name = @document.ensure_index [[:first_name, 1], [:last_name, -1]]
511
718
  }.should change { @document.collection.index_information.size }.by(1)
512
719
 
513
- index_name.should == 'first_name_1_last_name_-1'
720
+ [ 'first_name_1_last_name_-1', 'last_name_-1_first_name_1' ].should include(index_name)
514
721
 
515
722
  index = @document.collection.index_information[index_name]
516
723
  index.should_not be_nil
@@ -551,6 +758,21 @@ class DocumentTest < Test::Unit::TestCase
551
758
  from_db.first_name.should == 'John'
552
759
  from_db.age.should == 27
553
760
  end
761
+
762
+ should "allow to add custom attributes to the document" do
763
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male', :tags => [1, "2"])
764
+ @doc.save
765
+ from_db = @document.find(@doc.id)
766
+ from_db.gender.should == 'male'
767
+ from_db.tags.should == [1, "2"]
768
+ end
769
+
770
+ should "allow to use custom methods to assign properties" do
771
+ person = RealPerson.new(:realname => "David")
772
+ person.save
773
+ from_db = RealPerson.find(person.id)
774
+ from_db.name.should == "David"
775
+ end
554
776
  end
555
777
 
556
778
  context "Saving an existing document" do
@@ -575,6 +797,14 @@ class DocumentTest < Test::Unit::TestCase
575
797
  from_db.first_name.should == 'Johnny'
576
798
  from_db.age.should == 30
577
799
  end
800
+
801
+ should "allow to update custom attributes" do
802
+ @doc = @document.new(:first_name => 'David', :age => '26', :gender => 'male')
803
+ @doc.gender = 'Male'
804
+ @doc.save
805
+ from_db = @document.find(@doc.id)
806
+ from_db.gender.should == 'Male'
807
+ end
578
808
  end
579
809
 
580
810
  context "Calling update attributes on a new document" do
@@ -603,6 +833,12 @@ class DocumentTest < Test::Unit::TestCase
603
833
  from_db.first_name.should == 'Johnny'
604
834
  from_db.age.should == 30
605
835
  end
836
+
837
+ should "allow to update custom attributes" do
838
+ @doc.update_attributes(:gender => 'mALe')
839
+ from_db = @document.find(@doc.id)
840
+ from_db.gender.should == 'mALe'
841
+ end
606
842
  end
607
843
 
608
844
  context "Updating an existing document using update attributes" do
@@ -626,6 +862,20 @@ class DocumentTest < Test::Unit::TestCase
626
862
  from_db.age.should == 30
627
863
  end
628
864
  end
865
+
866
+ context "update_attributes" do
867
+ setup do
868
+ @document.key :foo, String, :required => true
869
+ end
870
+
871
+ should "return true if document valid" do
872
+ @document.new.update_attributes(:foo => 'bar').should be_true
873
+ end
874
+
875
+ should "return false if document not valid" do
876
+ @document.new.update_attributes({}).should be_false
877
+ end
878
+ end
629
879
 
630
880
  context "Destroying a document that exists" do
631
881
  setup do
@@ -640,6 +890,10 @@ class DocumentTest < Test::Unit::TestCase
640
890
  should "raise error if assignment is attempted" do
641
891
  lambda { @doc.first_name = 'Foo' }.should raise_error(TypeError)
642
892
  end
893
+
894
+ should "do nothing if destroy is called again" do
895
+ @doc.destroy.should be_false
896
+ end
643
897
  end
644
898
 
645
899
  context "Destroying a document that is a new" do
@@ -660,6 +914,10 @@ class DocumentTest < Test::Unit::TestCase
660
914
  end
661
915
 
662
916
  context "timestamping" do
917
+ setup do
918
+ @document.timestamps!
919
+ end
920
+
663
921
  should "set created_at and updated_at on create" do
664
922
  doc = @document.new(:first_name => 'John', :age => 27)
665
923
  doc.created_at.should be(nil)
@@ -679,13 +937,16 @@ class DocumentTest < Test::Unit::TestCase
679
937
  doc.updated_at.should_not == old_updated_at
680
938
  end
681
939
 
682
- should_eventually "set updated_at on document update but leave created_at alone" do
940
+ should "set updated_at on document update but leave created_at alone" do
683
941
  doc = @document.create(:first_name => 'John', :age => 27)
684
942
  old_created_at = doc.created_at
685
943
  old_updated_at = doc.updated_at
686
- doc = @document.update(old._id, { :first_name => 'Johnny' })
687
- doc.created_at.should == old_created_at
688
- doc.updated_at.should_not == old_updated_at
944
+ sleep 1 # this annoys me
945
+ @document.update(doc._id, { :first_name => 'Johnny' })
946
+
947
+ from_db = @document.find(doc.id)
948
+ from_db.created_at.to_i.should == old_created_at.to_i
949
+ from_db.updated_at.to_i.should_not == old_updated_at.to_i
689
950
  end
690
951
  end
691
- end
952
+ end
@@ -18,9 +18,8 @@ class TestRailsCompatibility < Test::Unit::TestCase
18
18
  end
19
19
 
20
20
  should "have to_param that returns id" do
21
- id = MongoID.new
22
- instance = Order.create('_id' => id.to_s)
23
- instance.to_param.should == id.to_s
21
+ instance = Order.create('_id' => 1234)
22
+ instance.to_param.should == '1234'
24
23
  end
25
24
 
26
25
  should "alias new to new_record?" do
data/test/models.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  class Address
2
2
  include MongoMapper::EmbeddedDocument
3
+
3
4
  key :address, String
4
5
  key :city, String
5
6
  key :state, String
@@ -8,7 +9,12 @@ end
8
9
 
9
10
  class Message
10
11
  include MongoMapper::Document
12
+
11
13
  key :body, String
14
+ key :position, Integer
15
+ key :_type, String
16
+ key :room_id, String
17
+
12
18
  belongs_to :room
13
19
  end
14
20
 
@@ -18,12 +24,14 @@ class Chat < Message; end
18
24
 
19
25
  class Room
20
26
  include MongoMapper::Document
27
+
21
28
  key :name, String
22
29
  many :messages, :polymorphic => true
23
30
  end
24
31
 
25
32
  class Project
26
33
  include MongoMapper::Document
34
+
27
35
  key :name, String
28
36
  many :statuses
29
37
  many :addresses
@@ -31,32 +39,48 @@ end
31
39
 
32
40
  class Status
33
41
  include MongoMapper::Document
42
+
43
+ key :project_id, String
44
+ key :target_id, String
45
+ key :target_type, String
46
+ key :name, String
47
+ key :position, Integer
48
+
34
49
  belongs_to :project
35
50
  belongs_to :target, :polymorphic => true
36
- key :name, String
37
51
  end
38
52
 
39
53
  class RealPerson
40
54
  include MongoMapper::Document
41
- many :pets
55
+
56
+ many :pets
42
57
  key :name, String
58
+
59
+ def realname=(n)
60
+ self.name = n
61
+ end
43
62
  end
44
63
 
45
64
  class Person
46
65
  include MongoMapper::EmbeddedDocument
66
+
47
67
  key :name, String
48
68
  key :child, Person
69
+
49
70
  many :pets
50
71
  end
51
72
 
52
73
  class Pet
53
74
  include MongoMapper::EmbeddedDocument
75
+
54
76
  key :name, String
55
77
  key :species, String
56
78
  end
57
79
 
58
80
  class Media
59
81
  include MongoMapper::EmbeddedDocument
82
+
83
+ key :_type, String
60
84
  key :file, String
61
85
  end
62
86
 
@@ -75,34 +99,41 @@ end
75
99
 
76
100
  class Catalog
77
101
  include MongoMapper::Document
102
+
78
103
  many :medias, :polymorphic => true
79
104
  end
80
105
 
81
106
  module TrModels
82
107
  class Transport
83
108
  include MongoMapper::EmbeddedDocument
109
+
110
+ key :_type, String
84
111
  key :license_plate, String
85
112
  end
86
-
113
+
87
114
  class Car < TrModels::Transport
88
115
  include MongoMapper::EmbeddedDocument
116
+
89
117
  key :model, String
90
118
  key :year, Integer
91
119
  end
92
-
120
+
93
121
  class Bus < TrModels::Transport
94
122
  include MongoMapper::EmbeddedDocument
123
+
95
124
  key :max_passengers, Integer
96
125
  end
97
-
126
+
98
127
  class Ambulance < TrModels::Transport
99
128
  include MongoMapper::EmbeddedDocument
129
+
100
130
  key :icu, Boolean
101
131
  end
102
-
132
+
103
133
  class Fleet
104
134
  include MongoMapper::Document
135
+
105
136
  many :transports, :polymorphic => true, :class_name => "TrModels::Transport"
106
- key :name, String
137
+ key :name, String
107
138
  end
108
- end
139
+ end
@@ -51,7 +51,7 @@ class JsonSerializationTest < Test::Unit::TestCase
51
51
  should "allow attribute filtering with except" do
52
52
  json = @contact.to_json(:except => [:name, :age])
53
53
 
54
- assert_match %r{"_id"}, json
54
+ assert_no_match %r{"_id"}, json
55
55
  assert_no_match %r{"name"}, json
56
56
  assert_no_match %r{"age"}, json
57
57
  assert_match %r{"awesome"}, json
@@ -59,26 +59,60 @@ class JsonSerializationTest < Test::Unit::TestCase
59
59
  assert_match %r{"preferences"}, json
60
60
  end
61
61
 
62
- context "including methods" do
62
+ context "_id key" do
63
+ should "not be included by default" do
64
+ json = @contact.to_json
65
+ assert_no_match %r{"_id":}, json
66
+ end
67
+
68
+ should "not be included even if :except is used" do
69
+ json = @contact.to_json(:except => :name)
70
+ assert_no_match %r{"_id":}, json
71
+ end
72
+ end
73
+
74
+ context "id method" do
63
75
  setup do
64
76
  def @contact.label; "Has cheezburger"; end
65
77
  def @contact.favorite_quote; "Constraints are liberating"; end
66
78
  end
67
79
 
68
- should "include label method" do
80
+ should "be included by default" do
81
+ json = @contact.to_json
82
+ assert_match %r{"id"}, json
83
+ end
84
+
85
+ should "be included when single method included" do
69
86
  json = @contact.to_json(:methods => :label)
87
+ assert_match %r{"id"}, json
70
88
  assert_match %r{"label":"Has cheezburger"}, json
89
+ assert_match %r{"name":"Konata Izumi"}, json
90
+ assert_no_match %r{"favorite_quote":"Constraints are liberating"}, json
71
91
  end
72
92
 
73
- should "include name and label method" do
74
- json = @contact.to_json(:only => :name, :methods => :label)
75
-
93
+ should "be included when multiple methods included" do
94
+ json = @contact.to_json(:methods => [:label, :favorite_quote])
95
+ assert_match %r{"id"}, json
76
96
  assert_match %r{"label":"Has cheezburger"}, json
97
+ assert_match %r{"favorite_quote":"Constraints are liberating"}, json
77
98
  assert_match %r{"name":"Konata Izumi"}, json
78
- assert_no_match %r{"age":16}, json
79
- assert_no_match %r{"awesome"}, json
80
- assert_no_match %r{"created_at"}, json
81
- assert_no_match %r{"preferences"}, json
99
+ end
100
+
101
+ should "not be included if :only is present" do
102
+ json = @contact.to_json(:only => :name)
103
+ assert_no_match %r{"id":}, json
104
+ end
105
+ end
106
+
107
+ context "including methods" do
108
+ setup do
109
+ def @contact.label; "Has cheezburger"; end
110
+ def @contact.favorite_quote; "Constraints are liberating"; end
111
+ end
112
+
113
+ should "include single method" do
114
+ json = @contact.to_json(:methods => :label)
115
+ assert_match %r{"label":"Has cheezburger"}, json
82
116
  end
83
117
 
84
118
  should "include multiple methods" do
@@ -106,8 +140,8 @@ class JsonSerializationTest < Test::Unit::TestCase
106
140
  end
107
141
 
108
142
  should "allow attribute filtering with except" do
109
- json = @contacts.to_json(:except => [:name, :preferences, :awesome, :created_at, :updated_at, :_id])
110
- assert_equal %([{"id":"","age":39},{"id":"","age":14}]), json
143
+ json = @contacts.to_json(:except => [:name, :preferences, :awesome, :created_at, :updated_at])
144
+ assert_equal %([{"id":null,"age":39},{"id":null,"age":14}]), json
111
145
  end
112
146
  end
113
147
 
@@ -78,8 +78,16 @@ class AssociationBaseTest < Test::Unit::TestCase
78
78
  end
79
79
  end
80
80
 
81
- should "have belongs_to_key_name" do
82
- Base.new(:belongs_to, :foo).belongs_to_key_name.should == 'foo_id'
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
83
91
  end
84
92
 
85
93
  should "have ivar that is association name" do