djsun-mongomapper 0.3.5.5 → 0.4.1.2

Sign up to get free protection for your applications and to get access to all the features.
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