rod 0.6.1 → 0.6.2
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.
- data/.gitignore +7 -0
- data/{README → README.rdoc} +33 -2
- data/Rakefile +7 -2
- data/changelog.txt +13 -0
- data/contributors.txt +2 -0
- data/features/append.feature +221 -0
- data/features/assoc_indexing.feature +66 -0
- data/features/basic.feature +199 -0
- data/features/collection.feature +171 -0
- data/features/flat_indexing.feature +140 -0
- data/features/fred.feature +49 -0
- data/features/inheritence.feature +211 -0
- data/features/muliple_db.feature +113 -0
- data/features/relationships.feature +195 -0
- data/features/segmented_indexing.feature +172 -0
- data/features/steps/model.rb +386 -0
- data/features/steps/rod.rb +71 -0
- data/features/steps/test_helper.rb +5 -0
- data/lib/rod/abstract_database.rb +17 -5
- data/lib/rod/constants.rb +1 -1
- data/lib/rod/database.rb +95 -74
- data/lib/rod/join_element.rb +6 -2
- data/lib/rod/model.rb +37 -9
- data/rod.gemspec +15 -12
- data/tests/check_strings.rb +10 -0
- data/tests/class_compatibility_create.rb +14 -0
- data/tests/class_compatibility_verify.rb +18 -0
- data/tests/eff1_test.rb +60 -0
- data/tests/eff2_test.rb +61 -0
- data/tests/full_runs.rb +68 -0
- data/tests/generate_classes_create.rb +25 -0
- data/tests/generate_classes_model.rb +23 -0
- data/tests/generate_classes_rewrite.rb +7 -0
- data/tests/generate_classes_verify.rb +46 -0
- data/tests/load_struct.rb +24 -0
- data/tests/migration_create.rb +25 -0
- data/tests/migration_migrate.rb +22 -0
- data/tests/migration_model1.rb +23 -0
- data/tests/migration_model2.rb +27 -0
- data/tests/migration_verify.rb +56 -0
- data/tests/mock_tests.rb +128 -0
- data/tests/read_on_create.rb +45 -0
- data/tests/save_struct.rb +49 -0
- data/tests/structures.rb +52 -0
- data/tests/unit/database.rb +60 -0
- data/tests/unit/model.rb +36 -0
- data/tests/unit/model_tests.rb +116 -0
- data/tests/validate_read_on_create.rb +12 -0
- data/utils/convert_index.rb +31 -0
- metadata +77 -28
@@ -52,7 +52,7 @@ module Rod
|
|
52
52
|
if File.exist?(@path)
|
53
53
|
remove_file("#{@path}database.yml")
|
54
54
|
else
|
55
|
-
|
55
|
+
FileUtils.mkdir_p(@path)
|
56
56
|
end
|
57
57
|
self.classes.each do |klass|
|
58
58
|
klass.send(:build_structure)
|
@@ -68,6 +68,7 @@ module Rod
|
|
68
68
|
next if special_class?(klass)
|
69
69
|
remove_files_but(klass.inline_library)
|
70
70
|
end
|
71
|
+
remove_files(self.inline_library)
|
71
72
|
generate_c_code(@path, classes)
|
72
73
|
remove_files_but(self.inline_library)
|
73
74
|
@metadata = {}
|
@@ -104,6 +105,7 @@ module Rod
|
|
104
105
|
elsif options[:migrate]
|
105
106
|
create_legacy_classes
|
106
107
|
FileUtils.cp(@path + DATABASE_FILE, @path + DATABASE_FILE + LEGACY_DATA_SUFFIX)
|
108
|
+
remove_files(self.inline_library)
|
107
109
|
end
|
108
110
|
self.classes.each do |klass|
|
109
111
|
klass.send(:build_structure)
|
@@ -266,16 +268,26 @@ module Rod
|
|
266
268
|
end
|
267
269
|
|
268
270
|
# Returns the string of given +length+ starting at given +offset+.
|
269
|
-
|
271
|
+
# Options:
|
272
|
+
# * +:skip_encoding+ - if set to +true+, the string is left as ASCII-8BIT
|
273
|
+
def read_string(length, offset,options={})
|
270
274
|
# TODO the encoding should be stored in the DB
|
271
275
|
# or configured globally
|
272
|
-
_read_string(length, offset, @handler)
|
276
|
+
value = _read_string(length, offset, @handler)
|
277
|
+
if options[:skip_encoding]
|
278
|
+
value.force_encoding("ascii-8bit")
|
279
|
+
else
|
280
|
+
value.force_encoding("utf-8")
|
281
|
+
end
|
273
282
|
end
|
274
283
|
|
275
284
|
# Stores the string in the DB encoding it to utf-8.
|
276
|
-
|
285
|
+
# Options:
|
286
|
+
# * +:skip_encoding+ - if set to +true+, the string is not encoded
|
287
|
+
def set_string(value,options={})
|
277
288
|
raise DatabaseError.new("Readonly database.") if readonly_data?
|
278
|
-
|
289
|
+
value = value.encode("utf-8") unless options[:skip_encoding]
|
290
|
+
_set_string(value,@handler)
|
279
291
|
end
|
280
292
|
|
281
293
|
# Returns the number of objects for given +klass+.
|
data/lib/rod/constants.rb
CHANGED
data/lib/rod/database.rb
CHANGED
@@ -57,19 +57,19 @@ module Rod
|
|
57
57
|
# exist.
|
58
58
|
def open_class_file(klass)
|
59
59
|
str =<<-END
|
60
|
-
|
61
|
-
|if(model_p->#{klass.struct_name}_lib_file == -1){
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
60
|
+
| // create the file unless it exists
|
61
|
+
| if(model_p->#{klass.struct_name}_lib_file == -1){
|
62
|
+
| char * path = malloc(sizeof(char) * (strlen(model_p->path) +
|
63
|
+
| #{klass.path_for_data("").size} + 1));
|
64
|
+
| strcpy(path,model_p->path);
|
65
|
+
| strcat(path,"#{klass.path_for_data("")}");
|
66
|
+
| model_p->#{klass.struct_name}_lib_file =
|
67
|
+
| open(path, O_RDWR | O_CREAT, S_IRUSR | S_IWUSR);
|
68
|
+
| if(model_p->#{klass.struct_name}_lib_file == -1) {
|
69
|
+
| rb_raise(rodException(),"Could not open file for class #{klass} on path %s writing.",path);
|
70
|
+
| }
|
71
|
+
| free(path);
|
70
72
|
| }
|
71
|
-
| free(path);
|
72
|
-
|}
|
73
73
|
END
|
74
74
|
str.margin
|
75
75
|
end
|
@@ -109,34 +109,36 @@ module Rod
|
|
109
109
|
|
|
110
110
|
| // increase the pages count by 1
|
111
111
|
| model_p->#{klass.struct_name}_page_count += ALLOCATED_PAGES;
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
| model_p->#{klass.struct_name}
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
112
|
+
| {
|
113
|
+
| // open the file for writing
|
114
|
+
| char* #{klass.struct_name}_empty_data;
|
115
|
+
| FILE * #{klass.struct_name}_file =
|
116
|
+
| fdopen(model_p->#{klass.struct_name}_lib_file,"w+");
|
117
|
+
| if(#{klass.struct_name}_file == NULL){
|
118
|
+
| rb_raise(rodException(),"Could not open file for #{klass.struct_name}.");
|
119
|
+
| }
|
120
|
+
| // seek to the end
|
121
|
+
| if(fseek(#{klass.struct_name}_file,0,SEEK_END) == -1){
|
122
|
+
| rb_raise(rodException(),"Could not seek to end file for #{klass.struct_name}.");
|
123
|
+
| }
|
124
|
+
| // write empty data at the end
|
125
|
+
| #{klass.struct_name}_empty_data = calloc(page_size() * ALLOCATED_PAGES,1);
|
126
|
+
| if(write(model_p->#{klass.struct_name}_lib_file,#{klass.struct_name}_empty_data,
|
127
|
+
| page_size() * ALLOCATED_PAGES) == -1){
|
128
|
+
| rb_raise(rodException(),"Could not write to file for #{klass.struct_name}.");
|
129
|
+
| }
|
130
|
+
| // seek to the beginning
|
131
|
+
| if(fseek(#{klass.struct_name}_file,0,SEEK_SET) == -1){
|
132
|
+
| rb_raise(rodException(),"Could not seek to start file for #{klass.struct_name}.");
|
133
|
+
| }
|
134
|
+
| // mmap the extended file
|
135
|
+
| model_p->#{klass.struct_name}_table = mmap(NULL,
|
136
|
+
| model_p->#{klass.struct_name}_page_count * page_size(),
|
137
|
+
| PROT_WRITE | PROT_READ, MAP_SHARED, model_p->#{klass.struct_name}_lib_file,0);
|
138
|
+
| if(model_p->#{klass.struct_name}_table == MAP_FAILED){
|
139
|
+
| perror(NULL);
|
140
|
+
| rb_raise(rodException(),"Could not mmap segment for #{klass.struct_name}.");
|
141
|
+
| }
|
140
142
|
| }
|
141
143
|
|#{update_pointer(klass) unless special_class?(klass)}
|
142
144
|
END
|
@@ -153,6 +155,19 @@ module Rod
|
|
153
155
|
# Implementations of abstract methods
|
154
156
|
#########################################################################
|
155
157
|
|
158
|
+
# Ruby inline generated shared library name.
|
159
|
+
def inline_library
|
160
|
+
unless defined?(@inline_library)
|
161
|
+
self.class.inline(:C) do |builder|
|
162
|
+
builder.c_singleton("void __unused_method_#{rand(1000)}(){}")
|
163
|
+
|
164
|
+
self.instance_variable_set("@inline_library",builder.so_name)
|
165
|
+
end
|
166
|
+
end
|
167
|
+
@inline_library
|
168
|
+
end
|
169
|
+
|
170
|
+
|
156
171
|
# Generates the code C responsible for management of the database.
|
157
172
|
def generate_c_code(path, classes)
|
158
173
|
if !@code_generated || @@rod_development_mode
|
@@ -177,14 +192,7 @@ module Rod
|
|
177
192
|
END
|
178
193
|
builder.prefix(str.margin)
|
179
194
|
|
180
|
-
|
181
|
-
|VALUE rodException(){
|
182
|
-
| VALUE klass = rb_const_get(rb_cObject, rb_intern("Rod"));
|
183
|
-
| klass = rb_const_get(klass, rb_intern("DatabaseError"));
|
184
|
-
| return klass;
|
185
|
-
|}
|
186
|
-
END
|
187
|
-
builder.prefix(str.margin)
|
195
|
+
builder.prefix(self.class.rod_exception)
|
188
196
|
|
189
197
|
|
190
198
|
#########################################
|
@@ -215,7 +223,7 @@ module Rod
|
|
215
223
|
|VALUE _join_element_index(unsigned long element_offset, unsigned long element_index, VALUE handler){
|
216
224
|
| #{model_struct} * model_p;
|
217
225
|
| Data_Get_Struct(handler,#{model_struct},model_p);
|
218
|
-
| return
|
226
|
+
| return ULONG2NUM((model_p->_join_element_table + element_offset + element_index)->offset);
|
219
227
|
|}
|
220
228
|
END
|
221
229
|
builder.c(str.margin)
|
@@ -225,7 +233,7 @@ module Rod
|
|
225
233
|
| unsigned long element_index, VALUE handler){
|
226
234
|
| #{model_struct} * model_p;
|
227
235
|
| Data_Get_Struct(handler,#{model_struct},model_p);
|
228
|
-
| return
|
236
|
+
| return ULONG2NUM((model_p->_polymorphic_join_element_table +
|
229
237
|
| element_offset + element_index)->offset);
|
230
238
|
|}
|
231
239
|
END
|
@@ -236,7 +244,7 @@ module Rod
|
|
236
244
|
| unsigned long element_index, VALUE handler){
|
237
245
|
| #{model_struct} * model_p;
|
238
246
|
| Data_Get_Struct(handler,#{model_struct},model_p);
|
239
|
-
| return
|
247
|
+
| return ULONG2NUM((model_p->_polymorphic_join_element_table +
|
240
248
|
| element_offset + element_index)->class);
|
241
249
|
|}
|
242
250
|
END
|
@@ -247,12 +255,11 @@ module Rod
|
|
247
255
|
| unsigned long element_index, unsigned long offset,
|
248
256
|
| VALUE handler){
|
249
257
|
| #{model_struct} * model_p;
|
250
|
-
| Data_Get_Struct(handler,#{model_struct},model_p);
|
251
258
|
| _join_element * element_p;
|
259
|
+
| Data_Get_Struct(handler,#{model_struct},model_p);
|
252
260
|
| element_p = model_p->_join_element_table + element_offset + element_index;
|
253
261
|
| if(element_p->index != element_index){
|
254
|
-
|
|
255
|
-
| rb_raise(eClass, "Join element indices are inconsistent: %lu %lu!",
|
262
|
+
| rb_raise(rodException(), "Join element indices are inconsistent: %lu %lu!",
|
256
263
|
| element_index, element_p->index);
|
257
264
|
| }
|
258
265
|
| element_p->offset = offset;
|
@@ -265,12 +272,11 @@ module Rod
|
|
265
272
|
| unsigned long element_index, unsigned long offset, unsigned long class_id,
|
266
273
|
| VALUE handler){
|
267
274
|
| #{model_struct} * model_p;
|
268
|
-
| Data_Get_Struct(handler,#{model_struct},model_p);
|
269
275
|
| _polymorphic_join_element * element_p;
|
276
|
+
| Data_Get_Struct(handler,#{model_struct},model_p);
|
270
277
|
| element_p = model_p->_polymorphic_join_element_table + element_offset + element_index;
|
271
278
|
| if(element_p->index != element_index){
|
272
|
-
|
|
273
|
-
| rb_raise(eClass, "Polymorphic join element indices are inconsistent: %lu %lu!",
|
279
|
+
| rb_raise(rodException(), "Polymorphic join element indices are inconsistent: %lu %lu!",
|
274
280
|
| element_index, element_p->index);
|
275
281
|
| }
|
276
282
|
| element_p->offset = offset;
|
@@ -284,8 +290,9 @@ module Rod
|
|
284
290
|
| _join_element * element;
|
285
291
|
| unsigned long index;
|
286
292
|
| #{model_struct} * model_p;
|
293
|
+
| unsigned long result;
|
287
294
|
| Data_Get_Struct(handler,#{model_struct},model_p);
|
288
|
-
|
|
295
|
+
| result = model_p->_join_element_count;
|
289
296
|
| for(index = 0; index < size; index++){
|
290
297
|
| if((model_p->_join_element_count + 1) * sizeof(_join_element) >=
|
291
298
|
| page_size() * model_p->_join_element_page_count){
|
@@ -306,8 +313,9 @@ module Rod
|
|
306
313
|
| _polymorphic_join_element * element;
|
307
314
|
| unsigned long index;
|
308
315
|
| #{model_struct} * model_p;
|
316
|
+
| unsigned long result;
|
309
317
|
| Data_Get_Struct(handler,#{model_struct},model_p);
|
310
|
-
|
|
318
|
+
| result = model_p->_polymorphic_join_element_count;
|
311
319
|
| for(index = 0; index < size; index++){
|
312
320
|
| if((model_p->_polymorphic_join_element_count + 1) *
|
313
321
|
| sizeof(_polymorphic_join_element) >=
|
@@ -332,8 +340,9 @@ module Rod
|
|
332
340
|
str =<<-END
|
333
341
|
|VALUE _read_string(unsigned long length, unsigned long offset, VALUE handler){
|
334
342
|
| #{model_struct} * model_p;
|
343
|
+
| char * str;
|
335
344
|
| Data_Get_Struct(handler,#{model_struct},model_p);
|
336
|
-
|
|
345
|
+
| str = model_p->#{StringElement.struct_name}_table + offset;
|
337
346
|
| return rb_str_new(str, length);
|
338
347
|
|}
|
339
348
|
END
|
@@ -344,10 +353,9 @@ module Rod
|
|
344
353
|
|// The return value is a pair: length and offset.
|
345
354
|
|VALUE _set_string(VALUE ruby_value, VALUE handler){
|
346
355
|
| #{model_struct} * model_p;
|
347
|
-
| Data_Get_Struct(handler,#{model_struct},model_p);
|
348
356
|
| unsigned long length = RSTRING_LEN(ruby_value);
|
349
357
|
| char * value = RSTRING_PTR(ruby_value);
|
350
|
-
| unsigned long string_offset, page_offset, current_page;
|
358
|
+
| unsigned long string_offset, page_offset, current_page, sum;
|
351
359
|
| char * dest;
|
352
360
|
| // table:
|
353
361
|
| // - address of the first page
|
@@ -356,12 +364,17 @@ module Rod
|
|
356
364
|
| // count:
|
357
365
|
| // - total number of bytes
|
358
366
|
| long length_left = length;
|
367
|
+
| // see the routine description above.
|
368
|
+
| VALUE result;
|
369
|
+
| // get the structure
|
370
|
+
| Data_Get_Struct(handler,#{model_struct},model_p);
|
359
371
|
| // first free byte in current page
|
360
372
|
| string_offset = model_p->#{StringElement.struct_name}_count % page_size();
|
361
373
|
| page_offset = model_p->#{StringElement.struct_name}_count / page_size();
|
362
374
|
| current_page = page_offset;
|
363
375
|
| while(length_left > 0){
|
364
|
-
|
|
376
|
+
| sum = ((unsigned long)length_left) + string_offset;
|
377
|
+
| if(sum >= page_size()){
|
365
378
|
| \n#{mmap_class(StringElement)}
|
366
379
|
| }
|
367
380
|
| dest = model_p->#{StringElement.struct_name}_table +
|
@@ -378,9 +391,9 @@ module Rod
|
|
378
391
|
|
|
379
392
|
| model_p->#{StringElement.struct_name}_count += length;
|
380
393
|
|
|
381
|
-
|
|
382
|
-
| rb_ary_push(result,
|
383
|
-
| rb_ary_push(result,
|
394
|
+
| result = rb_ary_new();
|
395
|
+
| rb_ary_push(result, ULONG2NUM(length));
|
396
|
+
| rb_ary_push(result, ULONG2NUM(string_offset + page_offset * page_size()));
|
384
397
|
| return result;
|
385
398
|
|}
|
386
399
|
END
|
@@ -410,12 +423,13 @@ module Rod
|
|
410
423
|
|void _store_#{klass.struct_name}(VALUE object, VALUE handler){
|
411
424
|
|
|
412
425
|
| #{model_struct} * model_p;
|
426
|
+
| #{klass.struct_name} * struct_p;
|
413
427
|
| Data_Get_Struct(handler,#{model_struct},model_p);
|
414
428
|
| if((model_p->#{klass.struct_name}_count+1) * sizeof(#{klass.struct_name}) >=
|
415
429
|
| model_p->#{klass.struct_name}_page_count * page_size()){
|
416
430
|
| \n#{mmap_class(klass)}
|
417
431
|
| }
|
418
|
-
|
|
432
|
+
| struct_p = model_p->#{klass.struct_name}_table +
|
419
433
|
| model_p->#{klass.struct_name}_count;
|
420
434
|
| //printf("struct assigned\\n");
|
421
435
|
| model_p->#{klass.struct_name}_count++;
|
@@ -423,7 +437,7 @@ module Rod
|
|
423
437
|
| //the number is incresed by 1, because 0 indicates that the
|
424
438
|
| //(referenced) object is nil
|
425
439
|
| struct_p->rod_id = model_p->#{klass.struct_name}_count;
|
426
|
-
| rb_iv_set(object, \"@rod_id\",
|
440
|
+
| rb_iv_set(object, \"@rod_id\",ULONG2NUM(struct_p->rod_id));
|
427
441
|
|}
|
428
442
|
END
|
429
443
|
builder.c(str.margin)
|
@@ -435,6 +449,7 @@ module Rod
|
|
435
449
|
str = <<-END
|
436
450
|
|VALUE _init_handler(char * dir_path){
|
437
451
|
| #{model_struct} * model_p;
|
452
|
+
| VALUE cClass;
|
438
453
|
| model_p = ALLOC(#{model_struct});
|
439
454
|
|
|
440
455
|
| #{init_structs(classes)}
|
@@ -444,7 +459,7 @@ module Rod
|
|
444
459
|
| strcpy(model_p->path,dir_path);
|
445
460
|
|
|
446
461
|
| //create the wrapping object
|
447
|
-
|
|
462
|
+
| cClass = rb_define_class("#{model_struct_name(path).camelcase(true)}",
|
448
463
|
| rb_cObject);
|
449
464
|
| return Data_Wrap_Struct(cClass, 0, free, model_p);
|
450
465
|
|}
|
@@ -569,11 +584,6 @@ module Rod
|
|
569
584
|
# This has to be at the very end of builder definition!
|
570
585
|
self.instance_variable_set("@inline_library",builder.so_name)
|
571
586
|
|
572
|
-
# Ruby inline generated shared library.
|
573
|
-
def self.inline_library
|
574
|
-
@inline_library
|
575
|
-
end
|
576
|
-
|
577
587
|
end
|
578
588
|
@code_generated = true
|
579
589
|
end
|
@@ -602,5 +612,16 @@ module Rod
|
|
602
612
|
END
|
603
613
|
builder.c(str.margin)
|
604
614
|
end
|
615
|
+
|
616
|
+
def self.rod_exception
|
617
|
+
str =<<-END
|
618
|
+
|VALUE rodException(){
|
619
|
+
| VALUE klass = rb_const_get(rb_cObject, rb_intern("Rod"));
|
620
|
+
| klass = rb_const_get(klass, rb_intern("DatabaseError"));
|
621
|
+
| return klass;
|
622
|
+
|}
|
623
|
+
END
|
624
|
+
str.margin
|
625
|
+
end
|
605
626
|
end
|
606
627
|
end
|
data/lib/rod/join_element.rb
CHANGED
@@ -13,7 +13,9 @@ module Rod
|
|
13
13
|
end
|
14
14
|
|
15
15
|
def self.layout
|
16
|
-
' printf(" offset: %lu, index: %lu\n",
|
16
|
+
' printf(" offset: %lu, index: %lu\n",' +
|
17
|
+
'(unsigned long)sizeof(unsigned long), ' +
|
18
|
+
'(unsigned long)sizeof(unsigned long));' + "\n"
|
17
19
|
end
|
18
20
|
|
19
21
|
def self.struct_name
|
@@ -39,7 +41,9 @@ module Rod
|
|
39
41
|
|
40
42
|
def self.layout
|
41
43
|
' printf(" offset: %lu, index: %lu, class: %lu\n",' +
|
42
|
-
'
|
44
|
+
'(unsigned long)sizeof(unsigned long), ' +
|
45
|
+
'(unsigned long)sizeof(unsigned long), ' +
|
46
|
+
'(unsigned long)sizeof(unsigned long));' + "\n"
|
43
47
|
end
|
44
48
|
end
|
45
49
|
end
|
data/lib/rod/model.rb
CHANGED
@@ -52,14 +52,19 @@ module Rod
|
|
52
52
|
self.class == other.class && self.rod_id == other.rod_id
|
53
53
|
end
|
54
54
|
|
55
|
-
# Default implementation of
|
56
|
-
def
|
55
|
+
# Default implementation of +inspect+.
|
56
|
+
def inspect
|
57
57
|
fields = self.class.fields.map{|n,o| "#{n}:#{self.send(n)}"}.join(",")
|
58
58
|
singular = self.class.singular_associations.map{|n,o| "#{n}:#{self.send(n).class}"}.join(",")
|
59
59
|
plural = self.class.plural_associations.map{|n,o| "#{n}:#{self.send(n).size}"}.join(",")
|
60
60
|
"#{self.class}:<#{fields}><#{singular}><#{plural}>"
|
61
61
|
end
|
62
62
|
|
63
|
+
# Default implementation of +to_s+.
|
64
|
+
def to_s
|
65
|
+
self.inspect
|
66
|
+
end
|
67
|
+
|
63
68
|
# Returns the number of objects of this class stored in the
|
64
69
|
# database.
|
65
70
|
def self.count
|
@@ -228,7 +233,11 @@ module Rod
|
|
228
233
|
else
|
229
234
|
raise RodException.new("Unrecognised field type '#{self.class.fields[name][:type]}'!")
|
230
235
|
end
|
231
|
-
|
236
|
+
options = {}
|
237
|
+
if self.class.fields[name][:type] == :object
|
238
|
+
options[:skip_encoding] = true
|
239
|
+
end
|
240
|
+
length, offset = database.set_string(value,options)
|
232
241
|
send("_#{name}_length=",@rod_id,length)
|
233
242
|
send("_#{name}_offset=",@rod_id,offset)
|
234
243
|
else
|
@@ -726,20 +735,23 @@ module Rod
|
|
726
735
|
result = <<-END
|
727
736
|
| \n#{self.fields.map do |field,options|
|
728
737
|
unless string_field?(options[:type])
|
729
|
-
"| printf(\" size of '#{field}': %lu\\n\",
|
738
|
+
"| printf(\" size of '#{field}': %lu\\n\"," +
|
739
|
+
"(unsigned long)sizeof(#{TYPE_MAPPING[options[:type]]}));"
|
730
740
|
else
|
731
741
|
<<-SUBEND
|
732
742
|
| printf(" string '#{field}' length: %lu offset: %lu page: %lu\\n",
|
733
|
-
| sizeof(unsigned long),
|
743
|
+
| (unsigned long)sizeof(unsigned long), (unsigned long)sizeof(unsigned long),
|
744
|
+
| (unsigned long)sizeof(unsigned long));
|
734
745
|
SUBEND
|
735
746
|
end
|
736
747
|
end.join("\n") }
|
737
748
|
| \n#{singular_associations.map do |name, options|
|
738
|
-
" printf(\" singular assoc '#{name}': %lu\\n\",
|
749
|
+
" printf(\" singular assoc '#{name}': %lu\\n\","+
|
750
|
+
"(unsigned long)sizeof(unsigned long));"
|
739
751
|
end.join("\n| ")}
|
740
752
|
| \n#{plural_associations.map do |name, options|
|
741
753
|
"| printf(\" plural assoc '#{name}' offset: %lu, count %lu\\n\",\n"+
|
742
|
-
"| sizeof(unsigned long),sizeof(unsigned long));"
|
754
|
+
"| (unsigned long)sizeof(unsigned long),(unsigned long)sizeof(unsigned long));"
|
743
755
|
end.join("\n| \n")}
|
744
756
|
END
|
745
757
|
result.margin
|
@@ -749,6 +761,9 @@ module Rod
|
|
749
761
|
def self.field_reader(name,result_type,builder)
|
750
762
|
str =<<-END
|
751
763
|
|#{result_type} _#{name}(unsigned long object_rod_id){
|
764
|
+
| if(object_rod_id == 0){
|
765
|
+
| rb_raise(rodException(), "Invalid object rod_id (0)");
|
766
|
+
| }
|
752
767
|
| VALUE klass = rb_funcall(self,rb_intern("class"),0);
|
753
768
|
| #{struct_name} * pointer = (#{struct_name} *)
|
754
769
|
| NUM2ULONG(rb_funcall(klass,rb_intern("rod_pointer"),0));
|
@@ -762,6 +777,9 @@ module Rod
|
|
762
777
|
def self.field_writer(name,arg_type,builder)
|
763
778
|
str =<<-END
|
764
779
|
|void _#{name}_equals(unsigned long object_rod_id,#{arg_type} value){
|
780
|
+
| if(object_rod_id == 0){
|
781
|
+
| rb_raise(rodException(), "Invalid object rod_id (0)");
|
782
|
+
| }
|
765
783
|
| VALUE klass = rb_funcall(self,rb_intern("class"),0);
|
766
784
|
| #{struct_name} * pointer = (#{struct_name} *)
|
767
785
|
| NUM2ULONG(rb_funcall(klass,rb_intern("rod_pointer"),0));
|
@@ -786,6 +804,7 @@ module Rod
|
|
786
804
|
|
787
805
|
inline(:C) do |builder|
|
788
806
|
builder.prefix(typedef_struct)
|
807
|
+
builder.prefix(Database.rod_exception)
|
789
808
|
if Database.development_mode
|
790
809
|
# This method is created to force rebuild of the C code, since
|
791
810
|
# it is rebuild on the basis of methods' signatures change.
|
@@ -883,7 +902,11 @@ module Rod
|
|
883
902
|
return (options[:type] == :object ? nil : "")
|
884
903
|
end
|
885
904
|
offset = send("_#{field}_offset", @rod_id)
|
886
|
-
|
905
|
+
read_options = {}
|
906
|
+
if options[:type] == :object
|
907
|
+
read_options[:skip_encoding] = true
|
908
|
+
end
|
909
|
+
value = database.read_string(length, offset, options)
|
887
910
|
if options[:type] == :object
|
888
911
|
value = Marshal.load(value)
|
889
912
|
end
|
@@ -917,6 +940,7 @@ module Rod
|
|
917
940
|
define_method(name) do
|
918
941
|
value = instance_variable_get("@#{name}")
|
919
942
|
if value.nil?
|
943
|
+
return nil if @rod_id == 0
|
920
944
|
rod_id = send("_#{name}",@rod_id)
|
921
945
|
# the indices are shifted by 1, to leave 0 for nil
|
922
946
|
if rod_id == 0
|
@@ -973,7 +997,11 @@ module Rod
|
|
973
997
|
if (instance_variable_get("@#{name}") != nil)
|
974
998
|
return instance_variable_get("@#{name}").count
|
975
999
|
else
|
976
|
-
|
1000
|
+
if @rod_id == 0
|
1001
|
+
return 0
|
1002
|
+
else
|
1003
|
+
return send("_#{name}_count",@rod_id)
|
1004
|
+
end
|
977
1005
|
end
|
978
1006
|
end
|
979
1007
|
|