drogus-mongo_mapper 0.6.10

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 (91) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +29 -0
  4. data/Rakefile +55 -0
  5. data/VERSION +1 -0
  6. data/bin/mmconsole +60 -0
  7. data/lib/mongo_mapper.rb +131 -0
  8. data/lib/mongo_mapper/document.rb +417 -0
  9. data/lib/mongo_mapper/embedded_document.rb +55 -0
  10. data/lib/mongo_mapper/finder_options.rb +127 -0
  11. data/lib/mongo_mapper/plugins.rb +30 -0
  12. data/lib/mongo_mapper/plugins/associations.rb +104 -0
  13. data/lib/mongo_mapper/plugins/associations/base.rb +121 -0
  14. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  15. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  16. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  17. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +50 -0
  18. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +139 -0
  19. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  20. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +117 -0
  21. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  22. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  23. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  24. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  25. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  26. data/lib/mongo_mapper/plugins/callbacks.rb +134 -0
  27. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  28. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  29. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  30. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  31. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  32. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  33. data/lib/mongo_mapper/plugins/keys.rb +324 -0
  34. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  35. data/lib/mongo_mapper/plugins/pagination.rb +85 -0
  36. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  37. data/lib/mongo_mapper/plugins/rails.rb +45 -0
  38. data/lib/mongo_mapper/plugins/serialization.rb +105 -0
  39. data/lib/mongo_mapper/plugins/validations.rb +57 -0
  40. data/lib/mongo_mapper/support.rb +217 -0
  41. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  42. data/lib/mongo_mapper/support/find.rb +77 -0
  43. data/mongo_mapper.gemspec +195 -0
  44. data/performance/read_write.rb +52 -0
  45. data/specs.watchr +51 -0
  46. data/test/NOTE_ON_TESTING +1 -0
  47. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  48. data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
  49. data/test/functional/associations/test_in_array_proxy.rb +309 -0
  50. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  51. data/test/functional/associations/test_many_documents_proxy.rb +431 -0
  52. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  53. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  54. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  55. data/test/functional/associations/test_one_proxy.rb +161 -0
  56. data/test/functional/test_associations.rb +44 -0
  57. data/test/functional/test_binary.rb +27 -0
  58. data/test/functional/test_callbacks.rb +81 -0
  59. data/test/functional/test_dirty.rb +163 -0
  60. data/test/functional/test_document.rb +1264 -0
  61. data/test/functional/test_embedded_document.rb +125 -0
  62. data/test/functional/test_identity_map.rb +508 -0
  63. data/test/functional/test_logger.rb +20 -0
  64. data/test/functional/test_modifiers.rb +252 -0
  65. data/test/functional/test_pagination.rb +93 -0
  66. data/test/functional/test_protected.rb +155 -0
  67. data/test/functional/test_string_id_compatibility.rb +67 -0
  68. data/test/functional/test_validations.rb +329 -0
  69. data/test/models.rb +232 -0
  70. data/test/support/custom_matchers.rb +55 -0
  71. data/test/support/timing.rb +16 -0
  72. data/test/test_helper.rb +60 -0
  73. data/test/unit/associations/test_base.rb +207 -0
  74. data/test/unit/associations/test_proxy.rb +105 -0
  75. data/test/unit/serializers/test_json_serializer.rb +189 -0
  76. data/test/unit/test_descendant_appends.rb +71 -0
  77. data/test/unit/test_document.rb +231 -0
  78. data/test/unit/test_dynamic_finder.rb +123 -0
  79. data/test/unit/test_embedded_document.rb +663 -0
  80. data/test/unit/test_finder_options.rb +329 -0
  81. data/test/unit/test_keys.rb +169 -0
  82. data/test/unit/test_mongo_mapper.rb +65 -0
  83. data/test/unit/test_pagination.rb +127 -0
  84. data/test/unit/test_plugins.rb +50 -0
  85. data/test/unit/test_rails.rb +123 -0
  86. data/test/unit/test_rails_compatibility.rb +52 -0
  87. data/test/unit/test_serialization.rb +51 -0
  88. data/test/unit/test_support.rb +354 -0
  89. data/test/unit/test_time_zones.rb +39 -0
  90. data/test/unit/test_validations.rb +544 -0
  91. metadata +290 -0
@@ -0,0 +1,55 @@
1
+ module CustomMatchers
2
+ custom_matcher :be_nil do |receiver, matcher, args|
3
+ matcher.positive_failure_message = "Expected #{receiver} to be nil but it wasn't"
4
+ matcher.negative_failure_message = "Expected #{receiver} not to be nil but it was"
5
+ receiver.nil?
6
+ end
7
+
8
+ custom_matcher :be_blank do |receiver, matcher, args|
9
+ matcher.positive_failure_message = "Expected #{receiver} to be blank but it wasn't"
10
+ matcher.negative_failure_message = "Expected #{receiver} not to be blank but it was"
11
+ receiver.blank?
12
+ end
13
+
14
+ custom_matcher :be_true do |receiver, matcher, args|
15
+ matcher.positive_failure_message = "Expected #{receiver} to be true but it wasn't"
16
+ matcher.negative_failure_message = "Expected #{receiver} not to be true but it was"
17
+ receiver.eql?(true)
18
+ end
19
+
20
+ custom_matcher :be_false do |receiver, matcher, args|
21
+ matcher.positive_failure_message = "Expected #{receiver} to be false but it wasn't"
22
+ matcher.negative_failure_message = "Expected #{receiver} not to be false but it was"
23
+ receiver.eql?(false)
24
+ end
25
+
26
+ custom_matcher :be_valid do |receiver, matcher, args|
27
+ matcher.positive_failure_message = "Expected to be valid but it was invalid #{receiver.errors.inspect}"
28
+ matcher.negative_failure_message = "Expected to be invalid but it was valid #{receiver.errors.inspect}"
29
+ receiver.valid?
30
+ end
31
+
32
+ custom_matcher :have_error_on do |receiver, matcher, args|
33
+ receiver.valid?
34
+ attribute = args[0]
35
+ expected_message = args[1]
36
+
37
+ if expected_message.nil?
38
+ matcher.positive_failure_message = "#{receiver} had no errors on #{attribute}"
39
+ matcher.negative_failure_message = "#{receiver} had errors on #{attribute} #{receiver.errors.inspect}"
40
+ !receiver.errors.on(attribute).blank?
41
+ else
42
+ actual = receiver.errors.on(attribute)
43
+ matcher.positive_failure_message = %Q(Expected error on #{attribute} to be "#{expected_message}" but was "#{actual}")
44
+ matcher.negative_failure_message = %Q(Expected error on #{attribute} not to be "#{expected_message}" but was "#{actual}")
45
+ actual == expected_message
46
+ end
47
+ end
48
+
49
+ custom_matcher :have_index do |receiver, matcher, args|
50
+ index_name = args[0]
51
+ matcher.positive_failure_message = "#{receiver} does not have index named #{index_name}, but should"
52
+ matcher.negative_failure_message = "#{receiver} does have index named #{index_name}, but should not"
53
+ !receiver.collection.index_information.detect { |index| index[0] == index_name }.nil?
54
+ end
55
+ end
@@ -0,0 +1,16 @@
1
+ class Test::Unit::TestCase
2
+ def run_with_test_timing(*args, &block)
3
+ begin_time = Time.now
4
+ run_without_test_timing(*args, &block)
5
+ end_time = Time.now
6
+
7
+ duration = end_time - begin_time
8
+ threshold = 1.0
9
+
10
+ if duration > threshold
11
+ puts "\nSLOW TEST: #{duration} - #{self.name}"
12
+ end
13
+ end
14
+
15
+ alias_method_chain :run, :test_timing unless method_defined?(:run_without_test_timing)
16
+ end
@@ -0,0 +1,60 @@
1
+ if ENV["RAILS3"]
2
+ gem "activemodel", ">= 3.0.0.beta"
3
+ require 'active_model'
4
+ end
5
+
6
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/mongo_mapper')
7
+
8
+ gem 'jnunemaker-matchy', '0.4.0'
9
+ gem 'shoulda', '2.10.2'
10
+ gem 'timecop', '0.3.1'
11
+ gem 'mocha', '0.9.8'
12
+
13
+ require 'matchy'
14
+ require 'shoulda'
15
+ require 'timecop'
16
+ require 'mocha'
17
+ require 'pp'
18
+
19
+ require 'support/custom_matchers'
20
+ require 'support/timing'
21
+
22
+ class Test::Unit::TestCase
23
+ include CustomMatchers
24
+
25
+ def Doc(name=nil, &block)
26
+ klass = Class.new do
27
+ include MongoMapper::Document
28
+ set_collection_name "test#{rand(20)}"
29
+
30
+ if name
31
+ class_eval "def self.name; '#{name}' end"
32
+ class_eval "def self.to_s; '#{name}' end"
33
+ end
34
+ end
35
+
36
+ klass.class_eval(&block) if block_given?
37
+ klass.collection.remove
38
+ klass
39
+ end
40
+
41
+ def EDoc(name=nil, &block)
42
+ klass = Class.new do
43
+ include MongoMapper::EmbeddedDocument
44
+
45
+ if name
46
+ class_eval "def self.name; '#{name}' end"
47
+ class_eval "def self.to_s; '#{name}' end"
48
+ end
49
+ end
50
+
51
+ klass.class_eval(&block) if block_given?
52
+ klass
53
+ end
54
+ end
55
+
56
+ test_dir = File.expand_path(File.dirname(__FILE__) + '/../tmp')
57
+ FileUtils.mkdir_p(test_dir) unless File.exist?(test_dir)
58
+
59
+ MongoMapper.connection = Mongo::Connection.new('127.0.0.1', 27017, {:logger => Logger.new(test_dir + '/test.log')})
60
+ MongoMapper.database = 'test'
@@ -0,0 +1,207 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class FooMonster; end
5
+
6
+ class AssociationBaseTest < Test::Unit::TestCase
7
+ include MongoMapper::Plugins::Associations
8
+
9
+ should "initialize with type and name" do
10
+ base = Base.new(:many, :foos)
11
+ base.type.should == :many
12
+ base.name.should == :foos
13
+ end
14
+
15
+ should "also allow options when initializing" do
16
+ base = Base.new(:many, :foos, :polymorphic => true)
17
+ base.options[:polymorphic].should be_true
18
+ end
19
+
20
+ context "class_name" do
21
+ should "work for belongs_to" do
22
+ Base.new(:belongs_to, :user).class_name.should == 'User'
23
+ end
24
+
25
+ should "work for many" do
26
+ Base.new(:many, :smart_people).class_name.should == 'SmartPerson'
27
+ end
28
+
29
+ should "be changeable using class_name option" do
30
+ base = Base.new(:many, :smart_people, :class_name => 'IntelligentPerson')
31
+ base.class_name.should == 'IntelligentPerson'
32
+ end
33
+ end
34
+
35
+ context "klass" do
36
+ should "default to class_name constantized" do
37
+ Base.new(:belongs_to, :foo_monster).klass.should == FooMonster
38
+ end
39
+
40
+ should "be the specified class" do
41
+ anonnymous_class = Class.new
42
+ Base.new(:belongs_to, :foo_monster, :class => anonnymous_class).klass.should == anonnymous_class
43
+ end
44
+ end
45
+
46
+ context "many?" do
47
+ should "be true if many" do
48
+ Base.new(:many, :foos).many?.should be_true
49
+ end
50
+
51
+ should "be false if not many" do
52
+ Base.new(:belongs_to, :foo).many?.should be_false
53
+ Base.new(:one, :foo).many?.should be_false
54
+ end
55
+ end
56
+
57
+ context "one?" do
58
+ should "be true if one" do
59
+ Base.new(:one, :foo).one?.should be_true
60
+ end
61
+
62
+ should "be false if not one" do
63
+ Base.new(:many, :foo).one?.should be_false
64
+ end
65
+ end
66
+
67
+ context "belongs_to?" do
68
+ should "be true if belongs_to" do
69
+ Base.new(:belongs_to, :foo).belongs_to?.should be_true
70
+ end
71
+
72
+ should "be false if not belongs_to" do
73
+ Base.new(:many, :foos).belongs_to?.should be_false
74
+ end
75
+ end
76
+
77
+ context "polymorphic?" do
78
+ should "be true if polymorphic" do
79
+ Base.new(:many, :foos, :polymorphic => true).polymorphic?.should be_true
80
+ end
81
+
82
+ should "be false if not polymorphic" do
83
+ Base.new(:many, :bars).polymorphic?.should be_false
84
+ end
85
+ end
86
+
87
+ context "as?" do
88
+ should "be true if one" do
89
+ Base.new(:one, :foo, :as => :commentable).as?.should be_true
90
+ end
91
+
92
+ should "be false if not one" do
93
+ Base.new(:many, :foo).as?.should be_false
94
+ end
95
+ end
96
+
97
+ context "in_array?" do
98
+ should "be true if one" do
99
+ Base.new(:one, :foo, :in => :list_ids).in_array?.should be_true
100
+ end
101
+
102
+ should "be false if not one" do
103
+ Base.new(:many, :foo).in_array?.should be_false
104
+ end
105
+ end
106
+
107
+ context "finder_options" do
108
+ should "default to empty hash" do
109
+ base = Base.new(:many, :foos)
110
+ base.finder_options.should == {}
111
+ end
112
+
113
+ should "work with order" do
114
+ base = Base.new(:many, :foos, :order => 'position')
115
+ base.finder_options.should == {:order => 'position'}
116
+ end
117
+
118
+ should "correctly parse from options" do
119
+ base = Base.new(:many, :foos, :order => 'position', :somekey => 'somevalue')
120
+ base.finder_options.should == {:order => 'position', :somekey => 'somevalue'}
121
+ end
122
+ end
123
+
124
+ context "type_key_name" do
125
+ should "be _type for many" do
126
+ Base.new(:many, :foos).type_key_name.should == '_type'
127
+ end
128
+
129
+ should "be association name _ type for belongs_to" do
130
+ Base.new(:belongs_to, :foo).type_key_name.should == 'foo_type'
131
+ end
132
+ end
133
+
134
+ context "foreign_key" do
135
+ should "default to assocation name _id for belongs to" do
136
+ base = Base.new(:belongs_to, :foo)
137
+ base.foreign_key.should == 'foo_id'
138
+ end
139
+
140
+ should "be overridable with :foreign_key option" do
141
+ base = Base.new(:belongs_to, :foo, :foreign_key => 'foobar_id')
142
+ base.foreign_key.should == 'foobar_id'
143
+ end
144
+ end
145
+
146
+ should "have ivar that is association name" do
147
+ Base.new(:belongs_to, :foo).ivar.should == '@_foo'
148
+ end
149
+
150
+ context "embeddable?" do
151
+ should "be true if class is embeddable" do
152
+ base = Base.new(:many, :medias)
153
+ base.embeddable?.should be_true
154
+ end
155
+
156
+ should "be false if class is not embeddable" do
157
+ base = Base.new(:many, :statuses)
158
+ base.embeddable?.should be_false
159
+
160
+ base = Base.new(:belongs_to, :project)
161
+ base.embeddable?.should be_false
162
+ end
163
+ end
164
+
165
+ context "proxy_class" do
166
+ should "be ManyDocumentsProxy for many" do
167
+ base = Base.new(:many, :statuses)
168
+ base.proxy_class.should == ManyDocumentsProxy
169
+ end
170
+
171
+ should "be ManyPolymorphicProxy for polymorphic many" do
172
+ base = Base.new(:many, :messages, :polymorphic => true)
173
+ base.proxy_class.should == ManyPolymorphicProxy
174
+ end
175
+
176
+ should "be ManyEmbeddedProxy for many embedded" do
177
+ base = Base.new(:many, :medias)
178
+ base.proxy_class.should == ManyEmbeddedProxy
179
+ end
180
+
181
+ should "be ManyEmbeddedPolymorphicProxy for polymorphic many embedded" do
182
+ base = Base.new(:many, :medias, :polymorphic => true)
183
+ base.proxy_class.should == ManyEmbeddedPolymorphicProxy
184
+ end
185
+
186
+ should "be BelongsToProxy for belongs_to" do
187
+ base = Base.new(:belongs_to, :project)
188
+ base.proxy_class.should == BelongsToProxy
189
+ end
190
+
191
+ should "be BelongsToPolymorphicProxy for polymorphic belongs_to" do
192
+ base = Base.new(:belongs_to, :target, :polymorphic => true)
193
+ base.proxy_class.should == BelongsToPolymorphicProxy
194
+ end
195
+
196
+ should "be OneProxy for one" do
197
+ base = Base.new(:one, :target, :polymorphic => true)
198
+ base.proxy_class.should == OneProxy
199
+ end
200
+
201
+ should "be InArrayProxy for many with :in option" do
202
+ base = Base.new(:many, :messages, :in => :message_ids)
203
+ base.proxy_class.should == InArrayProxy
204
+ end
205
+ end
206
+
207
+ end
@@ -0,0 +1,105 @@
1
+ require 'test_helper'
2
+
3
+ class FakeNilProxy < MongoMapper::Plugins::Associations::Proxy
4
+ def find_target; nil end
5
+ end
6
+
7
+ class FakeBlankProxy < MongoMapper::Plugins::Associations::Proxy
8
+ def find_target; '' end
9
+ end
10
+
11
+ class FakeNumberProxy < MongoMapper::Plugins::Associations::Proxy
12
+ def find_target; 17 end
13
+ end
14
+
15
+ class FakeProxy < MongoMapper::Plugins::Associations::Proxy
16
+ def find_target; [1, 2] end
17
+ end
18
+
19
+ class ProxyTest < Test::Unit::TestCase
20
+ def setup
21
+ @owner = mock('owner')
22
+ @owner.stubs(:new?).returns(false)
23
+ @association = mock('association')
24
+ @association.stubs(:options).returns({:extend => []})
25
+
26
+ @proxy = FakeProxy.new(@owner, @association)
27
+ @nil_proxy = FakeNilProxy.new(@owner, @association)
28
+ @blank_proxy = FakeBlankProxy.new(@owner, @association)
29
+ end
30
+
31
+ should 'return true for === target' do
32
+ @proxy = FakeProxy.new(@owner, @association)
33
+ @proxy.should === Array
34
+ end
35
+
36
+ should "set target to nil when reset is called" do
37
+ @proxy.reset
38
+ @proxy.target.should be_nil
39
+ end
40
+
41
+ should "be able to inspect the proxy" do
42
+ @proxy.inspect.should == '[1, 2]'
43
+ end
44
+
45
+ context "nil?" do
46
+ should "be true if nil" do
47
+ @nil_proxy.nil?.should be_true
48
+ end
49
+
50
+ should "be false if not nil" do
51
+ @proxy.nil?.should be_false
52
+ end
53
+ end
54
+
55
+ context "blank?" do
56
+ should "be true if blank" do
57
+ @blank_proxy.blank?.should be_true
58
+ @nil_proxy.blank?.should be_true
59
+ end
60
+
61
+ should "be false if not blank" do
62
+ @proxy.blank?.should be_false
63
+ end
64
+ end
65
+
66
+ context "present?" do
67
+ should "be true if present" do
68
+ @proxy.present?.should be_true
69
+ end
70
+
71
+ should "be false if not present" do
72
+ @blank_proxy.present?.should be_false
73
+ @nil_proxy.present?.should be_false
74
+ end
75
+ end
76
+
77
+ should "delegate respond_to? to target" do
78
+ @proxy.respond_to?(:each).should be_true
79
+ @proxy.respond_to?(:size).should be_true
80
+ @proxy.respond_to?(:gsub).should be_false
81
+ end
82
+
83
+ should "alias proxy owner to owner" do
84
+ @proxy.proxy_owner.should == @owner
85
+ end
86
+
87
+ should "alias proxy target to target" do
88
+ @proxy.proxy_target.should == @target
89
+ end
90
+
91
+ context "send" do
92
+ should "work if proxy responds to method" do
93
+ @proxy.send(:reset)
94
+ @proxy.target.should be_nil
95
+ end
96
+
97
+ should "work if the target responds to the method" do
98
+ @proxy.send(:size).should == 2
99
+ end
100
+
101
+ should "not work if neither the proxy or target respond to method" do
102
+ lambda { @proxy.send(:gsub) }.should raise_error
103
+ end
104
+ end
105
+ end
@@ -0,0 +1,189 @@
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
+
17
+ many :tags, :class_name => 'JsonSerializationTest::Tag'
18
+ end
19
+
20
+ def setup
21
+ Contact.include_root_in_json = false
22
+ @contact = Contact.new(
23
+ :name => 'Konata Izumi',
24
+ :age => 16,
25
+ :created_at => Time.utc(2006, 8, 1),
26
+ :awesome => true,
27
+ :preferences => { :shows => 'anime' }
28
+ )
29
+ end
30
+
31
+ should "include demodulized root" do
32
+ Contact.include_root_in_json = true
33
+ assert_match %r{^\{"contact": \{}, @contact.to_json
34
+ end
35
+
36
+ should "encode all encodable attributes" do
37
+ json = @contact.to_json
38
+
39
+ assert_no_match %r{"_id"}, json
40
+ assert_match %r{"name":"Konata Izumi"}, json
41
+ assert_match %r{"age":16}, json
42
+ assert json.include?(%("created_at":#{ActiveSupport::JSON.encode(Time.utc(2006, 8, 1))}))
43
+ assert_match %r{"awesome":true}, json
44
+ assert_match %r{"preferences":\{"shows":"anime"\}}, json
45
+ end
46
+
47
+ should "allow attribute filtering with only" do
48
+ json = @contact.to_json(:only => [:name, :age])
49
+
50
+ assert_no_match %r{"_id"}, json
51
+ assert_match %r{"name":"Konata Izumi"}, json
52
+ assert_match %r{"age":16}, json
53
+ assert_no_match %r{"awesome"}, json
54
+ assert_no_match %r{"created_at"}, json
55
+ assert_no_match %r{"preferences"}, json
56
+ end
57
+
58
+ should "allow attribute filtering with except" do
59
+ json = @contact.to_json(:except => [:name, :age])
60
+
61
+ assert_no_match %r{"_id"}, json
62
+ assert_no_match %r{"name"}, json
63
+ assert_no_match %r{"age"}, json
64
+ assert_match %r{"awesome"}, json
65
+ assert_match %r{"created_at"}, json
66
+ assert_match %r{"preferences"}, json
67
+ end
68
+
69
+ context "_id key" do
70
+ should "not be included by default" do
71
+ json = @contact.to_json
72
+ assert_no_match %r{"_id":}, json
73
+ end
74
+
75
+ should "not be included even if :except is used" do
76
+ json = @contact.to_json(:except => :name)
77
+ assert_no_match %r{"_id":}, json
78
+ end
79
+ end
80
+
81
+ context "id method" do
82
+ setup do
83
+ def @contact.label; "Has cheezburger"; end
84
+ def @contact.favorite_quote; "Constraints are liberating"; end
85
+ end
86
+
87
+ should "be included by default" do
88
+ json = @contact.to_json
89
+ assert_match %r{"id"}, json
90
+ end
91
+
92
+ should "be included when single method included" do
93
+ json = @contact.to_json(:methods => :label)
94
+ assert_match %r{"id"}, json
95
+ assert_match %r{"label":"Has cheezburger"}, json
96
+ assert_match %r{"name":"Konata Izumi"}, json
97
+ assert_no_match %r{"favorite_quote":"Constraints are liberating"}, json
98
+ end
99
+
100
+ should "be included when multiple methods included" do
101
+ json = @contact.to_json(:methods => [:label, :favorite_quote])
102
+ assert_match %r{"id"}, json
103
+ assert_match %r{"label":"Has cheezburger"}, json
104
+ assert_match %r{"favorite_quote":"Constraints are liberating"}, json
105
+ assert_match %r{"name":"Konata Izumi"}, json
106
+ end
107
+
108
+ should "not be included if :only is present" do
109
+ json = @contact.to_json(:only => :name)
110
+ assert_no_match %r{"id":}, json
111
+ end
112
+ end
113
+
114
+ context "including methods" do
115
+ setup do
116
+ def @contact.label; "Has cheezburger"; end
117
+ def @contact.favorite_quote; "Constraints are liberating"; end
118
+ end
119
+
120
+ should "include single method" do
121
+ json = @contact.to_json(:methods => :label)
122
+ assert_match %r{"label":"Has cheezburger"}, json
123
+ end
124
+
125
+ should "include multiple methods" do
126
+ json = @contact.to_json(:only => :name, :methods => [:label, :favorite_quote])
127
+ assert_match %r{"label":"Has cheezburger"}, json
128
+ assert_match %r{"favorite_quote":"Constraints are liberating"}, json
129
+ assert_match %r{"name":"Konata Izumi"}, json
130
+ assert_no_match %r{"age":16}, json
131
+ assert_no_match %r{"awesome"}, json
132
+ assert_no_match %r{"created_at"}, json
133
+ assert_no_match %r{"preferences"}, json
134
+ end
135
+ end
136
+
137
+ context "array of records" do
138
+ setup do
139
+ @contacts = [
140
+ Contact.new(:name => 'David', :age => 39),
141
+ Contact.new(:name => 'Mary', :age => 14)
142
+ ]
143
+ end
144
+
145
+ should "allow attribute filtering with only" do
146
+ json = @contacts.to_json(:only => :name)
147
+ assert_match %r{\{"name":"David"\}}, json
148
+ assert_match %r{\{"name":"Mary"\}}, json
149
+ end
150
+
151
+ should "allow attribute filtering with except" do
152
+ json = @contacts.to_json(:except => [:name, :preferences, :awesome, :created_at, :updated_at])
153
+ assert_match %r{"age":39}, json
154
+ assert_match %r{"age":14}, json
155
+ assert_no_match %r{"name":}, json
156
+ assert_no_match %r{"preferences":}, json
157
+ assert_no_match %r{"awesome":}, json
158
+ assert_no_match %r{"created_at":}, json
159
+ assert_no_match %r{"updated_at":}, json
160
+ end
161
+ end
162
+
163
+ should "allow options for hash of records" do
164
+ contacts = {
165
+ 1 => Contact.new(:name => 'David', :age => 39),
166
+ 2 => Contact.new(:name => 'Mary', :age => 14)
167
+ }
168
+ json = contacts.to_json(:only => [1, :name])
169
+ assert_match %r{"1":}, json
170
+ assert_match %r{\{"name":"David"\}}, json
171
+ assert_no_match %r{"2":}, json
172
+ end
173
+
174
+ should "include embedded attributes" do
175
+ contact = Contact.new(:name => 'John', :age => 27)
176
+ contact.tags = [Tag.new(:name => 'awesome'), Tag.new(:name => 'ruby')]
177
+ json = contact.to_json
178
+ assert_match %r{"tags":}, json
179
+ assert_match %r{"name":"awesome"}, json
180
+ assert_match %r{"name":"ruby"}, json
181
+ end
182
+
183
+ should "include dynamic attributes" do
184
+ contact = Contact.new(:name => 'John', :age => 27, :foo => 'bar')
185
+ contact['smell'] = 'stinky'
186
+ json = contact.to_json
187
+ assert_match %r{"smell":"stinky"}, json
188
+ end
189
+ end