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,337 @@
1
+
2
+ ###
3
+ # Interface implementation for Cursor class instances.
4
+ #
5
+ module ::Persistence::Cursor::CursorInterface
6
+
7
+ include ::Enumerable
8
+
9
+ ################
10
+ # initialize #
11
+ ################
12
+
13
+ ###
14
+ #
15
+ # @param bucket_instance Bucket to use for cursor context.
16
+ # @param index_instance Index to use for cursor context.
17
+ #
18
+ def initialize( bucket_instance, index_instance = nil )
19
+
20
+ @persistence_bucket = bucket_instance
21
+ @parent_index = index_instance
22
+
23
+ # use persistence port, bucket, index, value to instantiate adapter cursor
24
+ if index_instance
25
+ @adapter_cursor = index_instance.adapter_index.cursor
26
+ else
27
+ @adapter_cursor = bucket_instance.adapter_bucket.cursor
28
+ end
29
+
30
+ end
31
+
32
+ ###########
33
+ # close #
34
+ ###########
35
+
36
+ ###
37
+ # Declare cursor use complete.
38
+ #
39
+ # @return self
40
+ #
41
+ def close
42
+
43
+ @adapter_cursor.close
44
+
45
+ return self
46
+
47
+ end
48
+
49
+ #############
50
+ # atomize #
51
+ #############
52
+
53
+ ###
54
+ # Enable cursor as atomic cursor, causing objects to be loaded with atomic properties,
55
+ # regardless how they are configured.
56
+ #
57
+ # @return self
58
+ #
59
+ def atomize
60
+
61
+ extend( ::Persistence::Cursor::Atomic )
62
+
63
+ return self
64
+
65
+ end
66
+
67
+ ################
68
+ # persisted? #
69
+ ################
70
+
71
+ ###
72
+ # Query whether keys are persisted in cursor's current context.
73
+ #
74
+ # @overload persisted?( key, ... )
75
+ #
76
+ # @param [Object] Key to look up.
77
+ #
78
+ # @return [true,false] Whether key(s) exist in cursor's current context.
79
+ #
80
+ def persisted?( *args )
81
+
82
+ # [ global_id, ... ]
83
+
84
+ persisted = false
85
+
86
+ # args => global_id, ...
87
+ # positions on last id or false if one of ids is not persisted
88
+ if args.count > 0
89
+
90
+ args.each do |this_global_id|
91
+ break unless persisted = @adapter_cursor.persisted?( this_global_id )
92
+ end
93
+
94
+ # no args
95
+ # positions on first if keys or false if no keys
96
+ else
97
+
98
+ persisted = @adapter_cursor.persisted?
99
+
100
+ end
101
+
102
+ return @has_position = persisted
103
+
104
+ end
105
+
106
+ #############
107
+ # persist #
108
+ #############
109
+
110
+ ###
111
+ # Load object with specified persistence ID.
112
+ #
113
+ # @param global_id Object persistence ID for retrieval.
114
+ #
115
+ # @return [Object] Object for persistence ID.
116
+ #
117
+ def persist( global_id )
118
+
119
+ object = nil
120
+
121
+ if @has_position = @adapter_cursor.persisted?( global_id )
122
+ object = get_object( @adapter_cursor.current )
123
+ end
124
+
125
+ return object
126
+
127
+ end
128
+
129
+ ##########
130
+ # each #
131
+ ##########
132
+
133
+ ###
134
+ # Iterate objects in current cursor context.
135
+ #
136
+ # @yield [object] Current object for cursor context.
137
+ #
138
+ # @yieldparam object Object stored in cursor context.
139
+ #
140
+ def each
141
+
142
+ # we have to set position if it's not already set before we can iterate
143
+ first unless @has_position
144
+
145
+ return to_enum unless block_given?
146
+
147
+ # support for Enumerator#feed - permit a return value
148
+ feed_value = nil
149
+
150
+ begin
151
+ while yield_object = self.next
152
+ feed_value = yield( yield_object )
153
+ end
154
+ rescue StopIteration
155
+ end
156
+
157
+ return feed_value
158
+
159
+ end
160
+
161
+ ###########
162
+ # first #
163
+ ###########
164
+
165
+ ###
166
+ # Persist first object in cursor context.
167
+ #
168
+ # @param [Integer] first_count How many objects to persist from start of cursor context.
169
+ #
170
+ # @return [Object,Array<Object>] Object or objects requested.
171
+ #
172
+ def first( first_count = 1 )
173
+
174
+ objects = nil
175
+
176
+ if @has_position = persisted?
177
+ begin
178
+ if first_count == 1
179
+ objects = current
180
+ else
181
+ objects = [ ]
182
+ first_count.times do
183
+ objects.push( self.next )
184
+ end
185
+ end
186
+ # reset to first
187
+ @adapter_cursor.first
188
+ rescue StopIteration
189
+ end
190
+ end
191
+
192
+ return objects
193
+
194
+ end
195
+
196
+ ##########
197
+ # last #
198
+ ##########
199
+
200
+ ###
201
+ # Persist last object in cursor context.
202
+ #
203
+ # @param [Integer] last_count How many objects to persist from end of cursor context.
204
+ #
205
+ # @return [Object,Array<Object>] Object or objects requested.
206
+ #
207
+ def last( last_count = 1 )
208
+
209
+ objects = nil
210
+
211
+ if total_count = count
212
+ begin
213
+ first
214
+ skip_records = total_count - last_count
215
+ skip_records.times do
216
+ @adapter_cursor.next
217
+ end
218
+ if last_count == 1
219
+ objects = self.next
220
+ else
221
+ objects = [ ]
222
+ last_count.times do
223
+ objects.push( self.next )
224
+ end
225
+ end
226
+ # reset to first
227
+ @adapter_cursor.first
228
+ rescue StopIteration
229
+ end
230
+ end
231
+
232
+ return objects
233
+
234
+ end
235
+
236
+ #########
237
+ # any #
238
+ #########
239
+
240
+ ###
241
+ # Persist any object in cursor context.
242
+ #
243
+ # @param [Integer] any_count How many objects to persist from cursor context.
244
+ #
245
+ # @return [Object,Array<Object>] Object or objects requested.
246
+ #
247
+ def any( any_count = 1 )
248
+
249
+ object = nil
250
+
251
+ if total_count = count
252
+ begin
253
+ @adapter_cursor.first
254
+ objects = [ ]
255
+ any_count.times do
256
+ skip_records = rand( total_count - ( any_count + 1 ) )
257
+ skip_records.times do
258
+ @adapter_cursor.next
259
+ end
260
+ objects.push( self.next )
261
+ end
262
+ objects = objects[ 0 ] if objects.count <= 1
263
+ # reset to first
264
+ @adapter_cursor.first
265
+ rescue StopIteration
266
+ end
267
+ end
268
+
269
+ return objects
270
+
271
+ end
272
+
273
+ #############
274
+ # current #
275
+ #############
276
+
277
+ ###
278
+ # Persist current object in cursor context.
279
+ #
280
+ # @return [Object,Array<Object>] Object requested.
281
+ #
282
+ def current
283
+
284
+ first unless @has_position
285
+
286
+ return get_object( @adapter_cursor.current )
287
+
288
+ end
289
+
290
+ ##########
291
+ # next #
292
+ ##########
293
+
294
+ ###
295
+ # Return the next object in cursor's current context.
296
+ #
297
+ # @return [Object] Next object in cursor's current context.
298
+ #
299
+ def next( count = 1 )
300
+
301
+ objects = nil
302
+
303
+ if count > 1
304
+
305
+ objects = [ ]
306
+ count.times do
307
+ objects.push( get_object( @adapter_cursor.next ) )
308
+ end
309
+
310
+ else
311
+
312
+ objects = get_object( @adapter_cursor.next )
313
+
314
+ end
315
+
316
+ return objects
317
+
318
+ end
319
+
320
+ ################
321
+ # get_object #
322
+ ################
323
+
324
+ ###
325
+ # Get persistence hash for object with specified persistence ID.
326
+ #
327
+ # @param global_id Object persistence ID for retrieval.
328
+ #
329
+ # @return [Hash{String,Symbol=>Object}] Persistence hash of object properties for persistence ID.
330
+ #
331
+ def get_object( global_id )
332
+
333
+ return @persistence_bucket.get_object( global_id )
334
+
335
+ end
336
+
337
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when required block is not provided.
4
+ #
5
+ class ::Persistence::Exception::BlockRequired < Exception
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when an index is already declared with conflicting settings.
4
+ #
5
+ class ::Persistence::Exception::ConflictingIndexAlreadyDeclared < Exception
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when keys would create duplicate entries in an index that has been declared unique.
4
+ #
5
+ class ::Persistence::Exception::DuplicateViolatesUniqueIndex < Exception
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when an index that permits explicit keys is required but not provided.
4
+ #
5
+ class ::Persistence::Exception::ExplicitIndexRequired < Exception
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when index fails to generate keys and requires keys to be generated.
4
+ #
5
+ class ::Persistence::Exception::IndexingBlockFailedToGenerateKeys < Exception
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when indexing should have created keys but did not.
4
+ #
5
+ class ::Persistence::Exception::IndexingObjectRequiresKeys < Exception
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when required key value is not provided.
4
+ #
5
+ class ::Persistence::Exception::KeyValueRequired < Exception
6
+
7
+ end
@@ -0,0 +1,7 @@
1
+
2
+ ###
3
+ # Exception thrown when no persistence port is enabled and a function depending on a port is called.
4
+ #
5
+ class ::Persistence::Exception::NoPortEnabled < Exception
6
+
7
+ end
@@ -0,0 +1,21 @@
1
+
2
+ ###
3
+ # Convenience module for extending object of any type with persistence capabilities.
4
+ #
5
+ # If object is a {::Bignum}, {::Fixnum}, {::Complex}, {::Rational}, {::TrueClass}, {::FalseClass},
6
+ # {::String}, {::Symbol}, {::Regexp}, or {::NilClass} then object will include
7
+ # {::Persistence::Object::Flat Persistence::Object::Flat}.
8
+ #
9
+ # If object is a File then object will include {::Persistence::Object::Flat::File Persistence::Object::Flat::File}.
10
+ #
11
+ # If object is an Array then object will include {::Persistence::Object::Complex::Array Persistence::Object::Complex::Array}.
12
+ #
13
+ # If object is a Hash then object will include {::Persistence::Object::Complex::Hash Persistence::Object::Complex::Hash}.
14
+ #
15
+ # If object is any other class then object will include {::Persistence::Object::Complex Persistence::Object::Complex}.
16
+ #
17
+ module ::Persistence::Object
18
+
19
+ extend ::Persistence::Object::Autodetermine
20
+
21
+ end
@@ -0,0 +1,74 @@
1
+
2
+ ###
3
+ # @private
4
+ ###
5
+ # Module used internally to extend Persistence and Persistence::Object to automatically determine what type of object
6
+ # (of types: Complex, Flat, Hash, Array, File) module is being included in, and to include the appropriate
7
+ # corresponding module branch.
8
+ module ::Persistence::Object::Autodetermine
9
+
10
+ ###################
11
+ # self.extended #
12
+ ###################
13
+
14
+ def self.extended( persistence_object_module )
15
+
16
+ persistence_object_module.extend ModuleCluster::Define::Block::ClassOrModuleOrInstance
17
+
18
+ persistence_object_module.class_or_module_include do |class_or_module|
19
+
20
+ # two types of objects: complex and flat
21
+ # * complex objects persist ivars
22
+ # * flat objects persist themselves (no ivars)
23
+ #
24
+ # if you want a different result, use the appropriate module directly
25
+ # * ::Persistence::Complex
26
+ # * ::Persistence::Flat
27
+
28
+ # if we have a flat object, extend for flat object
29
+ if class_or_module <= ::Array
30
+
31
+ class_or_module.module_eval do
32
+ include ::Persistence::Object::Complex::Array
33
+ end
34
+
35
+ elsif class_or_module <= ::Hash
36
+
37
+ class_or_module.module_eval do
38
+ include ::Persistence::Object::Complex::Hash
39
+ end
40
+
41
+ elsif class_or_module <= ::Bignum or
42
+ class_or_module <= ::Fixnum or
43
+ class_or_module <= ::Complex or
44
+ class_or_module <= ::Rational or
45
+ class_or_module <= ::TrueClass or
46
+ class_or_module <= ::FalseClass or
47
+ class_or_module <= ::String or
48
+ class_or_module <= ::Symbol or
49
+ class_or_module <= ::Regexp or
50
+ class_or_module <= ::File or
51
+ class_or_module <= ::NilClass
52
+
53
+ class_or_module.module_eval do
54
+ include ::Persistence::Object::Flat
55
+ end
56
+
57
+ # otherwise extend as a complex object
58
+ else
59
+
60
+ class_or_module.module_eval do
61
+ include ::Persistence::Object::Complex
62
+ end
63
+
64
+ end
65
+
66
+ end
67
+
68
+ persistence_object_module.class_or_module_or_instance_extend do
69
+ raise 'Persistence does not expect to be used without class-level support.'
70
+ end
71
+
72
+ end
73
+
74
+ end