djsun-mongomapper 0.3.5.5 → 0.4.1.2

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 (44) hide show
  1. data/README.rdoc +38 -38
  2. data/Rakefile +87 -73
  3. data/VERSION +1 -1
  4. data/lib/mongomapper.rb +67 -71
  5. data/lib/mongomapper/associations.rb +86 -84
  6. data/lib/mongomapper/associations/belongs_to_polymorphic_proxy.rb +34 -34
  7. data/lib/mongomapper/associations/many_embedded_proxy.rb +67 -17
  8. data/lib/mongomapper/associations/proxy.rb +74 -73
  9. data/lib/mongomapper/document.rb +342 -348
  10. data/lib/mongomapper/embedded_document.rb +354 -274
  11. data/lib/mongomapper/finder_options.rb +84 -84
  12. data/lib/mongomapper/key.rb +32 -76
  13. data/lib/mongomapper/rails_compatibility/document.rb +14 -14
  14. data/lib/mongomapper/rails_compatibility/embedded_document.rb +26 -24
  15. data/lib/mongomapper/support.rb +156 -29
  16. data/lib/mongomapper/validations.rb +69 -47
  17. data/test/custom_matchers.rb +48 -0
  18. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +53 -56
  19. data/test/functional/associations/test_belongs_to_proxy.rb +48 -49
  20. data/test/functional/associations/test_many_documents_as_proxy.rb +208 -253
  21. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +130 -130
  22. data/test/functional/associations/test_many_embedded_proxy.rb +168 -106
  23. data/test/functional/associations/test_many_polymorphic_proxy.rb +261 -262
  24. data/test/functional/test_binary.rb +21 -0
  25. data/test/functional/test_document.rb +946 -952
  26. data/test/functional/test_embedded_document.rb +98 -0
  27. data/test/functional/test_pagination.rb +87 -80
  28. data/test/functional/test_rails_compatibility.rb +29 -29
  29. data/test/functional/test_validations.rb +262 -172
  30. data/test/models.rb +169 -169
  31. data/test/test_helper.rb +28 -66
  32. data/test/unit/serializers/test_json_serializer.rb +193 -193
  33. data/test/unit/test_document.rb +161 -123
  34. data/test/unit/test_embedded_document.rb +643 -547
  35. data/test/unit/test_finder_options.rb +183 -183
  36. data/test/unit/test_key.rb +175 -247
  37. data/test/unit/test_rails_compatibility.rb +38 -33
  38. data/test/unit/test_serializations.rb +52 -52
  39. data/test/unit/test_support.rb +268 -0
  40. data/test/unit/test_time_zones.rb +40 -0
  41. data/test/unit/test_validations.rb +499 -258
  42. metadata +22 -12
  43. data/History +0 -76
  44. data/mongomapper.gemspec +0 -145
@@ -1,169 +1,169 @@
1
- class Post
2
- include MongoMapper::Document
3
-
4
- key :title, String
5
- key :body, String
6
-
7
- has_many :comments, :as => :commentable, :class_name => 'PostComment'
8
-
9
- timestamps!
10
- end
11
-
12
- class PostComment
13
- include MongoMapper::Document
14
-
15
- key :username, String, :default => 'Anonymous'
16
- key :body, String
17
-
18
- key :commentable_id, String
19
- key :commentable_type, String
20
- belongs_to :commentable, :polymorphic => true
21
-
22
- timestamps!
23
- end
24
-
25
- class Address
26
- include MongoMapper::EmbeddedDocument
27
-
28
- key :address, String
29
- key :city, String
30
- key :state, String
31
- key :zip, Integer
32
- end
33
-
34
- class Message
35
- include MongoMapper::Document
36
-
37
- key :body, String
38
- key :position, Integer
39
- key :_type, String
40
- key :room_id, String
41
-
42
- belongs_to :room
43
- end
44
-
45
- class Answer
46
- include MongoMapper::Document
47
-
48
- key :body, String
49
- end
50
-
51
- class Enter < Message; end
52
- class Exit < Message; end
53
- class Chat < Message; end
54
-
55
- class Room
56
- include MongoMapper::Document
57
-
58
- key :name, String
59
- many :messages, :polymorphic => true
60
- end
61
-
62
- class Project
63
- include MongoMapper::Document
64
-
65
- key :name, String
66
- many :statuses
67
- many :addresses
68
- end
69
-
70
- class Status
71
- include MongoMapper::Document
72
-
73
- key :project_id, String
74
- key :target_id, String
75
- key :target_type, String
76
- key :name, String
77
- key :position, Integer
78
-
79
- belongs_to :project
80
- belongs_to :target, :polymorphic => true
81
- end
82
-
83
- class RealPerson
84
- include MongoMapper::Document
85
-
86
- many :pets
87
- key :name, String
88
-
89
- def realname=(n)
90
- self.name = n
91
- end
92
- end
93
-
94
- class Person
95
- include MongoMapper::EmbeddedDocument
96
-
97
- key :name, String
98
- key :child, Person
99
-
100
- many :pets
101
- end
102
-
103
- class Pet
104
- include MongoMapper::EmbeddedDocument
105
-
106
- key :name, String
107
- key :species, String
108
- end
109
-
110
- class Media
111
- include MongoMapper::EmbeddedDocument
112
-
113
- key :_type, String
114
- key :file, String
115
- end
116
-
117
- class Video < Media
118
- key :length, Integer
119
- end
120
-
121
- class Image < Media
122
- key :width, Integer
123
- key :height, Integer
124
- end
125
-
126
- class Music < Media
127
- key :bitrate, String
128
- end
129
-
130
- class Catalog
131
- include MongoMapper::Document
132
-
133
- many :medias, :polymorphic => true
134
- end
135
-
136
- module TrModels
137
- class Transport
138
- include MongoMapper::EmbeddedDocument
139
-
140
- key :_type, String
141
- key :license_plate, String
142
- end
143
-
144
- class Car < TrModels::Transport
145
- include MongoMapper::EmbeddedDocument
146
-
147
- key :model, String
148
- key :year, Integer
149
- end
150
-
151
- class Bus < TrModels::Transport
152
- include MongoMapper::EmbeddedDocument
153
-
154
- key :max_passengers, Integer
155
- end
156
-
157
- class Ambulance < TrModels::Transport
158
- include MongoMapper::EmbeddedDocument
159
-
160
- key :icu, Boolean
161
- end
162
-
163
- class Fleet
164
- include MongoMapper::Document
165
-
166
- many :transports, :polymorphic => true, :class_name => "TrModels::Transport"
167
- key :name, String
168
- end
169
- end
1
+ class Post
2
+ include MongoMapper::Document
3
+
4
+ key :title, String
5
+ key :body, String
6
+
7
+ has_many :comments, :as => :commentable, :class_name => 'PostComment'
8
+
9
+ timestamps!
10
+ end
11
+
12
+ class PostComment
13
+ include MongoMapper::Document
14
+
15
+ key :username, String, :default => 'Anonymous'
16
+ key :body, String
17
+
18
+ key :commentable_id, String
19
+ key :commentable_type, String
20
+ belongs_to :commentable, :polymorphic => true
21
+
22
+ timestamps!
23
+ end
24
+
25
+ class Address
26
+ include MongoMapper::EmbeddedDocument
27
+
28
+ key :address, String
29
+ key :city, String
30
+ key :state, String
31
+ key :zip, Integer
32
+ end
33
+
34
+ class Message
35
+ include MongoMapper::Document
36
+
37
+ key :body, String
38
+ key :position, Integer
39
+ key :_type, String
40
+ key :room_id, String
41
+
42
+ belongs_to :room
43
+ end
44
+
45
+ class Answer
46
+ include MongoMapper::Document
47
+
48
+ key :body, String
49
+ end
50
+
51
+ class Enter < Message; end
52
+ class Exit < Message; end
53
+ class Chat < Message; end
54
+
55
+ class Room
56
+ include MongoMapper::Document
57
+
58
+ key :name, String
59
+ many :messages, :polymorphic => true
60
+ end
61
+
62
+ class Project
63
+ include MongoMapper::Document
64
+
65
+ key :name, String
66
+ many :statuses
67
+ many :addresses
68
+ end
69
+
70
+ class Status
71
+ include MongoMapper::Document
72
+
73
+ key :project_id, String
74
+ key :target_id, String
75
+ key :target_type, String
76
+ key :name, String
77
+ key :position, Integer
78
+
79
+ belongs_to :project
80
+ belongs_to :target, :polymorphic => true
81
+ end
82
+
83
+ class RealPerson
84
+ include MongoMapper::Document
85
+
86
+ many :pets
87
+ key :name, String
88
+
89
+ def realname=(n)
90
+ self.name = n
91
+ end
92
+ end
93
+
94
+ class Person
95
+ include MongoMapper::EmbeddedDocument
96
+
97
+ key :name, String
98
+ key :child, Person
99
+
100
+ many :pets
101
+ end
102
+
103
+ class Pet
104
+ include MongoMapper::EmbeddedDocument
105
+
106
+ key :name, String
107
+ key :species, String
108
+ end
109
+
110
+ class Media
111
+ include MongoMapper::EmbeddedDocument
112
+
113
+ key :_type, String
114
+ key :file, String
115
+ end
116
+
117
+ class Video < Media
118
+ key :length, Integer
119
+ end
120
+
121
+ class Image < Media
122
+ key :width, Integer
123
+ key :height, Integer
124
+ end
125
+
126
+ class Music < Media
127
+ key :bitrate, String
128
+ end
129
+
130
+ class Catalog
131
+ include MongoMapper::Document
132
+
133
+ many :medias, :polymorphic => true
134
+ end
135
+
136
+ module TrModels
137
+ class Transport
138
+ include MongoMapper::EmbeddedDocument
139
+
140
+ key :_type, String
141
+ key :license_plate, String
142
+ end
143
+
144
+ class Car < TrModels::Transport
145
+ include MongoMapper::EmbeddedDocument
146
+
147
+ key :model, String
148
+ key :year, Integer
149
+ end
150
+
151
+ class Bus < TrModels::Transport
152
+ include MongoMapper::EmbeddedDocument
153
+
154
+ key :max_passengers, Integer
155
+ end
156
+
157
+ class Ambulance < TrModels::Transport
158
+ include MongoMapper::EmbeddedDocument
159
+
160
+ key :icu, Boolean
161
+ end
162
+
163
+ class Fleet
164
+ include MongoMapper::Document
165
+
166
+ many :transports, :polymorphic => true, :class_name => "TrModels::Transport"
167
+ key :name, String
168
+ end
169
+ end
@@ -1,67 +1,29 @@
1
- require 'pathname'
2
- require 'pp'
3
- require 'rubygems'
4
- require 'test/unit'
5
- require 'shoulda'
6
-
7
- gem 'mocha', '0.9.4'
8
- gem 'jnunemaker-matchy', '0.4.0'
9
-
10
- require 'matchy'
11
- require 'mocha'
12
-
13
- $LOAD_PATH.unshift(File.dirname(__FILE__))
14
- dir = (Pathname(__FILE__).dirname + '..' + 'lib').expand_path
15
- require dir + 'mongomapper'
16
-
17
- class Test::Unit::TestCase
18
- def clear_all_collections
19
- MongoMapper::Document.descendants.map(&:delete_all)
20
- end
21
-
22
- custom_matcher :be_nil do |receiver, matcher, args|
23
- matcher.positive_failure_message = "Expected #{receiver} to be nil but it wasn't"
24
- matcher.negative_failure_message = "Expected #{receiver} not to be nil but it was"
25
- receiver.nil?
26
- end
27
-
28
- custom_matcher :be_true do |receiver, matcher, args|
29
- matcher.positive_failure_message = "Expected #{receiver} to be true but it wasn't"
30
- matcher.negative_failure_message = "Expected #{receiver} not to be true but it was"
31
- receiver.eql?(true)
32
- end
33
-
34
- custom_matcher :be_false do |receiver, matcher, args|
35
- matcher.positive_failure_message = "Expected #{receiver} to be false but it wasn't"
36
- matcher.negative_failure_message = "Expected #{receiver} not to be false but it was"
37
- receiver.eql?(false)
38
- end
39
-
40
- custom_matcher :be_valid do |receiver, matcher, args|
41
- matcher.positive_failure_message = "Expected to be valid but it was invalid #{receiver.errors.inspect}"
42
- matcher.negative_failure_message = "Expected to be invalid but it was valid #{receiver.errors.inspect}"
43
- receiver.valid?
44
- end
45
-
46
- custom_matcher :have_error_on do |receiver, matcher, args|
47
- receiver.valid?
48
- attribute = args[0]
49
- expected_message = args[1]
50
-
51
- if expected_message.nil?
52
- matcher.positive_failure_message = "#{receiver} had no errors on #{attribute}"
53
- matcher.negative_failure_message = "#{receiver} had errors on #{attribute} #{receiver.errors.inspect}"
54
- !receiver.errors.on(attribute).blank?
55
- else
56
- actual = receiver.errors.on(attribute)
57
- matcher.positive_failure_message = %Q(Expected error on #{attribute} to be "#{expected_message}" but was "#{actual}")
58
- matcher.negative_failure_message = %Q(Expected error on #{attribute} not to be "#{expected_message}" but was "#{actual}")
59
- actual == expected_message
60
- end
61
- end
62
- end
63
-
64
- DefaultDatabase = 'test' unless defined?(DefaultDatabase)
65
- AlternateDatabase = 'test2' unless defined?(AlternateDatabase)
66
-
1
+ require 'pathname'
2
+ require 'pp'
3
+ require 'rubygems'
4
+ require 'shoulda'
5
+
6
+ gem 'mocha', '0.9.4'
7
+ gem 'jnunemaker-matchy', '0.4.0'
8
+
9
+ require 'matchy'
10
+ require 'mocha'
11
+ require 'custom_matchers'
12
+
13
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
14
+ dir = (Pathname(__FILE__).dirname + '..' + 'lib').expand_path
15
+ require dir + 'mongomapper'
16
+
17
+ class Test::Unit::TestCase
18
+ include CustomMatchers
19
+
20
+ def clear_all_collections
21
+ MongoMapper::Document.descendants.map { |d| d.collection.clear }
22
+ end
23
+ end
24
+
25
+ DefaultDatabase = 'test' unless defined?(DefaultDatabase)
26
+ AlternateDatabase = 'test2' unless defined?(AlternateDatabase)
27
+
28
+ MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017)
67
29
  MongoMapper.database = DefaultDatabase
@@ -1,193 +1,193 @@
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
- key :hiding, String
17
-
18
- many :tags, :class_name => 'JsonSerializationTest::Tag'
19
- end
20
-
21
- def setup
22
- Contact.include_root_in_json = false
23
- @contact = Contact.new(
24
- :name => 'Konata Izumi',
25
- :age => 16,
26
- :created_at => Time.utc(2006, 8, 1),
27
- :awesome => true,
28
- :preferences => { :shows => 'anime' }
29
- )
30
- end
31
-
32
- should "include demodulized root" do
33
- Contact.include_root_in_json = true
34
- assert_match %r{^\{"contact": \{}, @contact.to_json
35
- end
36
-
37
- should "encode all encodable attributes" do
38
- json = @contact.to_json
39
-
40
- assert_no_match %r{"_id"}, json
41
- assert_match %r{"name":"Konata Izumi"}, json
42
- assert_match %r{"age":16}, json
43
- assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
44
- assert_match %r{"awesome":true}, json
45
- assert_match %r{"preferences":\{"shows":"anime"\}}, json
46
- assert_match %r{"hiding":null}, json
47
- end
48
-
49
- should "allow attribute filtering with only" do
50
- json = @contact.to_json(:only => [:name, :age])
51
-
52
- assert_no_match %r{"_id"}, json
53
- assert_match %r{"name":"Konata Izumi"}, json
54
- assert_match %r{"age":16}, json
55
- assert_no_match %r{"awesome"}, json
56
- assert_no_match %r{"created_at"}, json
57
- assert_no_match %r{"preferences"}, json
58
- assert_no_match %r{"hiding"}, json
59
- end
60
-
61
- should "allow attribute filtering with except" do
62
- json = @contact.to_json(:except => [:name, :age])
63
-
64
- assert_no_match %r{"_id"}, json
65
- assert_no_match %r{"name"}, json
66
- assert_no_match %r{"age"}, json
67
- assert_match %r{"awesome"}, json
68
- assert_match %r{"created_at"}, json
69
- assert_match %r{"preferences"}, json
70
- assert_match %r{"hiding"}, json
71
- end
72
-
73
- context "_id key" do
74
- should "not be included by default" do
75
- json = @contact.to_json
76
- assert_no_match %r{"_id":}, json
77
- end
78
-
79
- should "not be included even if :except is used" do
80
- json = @contact.to_json(:except => :name)
81
- assert_no_match %r{"_id":}, json
82
- end
83
- end
84
-
85
- context "id method" do
86
- setup do
87
- def @contact.label; "Has cheezburger"; end
88
- def @contact.favorite_quote; "Constraints are liberating"; end
89
- end
90
-
91
- should "be included by default" do
92
- json = @contact.to_json
93
- assert_match %r{"id"}, json
94
- end
95
-
96
- should "be included when single method included" do
97
- json = @contact.to_json(:methods => :label)
98
- assert_match %r{"id"}, json
99
- assert_match %r{"label":"Has cheezburger"}, json
100
- assert_match %r{"name":"Konata Izumi"}, json
101
- assert_no_match %r{"favorite_quote":"Constraints are liberating"}, json
102
- end
103
-
104
- should "be included when multiple methods included" do
105
- json = @contact.to_json(:methods => [:label, :favorite_quote])
106
- assert_match %r{"id"}, json
107
- assert_match %r{"label":"Has cheezburger"}, json
108
- assert_match %r{"favorite_quote":"Constraints are liberating"}, json
109
- assert_match %r{"name":"Konata Izumi"}, json
110
- end
111
-
112
- should "not be included if :only is present" do
113
- json = @contact.to_json(:only => :name)
114
- assert_no_match %r{"id":}, json
115
- end
116
- end
117
-
118
- context "including methods" do
119
- setup do
120
- def @contact.label; "Has cheezburger"; end
121
- def @contact.favorite_quote; "Constraints are liberating"; end
122
- end
123
-
124
- should "include single method" do
125
- json = @contact.to_json(:methods => :label)
126
- assert_match %r{"label":"Has cheezburger"}, json
127
- end
128
-
129
- should "include multiple methods" do
130
- json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
131
- assert_match %r{"label":"Has cheezburger"}, json
132
- assert_match %r{"favorite_quote":"Constraints are liberating"}, json
133
- assert_match %r{"name":"Konata Izumi"}, json
134
- assert_no_match %r{"age":16}, json
135
- assert_no_match %r{"awesome"}, json
136
- assert_no_match %r{"created_at"}, json
137
- assert_no_match %r{"preferences"}, json
138
- end
139
- end
140
-
141
- context "array of records" do
142
- setup do
143
- @contacts = [
144
- Contact.new(:name => 'David', :age => 39),
145
- Contact.new(:name => 'Mary', :age => 14)
146
- ]
147
- end
148
-
149
- should "allow attribute filtering with only" do
150
- json = @contacts.to_json(:only => :name)
151
- assert_match %r{\{"name":"David"\}}, json
152
- assert_match %r{\{"name":"Mary"\}}, json
153
- end
154
-
155
- should "allow attribute filtering with except" do
156
- json = @contacts.to_json(:except => [:name, :preferences, :awesome, :created_at, :updated_at])
157
- assert_match %r{"age":39}, json
158
- assert_match %r{"age":14}, json
159
- assert_no_match %r{"name":}, json
160
- assert_no_match %r{"preferences":}, json
161
- assert_no_match %r{"awesome":}, json
162
- assert_no_match %r{"created_at":}, json
163
- assert_no_match %r{"updated_at":}, json
164
- end
165
- end
166
-
167
- should "allow options for hash of records" do
168
- contacts = {
169
- 1 => Contact.new(:name => 'David', :age => 39),
170
- 2 => Contact.new(:name => 'Mary', :age => 14)
171
- }
172
- json = contacts.to_json(:only => [1, :name])
173
- assert_match %r{"1":}, json
174
- assert_match %r{\{"name":"David"\}}, json
175
- assert_no_match %r{"2":}, json
176
- end
177
-
178
- should "include embedded attributes" do
179
- contact = Contact.new(:name => 'John', :age => 27)
180
- contact.tags = [Tag.new(:name => 'awesome'), Tag.new(:name => 'ruby')]
181
- json = contact.to_json
182
- assert_match %r{"tags":}, json
183
- assert_match %r{"name":"awesome"}, json
184
- assert_match %r{"name":"ruby"}, json
185
- end
186
-
187
- should "include dynamic attributes" do
188
- contact = Contact.new(:name => 'John', :age => 27, :foo => 'bar')
189
- contact['smell'] = 'stinky'
190
- json = contact.to_json
191
- assert_match %r{"smell":"stinky"}, json
192
- end
193
- end
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
+ key :hiding, String
17
+
18
+ many :tags, :class_name => 'JsonSerializationTest::Tag'
19
+ end
20
+
21
+ def setup
22
+ Contact.include_root_in_json = false
23
+ @contact = Contact.new(
24
+ :name => 'Konata Izumi',
25
+ :age => 16,
26
+ :created_at => Time.utc(2006, 8, 1),
27
+ :awesome => true,
28
+ :preferences => { :shows => 'anime' }
29
+ )
30
+ end
31
+
32
+ should "include demodulized root" do
33
+ Contact.include_root_in_json = true
34
+ assert_match %r{^\{"contact": \{}, @contact.to_json
35
+ end
36
+
37
+ should "encode all encodable attributes" do
38
+ json = @contact.to_json
39
+
40
+ assert_no_match %r{"_id"}, json
41
+ assert_match %r{"name":"Konata Izumi"}, json
42
+ assert_match %r{"age":16}, json
43
+ assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
44
+ assert_match %r{"awesome":true}, json
45
+ assert_match %r{"preferences":\{"shows":"anime"\}}, json
46
+ assert_match %r{"hiding":null}, json
47
+ end
48
+
49
+ should "allow attribute filtering with only" do
50
+ json = @contact.to_json(:only => [:name, :age])
51
+
52
+ assert_no_match %r{"_id"}, json
53
+ assert_match %r{"name":"Konata Izumi"}, json
54
+ assert_match %r{"age":16}, json
55
+ assert_no_match %r{"awesome"}, json
56
+ assert_no_match %r{"created_at"}, json
57
+ assert_no_match %r{"preferences"}, json
58
+ assert_no_match %r{"hiding"}, json
59
+ end
60
+
61
+ should "allow attribute filtering with except" do
62
+ json = @contact.to_json(:except => [:name, :age])
63
+
64
+ assert_no_match %r{"_id"}, json
65
+ assert_no_match %r{"name"}, json
66
+ assert_no_match %r{"age"}, json
67
+ assert_match %r{"awesome"}, json
68
+ assert_match %r{"created_at"}, json
69
+ assert_match %r{"preferences"}, json
70
+ assert_match %r{"hiding"}, json
71
+ end
72
+
73
+ context "_id key" do
74
+ should "not be included by default" do
75
+ json = @contact.to_json
76
+ assert_no_match %r{"_id":}, json
77
+ end
78
+
79
+ should "not be included even if :except is used" do
80
+ json = @contact.to_json(:except => :name)
81
+ assert_no_match %r{"_id":}, json
82
+ end
83
+ end
84
+
85
+ context "id method" do
86
+ setup do
87
+ def @contact.label; "Has cheezburger"; end
88
+ def @contact.favorite_quote; "Constraints are liberating"; end
89
+ end
90
+
91
+ should "be included by default" do
92
+ json = @contact.to_json
93
+ assert_match %r{"id"}, json
94
+ end
95
+
96
+ should "be included when single method included" do
97
+ json = @contact.to_json(:methods => :label)
98
+ assert_match %r{"id"}, json
99
+ assert_match %r{"label":"Has cheezburger"}, json
100
+ assert_match %r{"name":"Konata Izumi"}, json
101
+ assert_no_match %r{"favorite_quote":"Constraints are liberating"}, json
102
+ end
103
+
104
+ should "be included when multiple methods included" do
105
+ json = @contact.to_json(:methods => [:label, :favorite_quote])
106
+ assert_match %r{"id"}, json
107
+ assert_match %r{"label":"Has cheezburger"}, json
108
+ assert_match %r{"favorite_quote":"Constraints are liberating"}, json
109
+ assert_match %r{"name":"Konata Izumi"}, json
110
+ end
111
+
112
+ should "not be included if :only is present" do
113
+ json = @contact.to_json(:only => :name)
114
+ assert_no_match %r{"id":}, json
115
+ end
116
+ end
117
+
118
+ context "including methods" do
119
+ setup do
120
+ def @contact.label; "Has cheezburger"; end
121
+ def @contact.favorite_quote; "Constraints are liberating"; end
122
+ end
123
+
124
+ should "include single method" do
125
+ json = @contact.to_json(:methods => :label)
126
+ assert_match %r{"label":"Has cheezburger"}, json
127
+ end
128
+
129
+ should "include multiple methods" do
130
+ json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
131
+ assert_match %r{"label":"Has cheezburger"}, json
132
+ assert_match %r{"favorite_quote":"Constraints are liberating"}, json
133
+ assert_match %r{"name":"Konata Izumi"}, json
134
+ assert_no_match %r{"age":16}, json
135
+ assert_no_match %r{"awesome"}, json
136
+ assert_no_match %r{"created_at"}, json
137
+ assert_no_match %r{"preferences"}, json
138
+ end
139
+ end
140
+
141
+ context "array of records" do
142
+ setup do
143
+ @contacts = [
144
+ Contact.new(:name => 'David', :age => 39),
145
+ Contact.new(:name => 'Mary', :age => 14)
146
+ ]
147
+ end
148
+
149
+ should "allow attribute filtering with only" do
150
+ json = @contacts.to_json(:only => :name)
151
+ assert_match %r{\{"name":"David"\}}, json
152
+ assert_match %r{\{"name":"Mary"\}}, json
153
+ end
154
+
155
+ should "allow attribute filtering with except" do
156
+ json = @contacts.to_json(:except => [:name, :preferences, :awesome, :created_at, :updated_at])
157
+ assert_match %r{"age":39}, json
158
+ assert_match %r{"age":14}, json
159
+ assert_no_match %r{"name":}, json
160
+ assert_no_match %r{"preferences":}, json
161
+ assert_no_match %r{"awesome":}, json
162
+ assert_no_match %r{"created_at":}, json
163
+ assert_no_match %r{"updated_at":}, json
164
+ end
165
+ end
166
+
167
+ should "allow options for hash of records" do
168
+ contacts = {
169
+ 1 => Contact.new(:name => 'David', :age => 39),
170
+ 2 => Contact.new(:name => 'Mary', :age => 14)
171
+ }
172
+ json = contacts.to_json(:only => [1, :name])
173
+ assert_match %r{"1":}, json
174
+ assert_match %r{\{"name":"David"\}}, json
175
+ assert_no_match %r{"2":}, json
176
+ end
177
+
178
+ should "include embedded attributes" do
179
+ contact = Contact.new(:name => 'John', :age => 27)
180
+ contact.tags = [Tag.new(:name => 'awesome'), Tag.new(:name => 'ruby')]
181
+ json = contact.to_json
182
+ assert_match %r{"tags":}, json
183
+ assert_match %r{"name":"awesome"}, json
184
+ assert_match %r{"name":"ruby"}, json
185
+ end
186
+
187
+ should "include dynamic attributes" do
188
+ contact = Contact.new(:name => 'John', :age => 27, :foo => 'bar')
189
+ contact['smell'] = 'stinky'
190
+ json = contact.to_json
191
+ assert_match %r{"smell":"stinky"}, json
192
+ end
193
+ end