persistence 0.0.1.alpha → 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 (138) hide show
  1. data/CHANGELOG.md +4 -0
  2. data/README.md +260 -17
  3. data/lib/namespaces.rb +55 -0
  4. data/lib/persistence.rb +38 -3
  5. data/lib/persistence/adapter/abstract.rb +22 -0
  6. data/lib/persistence/adapter/abstract/enable_disable.rb +107 -0
  7. data/lib/persistence/adapter/abstract/primary_key/id_property_string.rb +33 -0
  8. data/lib/persistence/adapter/abstract/primary_key/simple.rb +29 -0
  9. data/lib/persistence/adapter/mock.rb +9 -0
  10. data/lib/persistence/adapter/mock/adapter_interface.rb +102 -0
  11. data/lib/persistence/adapter/mock/bucket.rb +9 -0
  12. data/lib/persistence/adapter/mock/bucket/bucket_interface.rb +260 -0
  13. data/lib/persistence/adapter/mock/bucket/index.rb +9 -0
  14. data/lib/persistence/adapter/mock/bucket/index/index_interface.rb +155 -0
  15. data/lib/persistence/adapter/mock/cursor.rb +9 -0
  16. data/lib/persistence/adapter/mock/cursor/cursor_interface.rb +238 -0
  17. data/lib/persistence/cursor.rb +11 -0
  18. data/lib/persistence/cursor/atomic.rb +110 -0
  19. data/lib/persistence/cursor/cursor_interface.rb +337 -0
  20. data/lib/persistence/exception/block_required.rb +7 -0
  21. data/lib/persistence/exception/conflicting_index_already_declared.rb +7 -0
  22. data/lib/persistence/exception/duplicate_violates_unique_index.rb +7 -0
  23. data/lib/persistence/exception/explicit_index_required.rb +7 -0
  24. data/lib/persistence/exception/indexing_block_failed_to_generate_keys.rb +7 -0
  25. data/lib/persistence/exception/indexing_object_requires_keys.rb +7 -0
  26. data/lib/persistence/exception/key_value_required.rb +7 -0
  27. data/lib/persistence/exception/no_port_enabled.rb +7 -0
  28. data/lib/persistence/object.rb +21 -0
  29. data/lib/persistence/object/autodetermine.rb +74 -0
  30. data/lib/persistence/object/class_instance.rb +1884 -0
  31. data/lib/persistence/object/complex.rb +17 -0
  32. data/lib/persistence/object/complex/array.rb +14 -0
  33. data/lib/persistence/object/complex/array/class_instance.rb +37 -0
  34. data/lib/persistence/object/complex/array/object_instance.rb +54 -0
  35. data/lib/persistence/object/complex/attributes.rb +1808 -0
  36. data/lib/persistence/object/complex/attributes/attributes_array.rb +32 -0
  37. data/lib/persistence/object/complex/attributes/attributes_hash.rb +187 -0
  38. data/lib/persistence/object/complex/attributes/default_atomic_non_atomic.rb +102 -0
  39. data/lib/persistence/object/complex/attributes/hash_to_port.rb +40 -0
  40. data/lib/persistence/object/complex/class_and_object_instance.rb +132 -0
  41. data/lib/persistence/object/complex/class_instance.rb +267 -0
  42. data/lib/persistence/object/complex/complex_object.rb +111 -0
  43. data/lib/persistence/object/complex/hash.rb +14 -0
  44. data/lib/persistence/object/complex/hash/class_instance.rb +40 -0
  45. data/lib/persistence/object/complex/hash/object_instance.rb +63 -0
  46. data/lib/persistence/object/complex/index/attribute_index.rb +10 -0
  47. data/lib/persistence/object/complex/index/attribute_index/attribute_index_interface.rb +43 -0
  48. data/lib/persistence/object/complex/object_instance.rb +469 -0
  49. data/lib/persistence/object/flat.rb +17 -0
  50. data/lib/persistence/object/flat/class_instance.rb +34 -0
  51. data/lib/persistence/object/flat/file.rb +14 -0
  52. data/lib/persistence/object/flat/file/class_instance.rb +122 -0
  53. data/lib/persistence/object/flat/file/contents.rb +7 -0
  54. data/lib/persistence/object/flat/file/file_persistence.rb +147 -0
  55. data/lib/persistence/object/flat/file/object_instance.rb +116 -0
  56. data/lib/persistence/object/flat/file/path.rb +9 -0
  57. data/lib/persistence/object/flat/object_instance.rb +24 -0
  58. data/lib/persistence/object/index.rb +479 -0
  59. data/lib/persistence/object/index/block_index.rb +10 -0
  60. data/lib/persistence/object/index/block_index/block_index_interface.rb +110 -0
  61. data/lib/persistence/object/index/explicit_index.rb +10 -0
  62. data/lib/persistence/object/index/explicit_index/explicit_index_interface.rb +57 -0
  63. data/lib/persistence/object/index_hash.rb +40 -0
  64. data/lib/persistence/object/object_instance.rb +322 -0
  65. data/lib/persistence/object/parse_persistence_args.rb +145 -0
  66. data/lib/persistence/port.rb +9 -0
  67. data/lib/persistence/port/bucket.rb +9 -0
  68. data/lib/persistence/port/bucket/bucket_index.rb +9 -0
  69. data/lib/persistence/port/bucket/bucket_interface.rb +685 -0
  70. data/lib/persistence/port/controller.rb +263 -0
  71. data/lib/persistence/port/port_interface.rb +417 -0
  72. data/lib/requires.rb +146 -0
  73. data/spec/Integration_spec.rb +53 -0
  74. data/spec/Persistence_spec.rb +175 -0
  75. data/spec/example_objects.rb +6 -0
  76. data/spec/example_objects/complex_object.rb +7 -0
  77. data/spec/example_objects/complex_object/array_object.rb +7 -0
  78. data/spec/example_objects/complex_object/hash_object.rb +7 -0
  79. data/spec/example_objects/flat_object.rb +7 -0
  80. data/spec/example_objects/flat_object/file_object.rb +7 -0
  81. data/spec/persistence/adapter/enable_disable_spec.rb +29 -0
  82. data/spec/persistence/adapter/mock/cursor_spec.rb +64 -0
  83. data/spec/persistence/adapter/mock_helpers.rb +27 -0
  84. data/spec/persistence/adapter/mock_helpers/bucket.rb +10 -0
  85. data/spec/persistence/adapter/mock_helpers/integration/dictionary_hash.rb +4 -0
  86. data/spec/persistence/adapter/mock_helpers/integration/note.rb +18 -0
  87. data/spec/persistence/adapter/mock_helpers/integration/notes_array.rb +4 -0
  88. data/spec/persistence/adapter/mock_helpers/integration/user.rb +44 -0
  89. data/spec/persistence/adapter/mock_helpers/integration/user/address.rb +18 -0
  90. data/spec/persistence/adapter/mock_helpers/integration/user/dictionary_entry.rb +12 -0
  91. data/spec/persistence/adapter/mock_helpers/integration/user/sub_account.rb +15 -0
  92. data/spec/persistence/adapter/mock_helpers/object.rb +87 -0
  93. data/spec/persistence/adapter/mock_helpers/port.rb +21 -0
  94. data/spec/persistence/adapter/mock_spec.rb +211 -0
  95. data/spec/persistence/adapter/primary_key/id_property_string_spec.rb +27 -0
  96. data/spec/persistence/adapter/primary_key/simple_spec.rb +19 -0
  97. data/spec/persistence/adapter/spec_abstract/adapter_spec.rb +223 -0
  98. data/spec/persistence/adapter/spec_abstract/cursor_spec.rb +116 -0
  99. data/spec/persistence/cursor/atomic_spec.rb +86 -0
  100. data/spec/persistence/cursor/object_and_class_instance_spec.rb +73 -0
  101. data/spec/persistence/cursor_spec.rb +128 -0
  102. data/spec/persistence/object/complex/attributes/persistence_hash/array_instance_spec.rb +51 -0
  103. data/spec/persistence/object/complex/attributes/persistence_hash/hash_instance_spec.rb +56 -0
  104. data/spec/persistence/object/complex/attributes_spec.rb +1717 -0
  105. data/spec/persistence/object/complex/complex_spec.rb +922 -0
  106. data/spec/persistence/object/complex/index/attribute_index_spec.rb +76 -0
  107. data/spec/persistence/object/flat/bignum_spec.rb +33 -0
  108. data/spec/persistence/object/flat/class_instance_spec.rb +30 -0
  109. data/spec/persistence/object/flat/class_spec.rb +38 -0
  110. data/spec/persistence/object/flat/complex_spec.rb +36 -0
  111. data/spec/persistence/object/flat/false_class_spec.rb +34 -0
  112. data/spec/persistence/object/flat/file/class_instance_spec.rb +54 -0
  113. data/spec/persistence/object/flat/file/object_instance_spec.rb +143 -0
  114. data/spec/persistence/object/flat/file_spec.rb +64 -0
  115. data/spec/persistence/object/flat/fixnum_spec.rb +32 -0
  116. data/spec/persistence/object/flat/float_spec.rb +32 -0
  117. data/spec/persistence/object/flat/indexing_spec.rb +38 -0
  118. data/spec/persistence/object/flat/rational_spec.rb +33 -0
  119. data/spec/persistence/object/flat/regexp_spec.rb +32 -0
  120. data/spec/persistence/object/flat/string_spec.rb +34 -0
  121. data/spec/persistence/object/flat/symbol_spec.rb +32 -0
  122. data/spec/persistence/object/flat/true_class_spec.rb +32 -0
  123. data/spec/persistence/object/indexes/block_index_spec.rb +119 -0
  124. data/spec/persistence/object/indexes/explicit_index_spec.rb +112 -0
  125. data/spec/persistence/object/parse_persistence_args_spec.rb +65 -0
  126. data/spec/persistence/object_spec.rb +310 -0
  127. data/spec/persistence/port/bucket/bucket_interface_spec.rb +146 -0
  128. data/spec/persistence/port/bucket/index/bucket_index_spec.rb +67 -0
  129. data/spec/persistence/port/bucket_spec.rb +20 -0
  130. data/spec/persistence/port/controller_spec.rb +60 -0
  131. data/spec/persistence/port/port_interface_spec.rb +105 -0
  132. metadata +178 -21
  133. data/.gitignore +0 -17
  134. data/Gemfile +0 -4
  135. data/LICENSE +0 -22
  136. data/Rakefile +0 -2
  137. data/lib/persistence/version.rb +0 -3
  138. data/persistence.gemspec +0 -17
@@ -0,0 +1,922 @@
1
+
2
+ require_relative '../../../../lib/persistence.rb'
3
+
4
+ describe ::Persistence::Object::Complex do
5
+
6
+ before :all do
7
+
8
+ ::Persistence.enable_port( :mock, ::Persistence::Adapter::Mock.new )
9
+
10
+ class ::Persistence::Object::Complex::UserObject
11
+ include ::Persistence::Object
12
+ attr_accessor :username, :firstname, :lastname
13
+ attr_index :username
14
+ end
15
+
16
+ class ::Persistence::Object::Complex::Address
17
+ include ::Persistence::Object
18
+ attr_accessor :number, :street, :city, :state, :zipcode
19
+ end
20
+
21
+ class ::Persistence::Object::Complex::HashContainerClass
22
+ include ::Persistence::Object
23
+ attr_accessor :some_hash, :storage_key
24
+ attr_index :storage_key
25
+ end
26
+
27
+ class ::Persistence::Object::Complex::ArrayContainerClass
28
+ include ::Persistence::Object
29
+ attr_accessor :array, :storage_key
30
+ attr_index :storage_key
31
+ end
32
+
33
+ end
34
+
35
+ after :all do
36
+
37
+ ::Persistence.disable_port( :mock )
38
+
39
+ end
40
+
41
+ it 'can persist complex objects' do
42
+ class ::Persistence::Object::Complex::UserMock
43
+ include ::Persistence::Object::Complex
44
+ attr_non_atomic_accessor :username, :firstname, :lastname, :address, :alternate_address
45
+ end
46
+ class ::Persistence::Object::Complex::AddressMock
47
+ include ::Persistence::Object::Complex
48
+ attr_non_atomic_accessor :number, :street, :city, :state, :zipcode
49
+ end
50
+
51
+ user = ::Persistence::Object::Complex::UserMock.new
52
+ user.username = 'user'
53
+ user.firstname = 'first'
54
+ user.lastname = 'last'
55
+
56
+ user.address = ::Persistence::Object::Complex::AddressMock.new
57
+ user.address.number = 42
58
+ user.address.street = 'Street'
59
+ user.address.city = 'Some City'
60
+ user.address.state = 'GA'
61
+ user.address.zipcode = '30003'
62
+
63
+ user.alternate_address = ::Persistence::Object::Complex::AddressMock.new
64
+ user.alternate_address.number = 37
65
+ user.alternate_address.street = 'Another Street'
66
+ user.alternate_address.city = 'Some Other City'
67
+ user.alternate_address.state = 'TX'
68
+ user.alternate_address.zipcode = '70004'
69
+ user.persist!
70
+
71
+ ::Persistence::Object::Complex::UserMock.persist( user.persistence_id ).should == user
72
+
73
+ user.alternate_address.number = 48
74
+
75
+ user.alternate_address.persist!
76
+
77
+ ::Persistence::Object::Complex::UserMock.persist( user.persistence_id ).should == user
78
+
79
+ end
80
+
81
+ ####################
82
+ # attr_flat #
83
+ # persists_flat? #
84
+ # attr_flat! #
85
+ ####################
86
+
87
+ it 'can force storing a attribute as a flat object' do
88
+ class ::Persistence::Object::Complex::AttrFlatMock
89
+
90
+ class ClassInstance
91
+
92
+ include ::Persistence::Object::Complex
93
+
94
+ persists_flat?( :some_attribute ).should == false
95
+ attr_flat :some_attribute
96
+ persists_flat?( :some_attribute ).should == true
97
+ non_atomic_attributes[ :some_other_attribute ] = :accessor
98
+ non_atomic_attributes[ :another_attribute ] = :accessor
99
+ attr_flat!
100
+ persists_flat?( :some_attribute ).should == true
101
+ persists_flat?( :some_other_attribute ).should == true
102
+ persists_flat?( :another_attribute ).should == true
103
+
104
+ end
105
+ end
106
+ end
107
+
108
+ ############
109
+ # cease! #
110
+ ############
111
+
112
+ it 'can delete an object by ID' do
113
+ module ::Persistence::Object::Complex::CeaseClassMock
114
+
115
+ class ClassInstance
116
+ include ::Persistence::Object::Complex
117
+ attr_non_atomic_accessor :some_value, :some_other_value
118
+ end
119
+
120
+ instance = ClassInstance.new
121
+ instance.some_value = :value
122
+ instance.some_other_value = :other_value
123
+ instance.persist!
124
+ copy = ClassInstance.persist( instance.persistence_id )
125
+ copy.should == instance
126
+ ClassInstance.cease!( instance.persistence_id )
127
+ ClassInstance.persist( instance.persistence_id ).should == nil
128
+
129
+ end
130
+ end
131
+
132
+ ################################
133
+ # attr_index #
134
+ # attr_index_with_duplicates #
135
+ ################################
136
+
137
+ it 'can create an index on a attribute' do
138
+ class ::Persistence::Object::Complex::AttrIndexMock
139
+
140
+ class ClassInstance
141
+
142
+ include ::Persistence::Object::Complex
143
+
144
+ attr_index :attribute_index
145
+ attr_index_with_duplicates :attribute_index_with_duplicates
146
+
147
+ has_attribute_index?( :attribute_index ).should == true
148
+ has_index?( :attribute_index ).should == true
149
+ has_attribute_index?( :attribute_index_with_duplicates ).should == true
150
+ has_index?( :attribute_index_with_duplicates ).should == true
151
+ index( :attribute_index ).is_a?( ::Persistence::Object::Index ).should == true
152
+ index( :attribute_index_with_duplicates ).is_a?( ::Persistence::Object::Index ).should == true
153
+
154
+ end
155
+
156
+ end
157
+ end
158
+
159
+ ###################################
160
+ # attr_delete_cascades #
161
+ # attr_delete_does_not_cascade #
162
+ # delete_cascades? #
163
+ # attr_delete_cascades! #
164
+ # attr_delete_does_not_cascade! #
165
+ ###################################
166
+
167
+ it 'can set an attribute to be deleted if self is deleted' do
168
+ module ::Persistence::Object::Complex::DeleteCascadesMock
169
+
170
+ class ObjectInstance
171
+ include ::Persistence::Object::Complex
172
+ attr_non_atomic_accessor :some_attribute, :cascading_attribute, :non_cascading_attribute, :complex_attribute
173
+ attr_delete_cascades :some_attribute
174
+ delete_cascades?( :some_attribute ).should == true
175
+ attr_delete_does_not_cascade :some_attribute
176
+ delete_cascades?( :some_attribute ).should == false
177
+ attr_delete_cascades!
178
+ delete_cascades?( :some_attribute ).should == true
179
+ attr_delete_does_not_cascade!
180
+ delete_cascades?( :some_attribute ).should == false
181
+ attr_delete_cascades :cascading_attribute
182
+ attr_delete_does_not_cascade :non_cascading_attribute
183
+ delete_cascades?( :cascading_attribute ).should == true
184
+ delete_cascades?( :non_cascading_attribute ).should == false
185
+ end
186
+ ObjectInstance.new.instance_eval do
187
+ delete_cascades?( :cascading_attribute ).should == true
188
+ delete_cascades?( :non_cascading_attribute ).should == false
189
+ object = ObjectInstance.new
190
+ object.persistence_bucket = persistence_bucket
191
+ persistence_bucket.put_object!( self )
192
+ persistence_bucket.put_attribute!( self, :complex_attribute, object )
193
+ # FIX - still have to figure out details of this
194
+ # delete_cascades?( :complex_attribute ).should == true
195
+ end
196
+
197
+ end
198
+ end
199
+
200
+ ########
201
+ # == #
202
+ ########
203
+
204
+ it 'can compare objects' do
205
+ module ::Persistence::Object::Complex::EqualsMock
206
+
207
+ class ObjectInstance
208
+ include ::Persistence::Object::Complex
209
+ attr_non_atomic_accessor :some_var, :some_other_var
210
+ end
211
+
212
+ # if we have the same ruby instance
213
+ instance = ObjectInstance.new
214
+ instance.persistence_id = 0
215
+ ( instance == instance ).should == true
216
+
217
+ # or if we have an id for both objects and the ids are not the same
218
+ other_instance = ObjectInstance.new
219
+ other_instance.persistence_id = 0
220
+ yet_other_instance = ObjectInstance.new
221
+ yet_other_instance.persistence_id = 1
222
+ ( instance == other_instance ).should == true
223
+ ( instance == yet_other_instance ).should == false
224
+
225
+ # or if the classes are not the same
226
+ ( instance == Object.new ).should == false
227
+
228
+ # otherwise if we have instance variables, compare
229
+ instance.instance_eval do
230
+ self.some_var = :some_value
231
+ self.persistence_id = nil
232
+ end
233
+ yet_other_instance.instance_eval do
234
+ self.some_var = :some_value
235
+ self.persistence_id = nil
236
+ end
237
+ ( instance == yet_other_instance ).should == true
238
+ yet_other_instance.instance_eval do
239
+ self.some_other_var = :some_other_value
240
+ end
241
+ ( instance == yet_other_instance ).should == false
242
+
243
+ end
244
+ end
245
+
246
+ ##############################
247
+ # persistence_hash_to_port #
248
+ ##############################
249
+
250
+ it "can create a persistence hash to correspond to persistence state" do
251
+ module ::Persistence::Object::Complex::PersistenceHashToPortMock
252
+
253
+ class ObjectInstance
254
+
255
+ include ::Persistence::Object::Complex
256
+
257
+ attr_atomic_accessor :flat_atomic_attribute
258
+ attr_atomic_accessor :complex_atomic_attribute
259
+ attr_non_atomic_accessor :flat_non_atomic_attribute
260
+ attr_non_atomic_accessor :complex_non_atomic_attribute
261
+ attr_accessor :flat_non_persistent_attribute
262
+ attr_accessor :complex_non_persistent_attribute
263
+ attr_flat :flat_attribute
264
+ attr_accessor :flat_non_persistent_attribute, :complex_non_persistent_attribute, :flat_attribute
265
+
266
+ def persist!
267
+ persistence_port.put_object!( self )
268
+ return self
269
+ end
270
+
271
+ end
272
+
273
+ instance = ObjectInstance.new
274
+
275
+ # flat object for attribute and for variable
276
+ instance.flat_atomic_attribute = 'flat atomic_attribute value'
277
+ complex_atomic_element = ObjectInstance.new
278
+ complex_atomic_element.flat_atomic_attribute = 'flat sub-atomic attribute'
279
+ instance.complex_atomic_attribute = complex_atomic_element
280
+
281
+ # complex object for attribute and for variable
282
+ instance.flat_non_atomic_attribute = 'flat non_atomic_attribute value'
283
+ complex_non_atomic_element = ObjectInstance.new
284
+ complex_non_atomic_element.flat_atomic_attribute = 'flat sub-atomic attribute'
285
+ instance.complex_non_atomic_attribute = complex_non_atomic_element
286
+
287
+ # non-persistent value
288
+ instance.flat_non_persistent_attribute = 'flat_non_persistent_attribute value'
289
+ instance.complex_non_persistent_attribute = 'complex_non_persistent_attribute value'
290
+
291
+ # flat complex object for attribute and for variable
292
+ instance.flat_attribute = 'flat_attribute value'
293
+
294
+ # get hash
295
+ hash_to_port = instance.persistence_hash_to_port
296
+
297
+ # make sure that flat atomic elements and non-atomic elements are included
298
+ hash_to_port[ :flat_atomic_attribute ].should == 'flat atomic_attribute value'
299
+ hash_to_port[ :flat_non_atomic_attribute ].should == 'flat non_atomic_attribute value'
300
+
301
+ # make sure that complex objects are stored by ID
302
+ hash_to_port[ :complex_atomic_attribute ].persistence_id.should == complex_atomic_element.persistence_id
303
+ hash_to_port[ :complex_non_atomic_attribute ].persistence_id.should == complex_non_atomic_element.persistence_id
304
+
305
+ end
306
+ end
307
+
308
+ ###################
309
+ # get_attribute #
310
+ ###################
311
+
312
+ it 'can serve as an adapter to a persistence bucket instance in an adapter instance' do
313
+ module ::Persistence::Object::Complex::GetAttributeMock
314
+
315
+ class ObjectInstance
316
+ include ::Persistence::Object::Complex
317
+ attr_non_atomic_accessor :simple_var, :complex_var
318
+ end
319
+ sub_object = ObjectInstance.new.instance_eval do
320
+ self.simple_var = :value
321
+ self
322
+ end
323
+ object = ObjectInstance.new.instance_eval do
324
+ self.simple_var = :some_value
325
+ self.complex_var = sub_object
326
+ self
327
+ end
328
+ bucket_instance = object.persistence_port.persistence_bucket( :some_bucket )
329
+ bucket_instance.put_object!( object )
330
+ object.persistence_id.should_not == nil
331
+ bucket_instance.get_attribute( object, :simple_var ).should == :some_value
332
+ bucket_instance.get_attribute( object, :complex_var ).persistence_hash_to_port.should == sub_object.persistence_hash_to_port
333
+ bucket_instance.delete_attribute!( object, :complex_var )
334
+ bucket_instance.get_attribute( object, :complex_var ).should == nil
335
+ bucket_instance.put_attribute!( object, :complex_var, sub_object )
336
+ bucket_instance.get_attribute( object, :complex_var ).persistence_hash_to_port.should == sub_object.persistence_hash_to_port
337
+
338
+ end
339
+ end
340
+
341
+ ####################################
342
+ # remove_atomic_attribute_values #
343
+ ####################################
344
+
345
+ it 'can remove any instance variables that are defined as atomic attributes' do
346
+ class ::Persistence::Object::Complex::PrivateMock
347
+ include ::Persistence::Object::Complex
348
+ attr_atomic_accessor :attribute1, :attribute2
349
+ end
350
+ ::Persistence::Object::Complex::PrivateMock.new.instance_eval do
351
+ self.attribute1 = :value1
352
+ self.attribute2 = :value2
353
+ remove_atomic_attribute_values
354
+ self.class::Controller.default_encapsulation.has_configuration_value?( self, :attribute1 ).should == false
355
+ self.class::Controller.default_encapsulation.has_configuration_value?( self, :attribute2 ).should == false
356
+ end
357
+ end
358
+
359
+ ########################
360
+ # is_complex_object? #
361
+ ########################
362
+
363
+ it 'can report whether an object should be treated as complex' do
364
+ class ::Persistence::Object::Complex::Mock
365
+ include ::Persistence::Object::Complex
366
+ attr_atomic_accessor :attribute1, :attribute2
367
+ end
368
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
369
+ is_complex_object?( 2**64 ).should == false # Bignum
370
+ is_complex_object?( 2 ).should == false # Fixnum
371
+ is_complex_object?( Complex( 2, 3 ) ).should == false # Complex
372
+ is_complex_object?( Rational( 2, 3 ) ).should == false # Rational
373
+ is_complex_object?( true ).should == false # TrueClass
374
+ is_complex_object?( false ).should == false # FalseClass
375
+ is_complex_object?( 'some string' ).should == false # String
376
+ is_complex_object?( :some_symbol ).should == false # Symbol
377
+ is_complex_object?( /some_string/ ).should == false # Regexp
378
+ is_complex_object?( File.new( '.' ) ).should == false # File
379
+ is_complex_object?( ::Persistence::Object::Flat::File::Path.new( '/some/path' ) ).should == false # File::Path
380
+ is_complex_object?( ::Persistence::Object::Flat::File::Contents.new( 'some file contents' ) ).should == false # File::Contents
381
+ is_complex_object?( nil ).should == false # NilClass
382
+ is_complex_object?( Object.new ).should == true # Object
383
+ end
384
+ end
385
+
386
+ ###########################################################################################################
387
+ # public ################################################################################################
388
+ ###########################################################################################################
389
+
390
+ ###################
391
+ # get_attribute #
392
+ # set_attribute #
393
+ ###################
394
+
395
+ it 'can get a variable atomically if appropriate' do
396
+ class ::Persistence::Object::Complex::Mock
397
+ include ::Persistence::Object::Complex
398
+ attr_atomic_accessor :atomic_attribute
399
+ attr_non_atomic_accessor :non_atomic_attribute
400
+ end
401
+ # test without persistence id
402
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
403
+ get_attribute( :atomic_attribute ).should == nil
404
+ set_attribute( :atomic_attribute, :some_value )
405
+ get_attribute( :atomic_attribute ).should == :some_value
406
+ end
407
+
408
+ # test with persistence id and non-atomic
409
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
410
+ self.persistence_id = 0
411
+ get_attribute( :non_atomic_attribute ).should == nil
412
+ set_attribute( :non_atomic_attribute, :some_value )
413
+ get_attribute( :non_atomic_attribute ).should == :some_value
414
+ end
415
+
416
+ # test with persistence id and atomic
417
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
418
+ atomic_attribute?( :atomic_attribute ).should == true
419
+ self.persistence_id = 1
420
+ get_attribute( :atomic_attribute ).should == nil
421
+ persistence_bucket.put_attribute!( self, :atomic_attribute, :some_value )
422
+ get_attribute( :atomic_attribute ).should == :some_value
423
+ end
424
+
425
+ # test with persistence id and atomic
426
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
427
+ atomic_attribute?( :atomic_attribute ).should == true
428
+ self.persistence_id = 2
429
+ get_attribute( :atomic_attribute ).should == nil
430
+ instance = ::Persistence::Object::Complex::Mock.new
431
+ # we don't want our port value; we give it the wrong value to make sure
432
+ persistence_port.persistence_bucket( persistence_bucket.name ).put_attribute!( self, :atomic_attribute, instance )
433
+ get_attribute( :atomic_attribute ).should == instance
434
+ get_attribute( :non_atomic_attribute ).should == nil
435
+ set_attribute( :non_atomic_attribute, :some_other_value )
436
+ # we don't want our port value; we give it the wrong value to make sure
437
+ persistence_port.persistence_bucket( persistence_bucket.name ).put_attribute!( self, :non_atomic_attribute, :not_some_other_value )
438
+ get_attribute( :non_atomic_attribute ).should == :some_other_value
439
+ end
440
+
441
+ end
442
+
443
+ ###################
444
+ # set_attribute #
445
+ ###################
446
+
447
+ it 'can set a variable atomically if appropriate' do
448
+ class ::Persistence::Object::Complex::Mock
449
+ include ::Persistence::Object::Complex
450
+ attr_atomic_accessor :atomic_attribute
451
+ attr_non_atomic_accessor :non_atomic_attribute
452
+ end
453
+
454
+ # test without persistence id and non-atomic
455
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
456
+ attr_non_atomic_accessor :some_var
457
+ get_attribute( :some_var ).should == nil
458
+ set_attribute( :some_var, :some_value )
459
+ get_attribute( :some_var ).should == :some_value
460
+ end
461
+
462
+ # test without persistence id and atomic
463
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
464
+ attr_atomic_accessor :some_var
465
+ get_attribute( :some_var ).should == nil
466
+ set_attribute( :some_var, :some_value )
467
+ get_attribute( :some_var ).should == :some_value
468
+ end
469
+
470
+ # test with persistence id and non-atomic
471
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
472
+ attr_non_atomic_accessor :some_var
473
+ self.persistence_id = 0
474
+ get_attribute( :some_var ).should == nil
475
+ set_attribute( :some_var, :some_value )
476
+ persistence_port.persistence_bucket( persistence_bucket.name ).get_attribute( self, :some_other_var ).should == nil
477
+ get_attribute( :some_var ).should == :some_value
478
+ end
479
+
480
+ # test with persistence id and atomic
481
+ ::Persistence::Object::Complex::Mock.new.instance_eval do
482
+ attr_atomic_accessor :some_var
483
+ self.persistence_id = 0
484
+ get_attribute( :some_var ).should == nil
485
+ set_attribute( :some_var, :some_value )
486
+ persistence_port.persistence_bucket( persistence_bucket.name ).get_attribute( self, :some_var ).should == :some_value
487
+ get_attribute( :some_var ).should == :some_value
488
+ end
489
+
490
+ end
491
+
492
+ #######################
493
+ # load_atomic_state #
494
+ #######################
495
+
496
+ it 'can load values for atomic state ' do
497
+ class ::Persistence::Object::Complex::PrivateMock
498
+ include ::Persistence::Object::Complex
499
+ attr_atomic_accessor :attribute1, :attribute2
500
+ end
501
+ ::Persistence::Object::Complex::PrivateMock.new.instance_eval do
502
+ self.attribute1 = :value1
503
+ self.attribute2 = :value2
504
+ load_atomic_state
505
+ @attribute1.should == :value1
506
+ @attribute2.should == :value2
507
+ end
508
+ end
509
+
510
+ it "can persist an object to and from a default bucket with an arbitrary key method" do
511
+ module ::Persistence::Object::Complex::ArbitraryKeyMethodMock
512
+
513
+ class UserObject < ::Persistence::Object::Complex::UserObject
514
+ end
515
+
516
+ user = UserObject.new
517
+ user.username = 'user'
518
+ user.firstname = 'first'
519
+ user.lastname = 'last'
520
+ user.persist!
521
+ UserObject.persist( :username => 'user' ).should == user
522
+
523
+ end
524
+ end
525
+
526
+ it "can persist an object to and from a default bucket with an arbitrary key variable" do
527
+ module ::Persistence::Object::Complex::ArbitraryKeyVariableMock
528
+
529
+ class UserObject < ::Persistence::Object::Complex::UserObject
530
+ end
531
+
532
+ user = UserObject.new
533
+ user.username = 'user'
534
+ user.firstname = 'first'
535
+ user.lastname = 'last'
536
+ user.persist!
537
+ UserObject.persist( :username => 'user' ).should == user
538
+
539
+ end
540
+ end
541
+
542
+ it "can persist an object with other objects as members" do
543
+ module ::Persistence::Object::Complex::ArbitraryNestedObjectMock
544
+
545
+ class UserObject < ::Persistence::Object::Complex::UserObject
546
+ attr_accessor :username, :firstname, :lastname, :address, :alternate_address
547
+ attr_index :username
548
+ end
549
+
550
+ class Address < ::Persistence::Object::Complex::Address
551
+ attr_accessor :number, :street, :city, :state, :zipcode
552
+ end
553
+
554
+ user = UserObject.new
555
+ user.username = 'user'
556
+ user.firstname = 'first'
557
+ user.lastname = 'last'
558
+
559
+ user.address = Address.new
560
+ user.address.number = 42
561
+ user.address.street = 'Street'
562
+ user.address.city = 'Some City'
563
+ user.address.state = 'GA'
564
+ user.address.zipcode = '30003'
565
+
566
+ user.alternate_address = Address.new
567
+ user.alternate_address.number = 37
568
+ user.alternate_address.street = 'Another Street'
569
+ user.alternate_address.city = 'Some Other City'
570
+ user.alternate_address.state = 'TX'
571
+ user.alternate_address.zipcode = '70004'
572
+ user.persist!
573
+
574
+ # here we should be looking for:
575
+ # * username => 'user' => looks for 'user' with bucket (should find it and replace it)
576
+ # * address => should get ID from existing user if user exists => needs to check if existing user address is same ID
577
+ # * alternate_ddress => should also get ID from existing user if user exists => needs to check if existing alternate address is same ID
578
+
579
+ UserObject.persist( :username => 'user' ).should == user
580
+
581
+ user.alternate_address.number = 48
582
+
583
+ user.alternate_address.persist!
584
+
585
+ UserObject.persist( :username => 'user' ).should == user
586
+
587
+ end
588
+ end
589
+
590
+ it "can persist an object with other objects as members that have atomic properties" do
591
+ module ::Persistence::Object::Complex::NestedAtomicObjectsMock
592
+
593
+ class UserObject < ::Persistence::Object::Complex::UserObject
594
+ attr_accessor :username, :firstname, :lastname, :address, :alternate_address
595
+ attr_index :username
596
+ end
597
+
598
+ class Address < ::Persistence::Object::Complex::Address
599
+ attr_accessor :number, :street, :city, :state, :zipcode
600
+ attr_atomic_accessor :number
601
+ attrs_atomic!
602
+ end
603
+
604
+ Address.atomic_attribute?( :number ).should == true
605
+
606
+ user = UserObject.new
607
+ user.username = 'user'
608
+ user.firstname = 'first'
609
+ user.lastname = 'last'
610
+
611
+ user.address = Address.new
612
+ user.address.number = 42
613
+ user.address.street = 'Street'
614
+ user.address.city = 'Some City'
615
+ user.address.state = 'GA'
616
+ user.address.zipcode = '30003'
617
+
618
+ user.alternate_address = Address.new
619
+ user.alternate_address.number = 37
620
+ user.alternate_address.street = 'Another Street'
621
+ user.alternate_address.city = 'Some Other City'
622
+ user.alternate_address.state = 'TX'
623
+ user.alternate_address.zipcode = '70004'
624
+ user.persist!
625
+
626
+ UserObject.persist( :username => 'user' ).should == user
627
+
628
+ user.alternate_address.number = 48
629
+
630
+ UserObject.persist( :username => 'user' ).should == user
631
+
632
+ end
633
+ end
634
+
635
+ it "can persist an object with hash members" do
636
+ module ::Persistence::Object::Complex::NestedHashesMock
637
+
638
+ class UserObject < ::Persistence::Object::Complex::UserObject
639
+ end
640
+
641
+ class HashContainerClass < ::Persistence::Object::Complex::HashContainerClass
642
+ end
643
+
644
+ class HashMock < ::Hash
645
+ end
646
+
647
+ hash_container = HashContainerClass.new
648
+ hash_container.storage_key = :hash_container
649
+ hash_container.some_hash = HashMock.new
650
+ hash_container.some_hash[ :hash_key ] = :hash_data
651
+
652
+ hash_container.persist!
653
+ HashContainerClass.persist( :storage_key => :hash_container ).should == hash_container
654
+
655
+ end
656
+ end
657
+
658
+ it "can persist an object with array members" do
659
+ module ::Persistence::Object::Complex::NestedArraysMock
660
+
661
+ class UserObject < ::Persistence::Object::Complex::UserObject
662
+ end
663
+
664
+ class ArrayContainerClass < ::Persistence::Object::Complex::ArrayContainerClass
665
+ end
666
+
667
+ class ArrayMock < ::Array
668
+ end
669
+
670
+ storage_key = :array_container
671
+ array_data = :array_data
672
+ array_container = ArrayContainerClass.new
673
+ array_container.storage_key = storage_key
674
+ array_container.array = ArrayMock.new
675
+ array_container.array.push( array_data )
676
+
677
+ array_container.persist!
678
+ ArrayContainerClass.persist( :storage_key => storage_key ).should == array_container
679
+
680
+ end
681
+ end
682
+
683
+ ##############
684
+ # persist! #
685
+ # persist #
686
+ ##############
687
+
688
+ it "can persist an object to and from a default bucket with an arbitrary key method" do
689
+ module ::Persistence::Object::Complex::PersistArbitraryKeyMethodMock
690
+
691
+ class UserObject < ::Persistence::Object::Complex::UserObject
692
+ end
693
+
694
+ user = UserObject.new
695
+ user.username = 'user'
696
+ user.firstname = 'first'
697
+ user.lastname = 'last'
698
+ user.persist!
699
+ persisted_user = UserObject.persist( user.persistence_id )
700
+ persisted_user.should == user
701
+ persisted_user_two = UserObject.new
702
+ persisted_user_two.persistence_id = persisted_user.persistence_id
703
+ persisted_user_two.persist
704
+ persisted_user_two.should == persisted_user
705
+ end
706
+
707
+ end
708
+
709
+ it "can persist an object to and from a default bucket with an arbitrary key variable" do
710
+ module ::Persistence::Object::Complex::PersistArbitraryKeyVariableMock
711
+
712
+ class UserObject < ::Persistence::Object::Complex::UserObject
713
+ end
714
+
715
+ user = UserObject.new
716
+ user.username = 'user'
717
+ user.firstname = 'first'
718
+ user.lastname = 'last'
719
+ user.persist!
720
+ UserObject.persist( user.persistence_id ).should == user
721
+ persisted_user_two = UserObject.new
722
+ persisted_user_two.persistence_id = user.persistence_id
723
+ persisted_user_two.persist
724
+ persisted_user_two.should == user
725
+
726
+ end
727
+ end
728
+
729
+ it "can persist an object with other objects as members" do
730
+ module ::Persistence::Object::Complex::PersistNestedObjectsMock
731
+
732
+ class UserObject < ::Persistence::Object::Complex::UserObject
733
+ attr_non_atomic_accessor :username, :firstname, :lastname, :address, :alternate_address
734
+ end
735
+
736
+ class Address < ::Persistence::Object::Complex::Address
737
+ attr_non_atomic_accessor :number, :street, :city, :state, :zipcode
738
+ end
739
+
740
+ user = UserObject.new
741
+ user.username = 'user'
742
+ user.firstname = 'first'
743
+ user.lastname = 'last'
744
+
745
+ user.address = Address.new
746
+ user.address.number = 42
747
+ user.address.street = 'Street'
748
+ user.address.city = 'Some City'
749
+ user.address.state = 'GA'
750
+ user.address.zipcode = '30003'
751
+
752
+ user.alternate_address = Address.new
753
+ user.alternate_address.number = 37
754
+ user.alternate_address.street = 'Another Street'
755
+ user.alternate_address.city = 'Some Other City'
756
+ user.alternate_address.state = 'TX'
757
+ user.alternate_address.zipcode = '70004'
758
+ user.persist!
759
+
760
+ # here we should be looking for:
761
+ # * username => 'user' => looks for 'user' with bucket (should find it and replace it)
762
+ # * address => should get ID from existing user if user exists => needs to check if existing user address is same ID
763
+ # * alternate_ddress => should also get ID from existing user if user exists => needs to check if existing alternate address is same ID
764
+
765
+ UserObject.persist( user.persistence_id ).should == user
766
+
767
+ user.alternate_address.number = 48
768
+
769
+ user.alternate_address.persist!
770
+
771
+ UserObject.persist( user.persistence_id ).should == user
772
+
773
+ end
774
+ end
775
+
776
+ it "can persist an object with other objects as members that have atomic properties" do
777
+ module ::Persistence::Object::Complex::PersistAtomicMock
778
+
779
+ class UserObject < ::Persistence::Object::Complex::UserObject
780
+ attr_non_atomic_accessor :username, :firstname, :lastname, :address, :alternate_address
781
+ end
782
+
783
+ class Address < ::Persistence::Object::Complex::Address
784
+ attr_non_atomic_accessor :number, :street, :city, :state, :zipcode
785
+ attr_atomic_accessor :number
786
+ attrs_atomic!
787
+ end
788
+
789
+ Address.atomic_attribute?( :number ).should == true
790
+
791
+ user = UserObject.new
792
+ user.username = 'user'
793
+ user.firstname = 'first'
794
+ user.lastname = 'last'
795
+
796
+ user.address = Address.new
797
+ user.address.number = 42
798
+ user.address.street = 'Street'
799
+ user.address.city = 'Some City'
800
+ user.address.state = 'GA'
801
+ user.address.zipcode = '30003'
802
+
803
+ user.alternate_address = Address.new
804
+ user.alternate_address.number = 37
805
+ user.alternate_address.street = 'Another Street'
806
+ user.alternate_address.city = 'Some Other City'
807
+ user.alternate_address.state = 'TX'
808
+ user.alternate_address.zipcode = '70004'
809
+ user.persist!
810
+
811
+ UserObject.persist( user.persistence_id ).should == user
812
+
813
+ user.alternate_address.number = 48
814
+
815
+ UserObject.persist( user.persistence_id ).should == user
816
+
817
+ end
818
+ end
819
+
820
+ it "can persist an object with hash members" do
821
+ module ::Persistence::Object::Complex::PersistNestedHashMembersMock
822
+
823
+ class HashContainerClass < ::Persistence::Object::Complex::HashContainerClass
824
+ attr_non_atomic_accessor :some_hash
825
+ end
826
+
827
+ class HashMock < ::Hash
828
+ include ::Persistence::Object::Complex::Hash
829
+ end
830
+
831
+ hash_container = HashContainerClass.new
832
+ hash_container.some_hash = HashMock.new
833
+ hash_container.some_hash[ :hash_key ] = :hash_data
834
+ hash_container.persist!
835
+ HashContainerClass.persist( hash_container.persistence_id ).should == hash_container
836
+
837
+ end
838
+ end
839
+
840
+ it "can persist an object with array members" do
841
+ module ::Persistence::Object::Complex::PersistNestedArrayMembersMock
842
+
843
+ class UserObject < ::Persistence::Object::Complex::UserObject
844
+ end
845
+
846
+ class ArrayContainerClass < ::Persistence::Object::Complex::ArrayContainerClass
847
+ attr_non_atomic_accessor :some_hash
848
+ end
849
+
850
+ class ArrayMock < ::Array
851
+ end
852
+
853
+ storage_key = :array_container
854
+ array_data = :array_data
855
+ array_container = ArrayContainerClass.new
856
+ array_container.storage_key = storage_key
857
+ array_container.array = ArrayMock.new
858
+ array_container.array.push( array_data )
859
+
860
+ array_container.persist!
861
+ ArrayContainerClass.persist( array_container.persistence_id ).should == array_container
862
+
863
+ end
864
+ end
865
+
866
+ ############
867
+ # cease! #
868
+ ############
869
+
870
+ it 'can delete an object' do
871
+ module ::Persistence::Object::Complex::CeaseObjectMock
872
+
873
+ class UserObject < ::Persistence::Object::Complex::UserObject
874
+ end
875
+
876
+ class MockObject
877
+ include ::Persistence
878
+ attr_non_atomic_accessor :some_value, :some_other_value
879
+ end
880
+ instance = MockObject.new
881
+ instance.some_value = :value
882
+ instance.some_other_value = :other_value
883
+ instance.persist!
884
+ copy = MockObject.persist( instance.persistence_id )
885
+ copy.should == instance
886
+ instance.cease!
887
+ MockObject.persist( instance.persistence_id ).should == nil
888
+
889
+ end
890
+ end
891
+
892
+ ######################
893
+ # persist! #
894
+ # index_attributes #
895
+ # persist #
896
+ ######################
897
+
898
+ it 'indexes attributes during persist' do
899
+ module ::Persistence::Object::Complex::PersistAndIndexAttributesMock
900
+
901
+ class UserObject < ::Persistence::Object::Complex::UserObject
902
+ end
903
+
904
+ class MockObject
905
+ include ::Persistence
906
+ attr_non_atomic_accessor :attribute_index
907
+ attr_index :attribute_index
908
+ end
909
+ instance = MockObject.new
910
+ instance.attribute_index = :some_value
911
+ # should call index_attributes
912
+ instance.persist!
913
+ instance_copy = MockObject.persist( :attribute_index, :some_value )
914
+ instance_copy.should == instance
915
+ instance_copy_two = MockObject.new
916
+ instance_copy_two.persist( :attribute_index, :some_value )
917
+ instance_copy_two.should == instance
918
+
919
+ end
920
+ end
921
+
922
+ end