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.
Files changed (50) hide show
  1. data/.gitignore +7 -0
  2. data/{README → README.rdoc} +33 -2
  3. data/Rakefile +7 -2
  4. data/changelog.txt +13 -0
  5. data/contributors.txt +2 -0
  6. data/features/append.feature +221 -0
  7. data/features/assoc_indexing.feature +66 -0
  8. data/features/basic.feature +199 -0
  9. data/features/collection.feature +171 -0
  10. data/features/flat_indexing.feature +140 -0
  11. data/features/fred.feature +49 -0
  12. data/features/inheritence.feature +211 -0
  13. data/features/muliple_db.feature +113 -0
  14. data/features/relationships.feature +195 -0
  15. data/features/segmented_indexing.feature +172 -0
  16. data/features/steps/model.rb +386 -0
  17. data/features/steps/rod.rb +71 -0
  18. data/features/steps/test_helper.rb +5 -0
  19. data/lib/rod/abstract_database.rb +17 -5
  20. data/lib/rod/constants.rb +1 -1
  21. data/lib/rod/database.rb +95 -74
  22. data/lib/rod/join_element.rb +6 -2
  23. data/lib/rod/model.rb +37 -9
  24. data/rod.gemspec +15 -12
  25. data/tests/check_strings.rb +10 -0
  26. data/tests/class_compatibility_create.rb +14 -0
  27. data/tests/class_compatibility_verify.rb +18 -0
  28. data/tests/eff1_test.rb +60 -0
  29. data/tests/eff2_test.rb +61 -0
  30. data/tests/full_runs.rb +68 -0
  31. data/tests/generate_classes_create.rb +25 -0
  32. data/tests/generate_classes_model.rb +23 -0
  33. data/tests/generate_classes_rewrite.rb +7 -0
  34. data/tests/generate_classes_verify.rb +46 -0
  35. data/tests/load_struct.rb +24 -0
  36. data/tests/migration_create.rb +25 -0
  37. data/tests/migration_migrate.rb +22 -0
  38. data/tests/migration_model1.rb +23 -0
  39. data/tests/migration_model2.rb +27 -0
  40. data/tests/migration_verify.rb +56 -0
  41. data/tests/mock_tests.rb +128 -0
  42. data/tests/read_on_create.rb +45 -0
  43. data/tests/save_struct.rb +49 -0
  44. data/tests/structures.rb +52 -0
  45. data/tests/unit/database.rb +60 -0
  46. data/tests/unit/model.rb +36 -0
  47. data/tests/unit/model_tests.rb +116 -0
  48. data/tests/validate_read_on_create.rb +12 -0
  49. data/utils/convert_index.rb +31 -0
  50. metadata +77 -28
@@ -0,0 +1,5 @@
1
+ $:.unshift "lib"
2
+ require 'rod'
3
+ module RodTest
4
+ end
5
+
@@ -52,7 +52,7 @@ module Rod
52
52
  if File.exist?(@path)
53
53
  remove_file("#{@path}database.yml")
54
54
  else
55
- Dir.mkdir(@path)
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
- def read_string(length, offset)
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).force_encoding("utf-8")
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
- def set_string(value)
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
- _set_string(value.encode("utf-8"),@handler)
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
@@ -1,5 +1,5 @@
1
1
  module Rod
2
- VERSION = "0.6.1"
2
+ VERSION = "0.6.2"
3
3
 
4
4
  # The name of file containing the data base.
5
5
  DATABASE_FILE = "database.yml"
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
- |// 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);
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
- | // open the file for writing
114
- | FILE * #{klass.struct_name}_file =
115
- | fdopen(model_p->#{klass.struct_name}_lib_file,"w+");
116
- | if(#{klass.struct_name}_file == NULL){
117
- | rb_raise(rodException(),"Could not open file for #{klass.struct_name}.");
118
- | }
119
- | // seek to the end
120
- | if(fseek(#{klass.struct_name}_file,0,SEEK_END) == -1){
121
- | rb_raise(rodException(),"Could not seek to end file for #{klass.struct_name}.");
122
- | }
123
- | // write empty data at the end
124
- | char* #{klass.struct_name}_empty_data = calloc(page_size() * ALLOCATED_PAGES,1);
125
- | if(write(model_p->#{klass.struct_name}_lib_file,#{klass.struct_name}_empty_data,
126
- | page_size() * ALLOCATED_PAGES) == -1){
127
- | rb_raise(rodException(),"Could not write to file for #{klass.struct_name}.");
128
- | }
129
- | // seek to the beginning
130
- | if(fseek(#{klass.struct_name}_file,0,SEEK_SET) == -1){
131
- | rb_raise(rodException(),"Could not seek to start file for #{klass.struct_name}.");
132
- | }
133
- | // mmap the extended file
134
- | model_p->#{klass.struct_name}_table = mmap(NULL,
135
- | model_p->#{klass.struct_name}_page_count * page_size(),
136
- | PROT_WRITE | PROT_READ, MAP_SHARED, model_p->#{klass.struct_name}_lib_file,0);
137
- | if(model_p->#{klass.struct_name}_table == MAP_FAILED){
138
- | perror(NULL);
139
- | rb_raise(rodException(),"Could not mmap segment for #{klass.struct_name}.");
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
- str =<<-END
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 UINT2NUM((model_p->_join_element_table + element_offset + element_index)->offset);
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 UINT2NUM((model_p->_polymorphic_join_element_table +
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 UINT2NUM((model_p->_polymorphic_join_element_table +
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
- | VALUE eClass = rb_const_get(rb_cObject, rb_intern("Exception"));
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
- | VALUE eClass = rb_const_get(rb_cObject, rb_intern("Exception"));
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
- | unsigned long result = model_p->_join_element_count;
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
- | unsigned long result = model_p->_polymorphic_join_element_count;
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
- | char * str = model_p->#{StringElement.struct_name}_table + offset;
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
- | if(length_left + string_offset >= page_size()){
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
- | VALUE result = rb_ary_new();
382
- | rb_ary_push(result, UINT2NUM(length));
383
- | rb_ary_push(result, UINT2NUM(string_offset + page_offset * page_size()));
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
- | #{klass.struct_name} * struct_p = model_p->#{klass.struct_name}_table +
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\",UINT2NUM(struct_p->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
- | VALUE cClass = rb_define_class("#{model_struct_name(path).camelcase(true)}",
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
@@ -13,7 +13,9 @@ module Rod
13
13
  end
14
14
 
15
15
  def self.layout
16
- ' printf(" offset: %lu, index: %lu\n",sizeof(unsigned long), sizeof(unsigned long));' + "\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
- 'sizeof(unsigned long), sizeof(unsigned long), sizeof(unsigned long));' + "\n"
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 to_s.
56
- def to_s
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
- length, offset = database.set_string(value)
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\",sizeof(#{TYPE_MAPPING[options[:type]]}));"
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), sizeof(unsigned long), 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\",sizeof(unsigned long));"
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
- value = database.read_string(length, offset)
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
- return send("_#{name}_count",@rod_id)
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