numon 0.0.1

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 (99) hide show
  1. data/.gitignore +10 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +31 -0
  4. data/Rakefile +52 -0
  5. data/bin/mmconsole +60 -0
  6. data/lib/mongo_mapper.rb +138 -0
  7. data/lib/mongo_mapper/document.rb +359 -0
  8. data/lib/mongo_mapper/embedded_document.rb +61 -0
  9. data/lib/mongo_mapper/plugins.rb +34 -0
  10. data/lib/mongo_mapper/plugins/associations.rb +105 -0
  11. data/lib/mongo_mapper/plugins/associations/base.rb +123 -0
  12. data/lib/mongo_mapper/plugins/associations/belongs_to_polymorphic_proxy.rb +30 -0
  13. data/lib/mongo_mapper/plugins/associations/belongs_to_proxy.rb +25 -0
  14. data/lib/mongo_mapper/plugins/associations/collection.rb +21 -0
  15. data/lib/mongo_mapper/plugins/associations/embedded_collection.rb +39 -0
  16. data/lib/mongo_mapper/plugins/associations/in_array_proxy.rb +144 -0
  17. data/lib/mongo_mapper/plugins/associations/many_documents_as_proxy.rb +28 -0
  18. data/lib/mongo_mapper/plugins/associations/many_documents_proxy.rb +120 -0
  19. data/lib/mongo_mapper/plugins/associations/many_embedded_polymorphic_proxy.rb +31 -0
  20. data/lib/mongo_mapper/plugins/associations/many_embedded_proxy.rb +23 -0
  21. data/lib/mongo_mapper/plugins/associations/many_polymorphic_proxy.rb +13 -0
  22. data/lib/mongo_mapper/plugins/associations/one_proxy.rb +68 -0
  23. data/lib/mongo_mapper/plugins/associations/proxy.rb +118 -0
  24. data/lib/mongo_mapper/plugins/callbacks.rb +234 -0
  25. data/lib/mongo_mapper/plugins/clone.rb +13 -0
  26. data/lib/mongo_mapper/plugins/descendants.rb +16 -0
  27. data/lib/mongo_mapper/plugins/dirty.rb +119 -0
  28. data/lib/mongo_mapper/plugins/equality.rb +23 -0
  29. data/lib/mongo_mapper/plugins/identity_map.rb +122 -0
  30. data/lib/mongo_mapper/plugins/inspect.rb +14 -0
  31. data/lib/mongo_mapper/plugins/keys.rb +336 -0
  32. data/lib/mongo_mapper/plugins/logger.rb +17 -0
  33. data/lib/mongo_mapper/plugins/modifiers.rb +87 -0
  34. data/lib/mongo_mapper/plugins/pagination.rb +24 -0
  35. data/lib/mongo_mapper/plugins/pagination/proxy.rb +72 -0
  36. data/lib/mongo_mapper/plugins/protected.rb +45 -0
  37. data/lib/mongo_mapper/plugins/rails.rb +53 -0
  38. data/lib/mongo_mapper/plugins/serialization.rb +75 -0
  39. data/lib/mongo_mapper/plugins/timestamps.rb +21 -0
  40. data/lib/mongo_mapper/plugins/userstamps.rb +14 -0
  41. data/lib/mongo_mapper/plugins/validations.rb +46 -0
  42. data/lib/mongo_mapper/query.rb +130 -0
  43. data/lib/mongo_mapper/support.rb +216 -0
  44. data/lib/mongo_mapper/support/descendant_appends.rb +46 -0
  45. data/lib/mongo_mapper/support/find.rb +77 -0
  46. data/lib/mongo_mapper/version.rb +3 -0
  47. data/numon.gemspec +207 -0
  48. data/performance/read_write.rb +52 -0
  49. data/specs.watchr +51 -0
  50. data/test/NOTE_ON_TESTING +1 -0
  51. data/test/active_model_lint_test.rb +11 -0
  52. data/test/functional/associations/test_belongs_to_polymorphic_proxy.rb +63 -0
  53. data/test/functional/associations/test_belongs_to_proxy.rb +101 -0
  54. data/test/functional/associations/test_in_array_proxy.rb +325 -0
  55. data/test/functional/associations/test_many_documents_as_proxy.rb +229 -0
  56. data/test/functional/associations/test_many_documents_proxy.rb +453 -0
  57. data/test/functional/associations/test_many_embedded_polymorphic_proxy.rb +176 -0
  58. data/test/functional/associations/test_many_embedded_proxy.rb +256 -0
  59. data/test/functional/associations/test_many_polymorphic_proxy.rb +302 -0
  60. data/test/functional/associations/test_one_proxy.rb +161 -0
  61. data/test/functional/test_associations.rb +44 -0
  62. data/test/functional/test_binary.rb +27 -0
  63. data/test/functional/test_callbacks.rb +151 -0
  64. data/test/functional/test_dirty.rb +163 -0
  65. data/test/functional/test_document.rb +1165 -0
  66. data/test/functional/test_embedded_document.rb +130 -0
  67. data/test/functional/test_identity_map.rb +508 -0
  68. data/test/functional/test_indexing.rb +44 -0
  69. data/test/functional/test_logger.rb +20 -0
  70. data/test/functional/test_modifiers.rb +322 -0
  71. data/test/functional/test_pagination.rb +93 -0
  72. data/test/functional/test_protected.rb +161 -0
  73. data/test/functional/test_string_id_compatibility.rb +67 -0
  74. data/test/functional/test_timestamps.rb +64 -0
  75. data/test/functional/test_userstamps.rb +28 -0
  76. data/test/functional/test_validations.rb +329 -0
  77. data/test/models.rb +232 -0
  78. data/test/support/custom_matchers.rb +55 -0
  79. data/test/support/timing.rb +16 -0
  80. data/test/test_helper.rb +61 -0
  81. data/test/unit/associations/test_base.rb +207 -0
  82. data/test/unit/associations/test_proxy.rb +105 -0
  83. data/test/unit/serializers/test_json_serializer.rb +202 -0
  84. data/test/unit/test_descendant_appends.rb +71 -0
  85. data/test/unit/test_document.rb +231 -0
  86. data/test/unit/test_dynamic_finder.rb +123 -0
  87. data/test/unit/test_embedded_document.rb +663 -0
  88. data/test/unit/test_keys.rb +173 -0
  89. data/test/unit/test_mongo_mapper.rb +155 -0
  90. data/test/unit/test_pagination.rb +160 -0
  91. data/test/unit/test_plugins.rb +50 -0
  92. data/test/unit/test_query.rb +340 -0
  93. data/test/unit/test_rails.rb +123 -0
  94. data/test/unit/test_rails_compatibility.rb +52 -0
  95. data/test/unit/test_serialization.rb +51 -0
  96. data/test/unit/test_support.rb +366 -0
  97. data/test/unit/test_time_zones.rb +39 -0
  98. data/test/unit/test_validations.rb +544 -0
  99. metadata +305 -0
@@ -0,0 +1,50 @@
1
+ require 'test_helper'
2
+
3
+ module MyPlugin
4
+ def self.configure(model)
5
+ model.class_eval { attr_accessor :from_configure }
6
+ end
7
+
8
+ module ClassMethods
9
+ def class_foo
10
+ 'class_foo'
11
+ end
12
+ end
13
+
14
+ module InstanceMethods
15
+ def instance_foo
16
+ 'instance_foo'
17
+ end
18
+ end
19
+ end
20
+
21
+ class PluginsTest < Test::Unit::TestCase
22
+ context "plugin" do
23
+ setup do
24
+ @document = Class.new do
25
+ extend MongoMapper::Plugins
26
+ plugin MyPlugin
27
+ end
28
+ end
29
+
30
+ should "include instance methods" do
31
+ @document.new.instance_foo.should == 'instance_foo'
32
+ end
33
+
34
+ should "extend class methods" do
35
+ @document.class_foo.should == 'class_foo'
36
+ end
37
+
38
+ should "pass model to configure" do
39
+ @document.new.should respond_to(:from_configure)
40
+ end
41
+
42
+ should "default plugins to empty array" do
43
+ Class.new { extend MongoMapper::Plugins }.plugins.should == []
44
+ end
45
+
46
+ should "add plugin to plugins" do
47
+ @document.plugins.should include(MyPlugin)
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,340 @@
1
+ require 'test_helper'
2
+ require 'models'
3
+
4
+ class QueryTest < Test::Unit::TestCase
5
+ include MongoMapper
6
+
7
+ should "raise error if provided something other than a hash" do
8
+ lambda { Query.new(Room) }.should raise_error(ArgumentError)
9
+ lambda { Query.new(Room, 1) }.should raise_error(ArgumentError)
10
+ end
11
+
12
+ should "symbolize the keys of the hash provided" do
13
+ Query.new(Room, 'offset' => 1).options.keys.map do |key|
14
+ key.should be_instance_of(Symbol)
15
+ end
16
+ end
17
+
18
+ context "Converting conditions to criteria" do
19
+ should "not add _type to query if model does not have superclass that is single collection inherited" do
20
+ Query.new(Message, :foo => 'bar').criteria.should == {
21
+ :foo => 'bar'
22
+ }
23
+ end
24
+
25
+ should "not add _type to nested conditions" do
26
+ Query.new(Enter, :foo => 'bar', :age => {'$gt' => 21}).criteria.should == {
27
+ :foo => 'bar',
28
+ :age => {'$gt' => 21},
29
+ :_type => 'Enter'
30
+ }
31
+ end
32
+
33
+ should "automatically add _type to query if model is single collection inherited" do
34
+ Query.new(Enter, :foo => 'bar').criteria.should == {
35
+ :foo => 'bar',
36
+ :_type => 'Enter'
37
+ }
38
+ end
39
+
40
+ %w{gt lt gte lte ne in nin mod all size where exists}.each do |operator|
41
+ next if operator == 'size' && RUBY_VERSION >= '1.9.1' # 1.9 defines Symbol#size
42
+
43
+ should "convert #{operator} conditions" do
44
+ Query.new(Room, :age.send(operator) => 21).criteria.should == {
45
+ :age => {"$#{operator}" => 21}
46
+ }
47
+ end
48
+ end
49
+
50
+ should "normalize value when using symbol operators" do
51
+ time = Time.now.in_time_zone('Indiana (East)')
52
+ criteria = Query.new(Room, :created_at.gt => time).criteria
53
+ criteria[:created_at]['$gt'].should be_utc
54
+ end
55
+
56
+ should "work with simple criteria" do
57
+ Query.new(Room, :foo => 'bar').criteria.should == {
58
+ :foo => 'bar'
59
+ }
60
+
61
+ Query.new(Room, :foo => 'bar', :baz => 'wick').criteria.should == {
62
+ :foo => 'bar',
63
+ :baz => 'wick'
64
+ }
65
+ end
66
+
67
+ should "convert id to _id" do
68
+ id = Mongo::ObjectID.new
69
+ Query.new(Room, :id => id).criteria.should == {:_id => id}
70
+ end
71
+
72
+ should "convert id with symbol operator to _id with modifier" do
73
+ id = Mongo::ObjectID.new
74
+ Query.new(Room, :id.ne => id).criteria.should == {
75
+ :_id => {'$ne' => id}
76
+ }
77
+ end
78
+
79
+ should "make sure that _id's are object ids" do
80
+ id = Mongo::ObjectID.new
81
+ Query.new(Room, :_id => id.to_s).criteria.should == {:_id => id}
82
+ end
83
+
84
+ should "work fine with _id's that are object ids" do
85
+ id = Mongo::ObjectID.new
86
+ Query.new(Room, :_id => id).criteria.should == {:_id => id}
87
+ end
88
+
89
+ should "make sure other object id typed keys get converted" do
90
+ id = Mongo::ObjectID.new
91
+ Query.new(Message, :room_id => id.to_s).criteria.should == {:room_id => id}
92
+ end
93
+
94
+ should "work fine with object ids for object id typed keys" do
95
+ id = Mongo::ObjectID.new
96
+ Query.new(Message, :room_id => id).criteria.should == {:room_id => id}
97
+ end
98
+
99
+ should "convert times to utc if they aren't already" do
100
+ time = Time.now.in_time_zone('Indiana (East)')
101
+ criteria = Query.new(Room, :created_at => time).criteria
102
+ criteria[:created_at].utc?.should be_true
103
+ end
104
+
105
+ should "not funk with times already in utc" do
106
+ time = Time.now.utc
107
+ criteria = Query.new(Room, :created_at => time).criteria
108
+ criteria[:created_at].utc?.should be_true
109
+ criteria[:created_at].should == time
110
+ end
111
+
112
+ should "use $in for arrays" do
113
+ Query.new(Room, :foo => [1,2,3]).criteria.should == {
114
+ :foo => {'$in' => [1,2,3]}
115
+ }
116
+ end
117
+
118
+ should "not use $in for arrays if already using array operator" do
119
+ Query.new(Room, :foo => {'$all' => [1,2,3]}).criteria.should == {
120
+ :foo => {'$all' => [1,2,3]}
121
+ }
122
+
123
+ Query.new(Room, :foo => {'$any' => [1,2,3]}).criteria.should == {
124
+ :foo => {'$any' => [1,2,3]}
125
+ }
126
+ end
127
+
128
+ should "work arbitrarily deep" do
129
+ Query.new(Room, :foo => {:bar => [1,2,3]}).criteria.should == {
130
+ :foo => {:bar => {'$in' => [1,2,3]}}
131
+ }
132
+
133
+ Query.new(Room, :foo => {:bar => {'$any' => [1,2,3]}}).criteria.should == {
134
+ :foo => {:bar => {'$any' => [1,2,3]}}
135
+ }
136
+ end
137
+ end
138
+
139
+ context "ordering" do
140
+ should "single field with ascending direction" do
141
+ sort = [['foo', 1]]
142
+ Query.new(Room, :order => 'foo asc').options[:sort].should == sort
143
+ Query.new(Room, :order => 'foo ASC').options[:sort].should == sort
144
+ end
145
+
146
+ should "single field with descending direction" do
147
+ sort = [['foo', -1]]
148
+ Query.new(Room, :order => 'foo desc').options[:sort].should == sort
149
+ Query.new(Room, :order => 'foo DESC').options[:sort].should == sort
150
+ end
151
+
152
+ should "convert order operators to mongo sort" do
153
+ Query.new(Room, :order => :foo.asc).options[:sort].should == [['foo', 1]]
154
+ Query.new(Room, :order => :foo.desc).options[:sort].should == [['foo', -1]]
155
+ end
156
+
157
+ should "convert array of order operators to mongo sort" do
158
+ Query.new(Room, :order => [:foo.asc, :bar.desc]).options[:sort].should == [['foo', 1], ['bar', -1]]
159
+ end
160
+
161
+ should "convert field without direction to ascending" do
162
+ sort = [['foo', 1]]
163
+ Query.new(Room, :order => 'foo').options[:sort].should == sort
164
+ end
165
+
166
+ should "convert multiple fields with directions" do
167
+ sort = [['foo', -1], ['bar', 1], ['baz', -1]]
168
+ Query.new(Room, :order => 'foo desc, bar asc, baz desc').options[:sort].should == sort
169
+ end
170
+
171
+ should "convert multiple fields with some missing directions" do
172
+ sort = [['foo', -1], ['bar', 1], ['baz', 1]]
173
+ Query.new(Room, :order => 'foo desc, bar, baz').options[:sort].should == sort
174
+ end
175
+
176
+ should "just use sort if sort and order are present" do
177
+ sort = [['$natural', 1]]
178
+ Query.new(Room, :sort => sort, :order => 'foo asc').options[:sort].should == sort
179
+ end
180
+
181
+ should "normalize id to _id" do
182
+ Query.new(Room, :order => :id.asc).options[:sort].should == [['_id', 1]]
183
+ end
184
+
185
+ should "convert natural in order to proper" do
186
+ sort = [['$natural', 1]]
187
+ Query.new(Room, :order => '$natural asc').options[:sort].should == sort
188
+ sort = [['$natural', -1]]
189
+ Query.new(Room, :order => '$natural desc').options[:sort].should == sort
190
+ end
191
+
192
+ should "work for natural order ascending" do
193
+ Query.new(Room, :sort => {'$natural' => 1}).options[:sort]['$natural'].should == 1
194
+ end
195
+
196
+ should "work for natural order descending" do
197
+ Query.new(Room, :sort => {'$natural' => -1}).options[:sort]['$natural'].should == -1
198
+ end
199
+ end
200
+
201
+ context "skip" do
202
+ should "default to 0" do
203
+ Query.new(Room, {}).options[:skip].should == 0
204
+ end
205
+
206
+ should "use skip provided" do
207
+ Query.new(Room, :skip => 2).options[:skip].should == 2
208
+ end
209
+
210
+ should "covert string to integer" do
211
+ Query.new(Room, :skip => '2').options[:skip].should == 2
212
+ end
213
+
214
+ should "convert offset to skip" do
215
+ Query.new(Room, :offset => 1).options[:skip].should == 1
216
+ end
217
+ end
218
+
219
+ context "limit" do
220
+ should "default to 0" do
221
+ Query.new(Room, {}).options[:limit].should == 0
222
+ end
223
+
224
+ should "use limit provided" do
225
+ Query.new(Room, :limit => 2).options[:limit].should == 2
226
+ end
227
+
228
+ should "covert string to integer" do
229
+ Query.new(Room, :limit => '2').options[:limit].should == 2
230
+ end
231
+ end
232
+
233
+ context "fields" do
234
+ should "default to nil" do
235
+ Query.new(Room, {}).options[:fields].should be(nil)
236
+ end
237
+
238
+ should "be converted to nil if empty string" do
239
+ Query.new(Room, :fields => '').options[:fields].should be(nil)
240
+ end
241
+
242
+ should "be converted to nil if []" do
243
+ Query.new(Room, :fields => []).options[:fields].should be(nil)
244
+ end
245
+
246
+ should "should work with array" do
247
+ Query.new(Room, {:fields => %w(a b)}).options[:fields].should == %w(a b)
248
+ end
249
+
250
+ should "convert comma separated list to array" do
251
+ Query.new(Room, {:fields => 'a, b'}).options[:fields].should == %w(a b)
252
+ end
253
+
254
+ should "also work as select" do
255
+ Query.new(Room, :select => %w(a b)).options[:fields].should == %w(a b)
256
+ end
257
+
258
+ should "also work with select as array of symbols" do
259
+ Query.new(Room, :select => [:a, :b]).options[:fields].should == [:a, :b]
260
+ end
261
+ end
262
+
263
+ context "Condition auto-detection" do
264
+ should "know :conditions are criteria" do
265
+ finder = Query.new(Room, :conditions => {:foo => 'bar'})
266
+ finder.criteria.should == {:foo => 'bar'}
267
+ finder.options.keys.should_not include(:conditions)
268
+ end
269
+
270
+ should "know fields is an option" do
271
+ finder = Query.new(Room, :fields => ['foo'])
272
+ finder.options[:fields].should == ['foo']
273
+ finder.criteria.keys.should_not include(:fields)
274
+ end
275
+
276
+ # select gets converted to fields so just checking keys
277
+ should "know select is an option" do
278
+ finder = Query.new(Room, :select => 'foo')
279
+ finder.options.keys.should include(:sort)
280
+ finder.criteria.keys.should_not include(:select)
281
+ finder.criteria.keys.should_not include(:fields)
282
+ end
283
+
284
+ should "know skip is an option" do
285
+ finder = Query.new(Room, :skip => 10)
286
+ finder.options[:skip].should == 10
287
+ finder.criteria.keys.should_not include(:skip)
288
+ end
289
+
290
+ # offset gets converted to skip so just checking keys
291
+ should "know offset is an option" do
292
+ finder = Query.new(Room, :offset => 10)
293
+ finder.options.keys.should include(:skip)
294
+ finder.criteria.keys.should_not include(:skip)
295
+ finder.criteria.keys.should_not include(:offset)
296
+ end
297
+
298
+ should "know limit is an option" do
299
+ finder = Query.new(Room, :limit => 10)
300
+ finder.options[:limit].should == 10
301
+ finder.criteria.keys.should_not include(:limit)
302
+ end
303
+
304
+ should "know sort is an option" do
305
+ finder = Query.new(Room, :sort => [['foo', 1]])
306
+ finder.options[:sort].should == [['foo', 1]]
307
+ finder.criteria.keys.should_not include(:sort)
308
+ end
309
+
310
+ # order gets converted to sort so just checking keys
311
+ should "know order is an option" do
312
+ finder = Query.new(Room, :order => 'foo')
313
+ finder.options.keys.should include(:sort)
314
+ finder.criteria.keys.should_not include(:sort)
315
+ end
316
+
317
+ should "work with full range of things" do
318
+ query_options = Query.new(Room, {
319
+ :foo => 'bar',
320
+ :baz => true,
321
+ :sort => [['foo', 1]],
322
+ :fields => ['foo', 'baz'],
323
+ :limit => 10,
324
+ :skip => 10,
325
+ })
326
+
327
+ query_options.criteria.should == {
328
+ :foo => 'bar',
329
+ :baz => true,
330
+ }
331
+
332
+ query_options.options.should == {
333
+ :sort => [['foo', 1]],
334
+ :fields => ['foo', 'baz'],
335
+ :limit => 10,
336
+ :skip => 10,
337
+ }
338
+ end
339
+ end
340
+ end
@@ -0,0 +1,123 @@
1
+ require 'test_helper'
2
+
3
+ class TestRails < Test::Unit::TestCase
4
+ context "Document" do
5
+ setup do
6
+ @klass = Doc('Post') do
7
+ key :foo, String
8
+ end
9
+ end
10
+
11
+ context "Class methods" do
12
+ should "alias has_many to many" do
13
+ @klass.should respond_to(:has_many)
14
+ end
15
+
16
+ should "alias has_one to one" do
17
+ @klass.should respond_to(:has_one)
18
+ end
19
+
20
+ should "have column names" do
21
+ @klass.column_names.sort.should == ['_id', 'foo']
22
+ end
23
+
24
+ should "implement human_name" do
25
+ @klass.human_name.should == 'Post'
26
+ end
27
+ end
28
+
29
+ context "Instance methods" do
30
+ setup do
31
+ @klass.class_eval do
32
+ def bar=(value)
33
+ write_attribute(:foo, value)
34
+ end
35
+
36
+ def bar_before_typecast
37
+ read_attribute_before_typecast(:foo)
38
+ end
39
+
40
+ def bar
41
+ read_attribute(:foo)
42
+ end
43
+ end
44
+ end
45
+
46
+ should "alias new_record? to new?" do
47
+ @klass.new.should be_new_record
48
+ end
49
+
50
+ should "be able to read key with read_attribute" do
51
+ @klass.new(:foo => 'Bar').bar.should == 'Bar'
52
+ end
53
+
54
+ should "be able to read key before typecast with read_attribute_before_typecast" do
55
+ @klass.new(:foo => 21).bar_before_typecast.should == 21
56
+ @klass.new(:foo => 21).bar.should == '21'
57
+ end
58
+
59
+ should "be able to write key with write_attribute" do
60
+ @klass.new(:bar => 'Setting Foo').foo.should == 'Setting Foo'
61
+ end
62
+ end
63
+ end
64
+
65
+ context "EmbeddedDocument" do
66
+ setup do
67
+ @klass = EDoc('Post') { key :foo, String }
68
+ end
69
+
70
+ context "Class methods" do
71
+ should "alias has_many to many" do
72
+ @klass.should respond_to(:has_many)
73
+ end
74
+
75
+ should "alias has_one to one" do
76
+ @klass.should respond_to(:has_one)
77
+ end
78
+
79
+ should "have column names" do
80
+ @klass.column_names.sort.should == ['_id', 'foo']
81
+ end
82
+
83
+ should "implement human_name" do
84
+ @klass.human_name.should == 'Post'
85
+ end
86
+ end
87
+
88
+ context "Instance methods" do
89
+ setup do
90
+ @klass.class_eval do
91
+ def bar=(value)
92
+ write_attribute(:foo, value)
93
+ end
94
+
95
+ def bar_before_typecast
96
+ read_attribute_before_typecast(:foo)
97
+ end
98
+
99
+ def bar
100
+ read_attribute(:foo)
101
+ end
102
+ end
103
+ end
104
+
105
+ should "alias new_record? to new?" do
106
+ @klass.new.should be_new_record
107
+ end
108
+
109
+ should "be able to read key with read_attribute" do
110
+ @klass.new(:foo => 'Bar').bar.should == 'Bar'
111
+ end
112
+
113
+ should "be able to read key before typecast with read_attribute_before_typecast" do
114
+ @klass.new(:foo => 21).bar_before_typecast.should == 21
115
+ @klass.new(:foo => 21).bar.should == '21'
116
+ end
117
+
118
+ should "be able to write key with write_attribute" do
119
+ @klass.new(:bar => 'Setting Foo').foo.should == 'Setting Foo'
120
+ end
121
+ end
122
+ end
123
+ end