oj 3.13.0 → 3.13.4

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/ext/oj/rails.c CHANGED
@@ -157,7 +157,7 @@ static void dump_struct(VALUE obj, int depth, Out out, bool as_ok) {
157
157
  assure_size(out, 2);
158
158
  *out->cur++ = '{';
159
159
  for (i = 0; i < cnt; i++) {
160
- volatile VALUE s = rb_sym_to_s(rb_ary_entry(ma, i));
160
+ volatile VALUE s = rb_sym2str(rb_ary_entry(ma, i));
161
161
 
162
162
  name = RSTRING_PTR(s);
163
163
  len = (int)RSTRING_LEN(s);
data/ext/oj/rxclass.c CHANGED
@@ -110,7 +110,7 @@ oj_rxclass_match(RxClass rc, const char *str, int len) {
110
110
  }
111
111
  } else if (len < (int)sizeof(buf)) {
112
112
  #if !IS_WINDOWS
113
- // string is not \0 terminated so copy and atempt a match
113
+ // string is not \0 terminated so copy and attempt a match
114
114
  memcpy(buf, str, len);
115
115
  buf[len] = '\0';
116
116
  if (0 == regexec(&rxc->rx, buf, 0, NULL, 0)) { // match
data/ext/oj/saj.c CHANGED
@@ -628,7 +628,7 @@ static void saj_parse(VALUE handler, char *json) {
628
628
  * @param [IO|String] io IO Object to read from
629
629
  * @deprecated The sc_parse() method along with the ScHandler is the preferred
630
630
  * callback parser. It is slightly faster and handles streams while the
631
- * saj_parse() methos requires a complete read before parsing.
631
+ * saj_parse() method requires a complete read before parsing.
632
632
  * @see sc_parse
633
633
  */
634
634
  VALUE
data/ext/oj/saj2.c CHANGED
@@ -158,7 +158,7 @@ static void add_str(ojParser p) {
158
158
  const char * str = buf_str(&p->buf);
159
159
  size_t len = buf_len(&p->buf);
160
160
 
161
- if (d->cache_str <= len) {
161
+ if (d->cache_str < len) {
162
162
  rstr = cache_intern(d->str_cache, str, len);
163
163
  } else {
164
164
  rstr = rb_utf8_str_new(str, len);
@@ -172,7 +172,7 @@ static void add_str_key(ojParser p) {
172
172
  const char * str = buf_str(&p->buf);
173
173
  size_t len = buf_len(&p->buf);
174
174
 
175
- if (d->cache_str <= len) {
175
+ if (d->cache_str < len) {
176
176
  rstr = cache_intern(d->str_cache, str, len);
177
177
  } else {
178
178
  rstr = rb_utf8_str_new(str, len);
@@ -182,8 +182,9 @@ static void add_str_key(ojParser p) {
182
182
 
183
183
  static void reset(ojParser p) {
184
184
  Funcs end = p->funcs + 3;
185
+ Funcs f;
185
186
 
186
- for (Funcs f = p->funcs; f < end; f++) {
187
+ for (f = p->funcs; f < end; f++) {
187
188
  f->add_null = noop;
188
189
  f->add_true = noop;
189
190
  f->add_false = noop;
@@ -312,13 +313,14 @@ static void mark(ojParser p) {
312
313
  return;
313
314
  }
314
315
  Delegate d = (Delegate)p->ctx;
316
+ VALUE *kp;
315
317
 
316
318
  cache_mark(d->str_cache);
317
319
  if (Qnil != d->handler) {
318
320
  rb_gc_mark(d->handler);
319
321
  }
320
322
  if (!d->cache_keys) {
321
- for (VALUE *kp = d->keys; kp < d->tail; kp++) {
323
+ for (kp = d->keys; kp < d->tail; kp++) {
322
324
  rb_gc_mark(*kp);
323
325
  }
324
326
  }
@@ -334,7 +336,7 @@ void oj_set_parser_saj(ojParser p) {
334
336
  d->klen = 256;
335
337
  d->keys = ALLOC_N(VALUE, d->klen);
336
338
  d->tail = d->keys;
337
- d->str_cache = cache_create(0, form_str, true);
339
+ d->str_cache = cache_create(0, form_str, true, false);
338
340
 
339
341
  p->ctx = (void *)d;
340
342
  reset(p);
data/ext/oj/sparse.c CHANGED
@@ -494,7 +494,7 @@ static void read_num(ParseInfo pi) {
494
494
  if ('.' == c) {
495
495
  c = reader_get(&pi->rd);
496
496
  // A trailing . is not a valid decimal but if encountered allow it
497
- // except when mimicing the JSON gem.
497
+ // except when mimicking the JSON gem.
498
498
  if (CompatMode == pi->options.mode) {
499
499
  if (c < '0' || '9' < c) {
500
500
  oj_set_error_at(pi, oj_parse_error_class, __FILE__, __LINE__, "not a number");
@@ -67,7 +67,7 @@ static VALUE buffer_size_sym = Qundef;
67
67
  * should be and also a hint on when to flush.
68
68
  *
69
69
  * - *io* [_IO_] stream to write to
70
- * - *options* [_Hash_] formating options
70
+ * - *options* [_Hash_] formatting options
71
71
  */
72
72
  static VALUE stream_writer_new(int argc, VALUE *argv, VALUE self) {
73
73
  StreamWriterType type = STREAM_IO;
data/ext/oj/strict.c CHANGED
@@ -37,8 +37,8 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
37
37
  } else {
38
38
  rkey = rb_str_new(parent->key, parent->klen);
39
39
  rkey = oj_encode(rkey);
40
+ OBJ_FREEZE(rkey);
40
41
  }
41
- OBJ_FREEZE(rkey);
42
42
  return rkey;
43
43
  }
44
44
  if (Yes == pi->options.sym_key) {
@@ -46,7 +46,6 @@ VALUE oj_calc_hash_key(ParseInfo pi, Val parent) {
46
46
  } else {
47
47
  rkey = oj_str_intern(parent->key, parent->klen);
48
48
  }
49
- OBJ_FREEZE(rkey);
50
49
  return rkey;
51
50
  }
52
51
 
@@ -248,7 +248,7 @@ static void str_writer_free(void *ptr) {
248
248
  * should be.
249
249
  *
250
250
  * - *io* [_IO_] stream to write to
251
- * - *options* [_Hash_] formating options
251
+ * - *options* [_Hash_] formatting options
252
252
  */
253
253
  static VALUE str_writer_new(int argc, VALUE *argv, VALUE self) {
254
254
  StrWriter sw = ALLOC(struct _strWriter);
@@ -466,7 +466,7 @@ static VALUE str_writer_as_json(VALUE self) {
466
466
  * by pushing values into the document. Pushing an array or an object will
467
467
  * create that element in the JSON document and subsequent pushes will add the
468
468
  * elements to that array or object until a pop() is called. When complete
469
- * calling to_s() will return the JSON document. Note tha calling to_s() before
469
+ * calling to_s() will return the JSON document. Note that calling to_s() before
470
470
  * construction is complete will return the document in it's current state.
471
471
  */
472
472
  void oj_string_writer_init() {
data/ext/oj/usual.c CHANGED
@@ -77,6 +77,7 @@ typedef struct _delegate {
77
77
  char * create_id;
78
78
  uint8_t create_id_len;
79
79
  uint8_t cache_str;
80
+ uint8_t cache_xrate;
80
81
  uint8_t miss_class;
81
82
  bool cache_keys;
82
83
  bool ignore_json_create;
@@ -100,7 +101,6 @@ static VALUE form_str(const char *str, size_t len) {
100
101
  }
101
102
 
102
103
  static VALUE form_sym(const char *str, size_t len) {
103
- // return ID2SYM(rb_intern3(str, len, oj_utf8_encoding));
104
104
  return rb_str_intern(rb_utf8_str_new(str, len));
105
105
  }
106
106
 
@@ -323,6 +323,7 @@ static void open_array_key(ojParser p) {
323
323
  }
324
324
 
325
325
  static void close_object(ojParser p) {
326
+ VALUE * vp;
326
327
  Delegate d = (Delegate)p->ctx;
327
328
 
328
329
  d->ctail--;
@@ -333,7 +334,7 @@ static void close_object(ojParser p) {
333
334
  volatile VALUE obj = rb_hash_new();
334
335
 
335
336
  #if HAVE_RB_HASH_BULK_INSERT
336
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
337
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
337
338
  *vp = d->get_key(p, kp);
338
339
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
339
340
  xfree(kp->key);
@@ -341,7 +342,7 @@ static void close_object(ojParser p) {
341
342
  }
342
343
  rb_hash_bulk_insert(d->vtail - head, head, obj);
343
344
  #else
344
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
345
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
345
346
  rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
346
347
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
347
348
  xfree(kp->key);
@@ -355,6 +356,7 @@ static void close_object(ojParser p) {
355
356
  }
356
357
 
357
358
  static void close_object_class(ojParser p) {
359
+ VALUE * vp;
358
360
  Delegate d = (Delegate)p->ctx;
359
361
 
360
362
  d->ctail--;
@@ -364,7 +366,7 @@ static void close_object_class(ojParser p) {
364
366
  VALUE * head = d->vhead + c->vi + 1;
365
367
  volatile VALUE obj = rb_class_new_instance(0, NULL, d->hash_class);
366
368
 
367
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
369
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
368
370
  rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
369
371
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
370
372
  xfree(kp->key);
@@ -377,6 +379,7 @@ static void close_object_class(ojParser p) {
377
379
  }
378
380
 
379
381
  static void close_object_create(ojParser p) {
382
+ VALUE * vp;
380
383
  Delegate d = (Delegate)p->ctx;
381
384
 
382
385
  d->ctail--;
@@ -391,7 +394,7 @@ static void close_object_create(ojParser p) {
391
394
  if (Qnil == d->hash_class) {
392
395
  obj = rb_hash_new();
393
396
  #if HAVE_RB_HASH_BULK_INSERT
394
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
397
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
395
398
  *vp = d->get_key(p, kp);
396
399
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
397
400
  xfree(kp->key);
@@ -399,7 +402,7 @@ static void close_object_create(ojParser p) {
399
402
  }
400
403
  rb_hash_bulk_insert(d->vtail - head, head, obj);
401
404
  #else
402
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
405
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
403
406
  rb_hash_aset(obj, d->get_key(p, kp), *(vp + 1));
404
407
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
405
408
  xfree(kp->key);
@@ -408,7 +411,7 @@ static void close_object_create(ojParser p) {
408
411
  #endif
409
412
  } else {
410
413
  obj = rb_class_new_instance(0, NULL, d->hash_class);
411
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
414
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
412
415
  rb_funcall(obj, hset_id, 2, d->get_key(p, kp), *(vp + 1));
413
416
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
414
417
  xfree(kp->key);
@@ -423,7 +426,7 @@ static void close_object_create(ojParser p) {
423
426
  volatile VALUE arg = rb_hash_new();
424
427
 
425
428
  #if HAVE_RB_HASH_BULK_INSERT
426
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
429
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
427
430
  *vp = d->get_key(p, kp);
428
431
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
429
432
  xfree(kp->key);
@@ -431,7 +434,7 @@ static void close_object_create(ojParser p) {
431
434
  }
432
435
  rb_hash_bulk_insert(d->vtail - head, head, arg);
433
436
  #else
434
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
437
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
435
438
  rb_hash_aset(arg, d->get_key(p, kp), *(vp + 1));
436
439
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
437
440
  xfree(kp->key);
@@ -441,7 +444,7 @@ static void close_object_create(ojParser p) {
441
444
  obj = rb_funcall(clas, oj_json_create_id, 1, arg);
442
445
  } else {
443
446
  obj = rb_class_new_instance(0, NULL, clas);
444
- for (VALUE *vp = head; kp < d->ktail; kp++, vp += 2) {
447
+ for (vp = head; kp < d->ktail; kp++, vp += 2) {
445
448
  rb_ivar_set(obj, get_attr_id(p, kp), *(vp + 1));
446
449
  if (sizeof(kp->buf) - 1 < (size_t)kp->len) {
447
450
  xfree(kp->key);
@@ -468,13 +471,14 @@ static void close_array(ojParser p) {
468
471
  }
469
472
 
470
473
  static void close_array_class(ojParser p) {
474
+ VALUE * vp;
471
475
  Delegate d = (Delegate)p->ctx;
472
476
 
473
477
  d->ctail--;
474
478
  VALUE * head = d->vhead + d->ctail->vi + 1;
475
479
  volatile VALUE a = rb_class_new_instance(0, NULL, d->array_class);
476
480
 
477
- for (VALUE *vp = head; vp < d->vtail; vp++) {
481
+ for (vp = head; vp < d->vtail; vp++) {
478
482
  rb_funcall(a, ltlt_id, 1, *vp);
479
483
  }
480
484
  d->vtail = head;
@@ -682,9 +686,10 @@ static void mark(ojParser p) {
682
686
  return;
683
687
  }
684
688
  Delegate d = (Delegate)p->ctx;
689
+ VALUE * vp;
685
690
 
686
691
  if (NULL == d) {
687
- return;
692
+ return;
688
693
  }
689
694
  cache_mark(d->str_cache);
690
695
  if (NULL != d->sym_cache) {
@@ -693,7 +698,7 @@ static void mark(ojParser p) {
693
698
  if (NULL != d->class_cache) {
694
699
  cache_mark(d->class_cache);
695
700
  }
696
- for (VALUE *vp = d->vhead; vp < d->vtail; vp++) {
701
+ for (vp = d->vhead; vp < d->vtail; vp++) {
697
702
  if (Qundef != *vp) {
698
703
  rb_gc_mark(*vp);
699
704
  }
@@ -787,6 +792,30 @@ static VALUE opt_cache_strings_set(ojParser p, VALUE value) {
787
792
  return INT2NUM((int)d->cache_str);
788
793
  }
789
794
 
795
+ static VALUE opt_cache_expunge(ojParser p, VALUE value) {
796
+ Delegate d = (Delegate)p->ctx;
797
+
798
+ return INT2NUM((int)d->cache_xrate);
799
+ }
800
+
801
+ static VALUE opt_cache_expunge_set(ojParser p, VALUE value) {
802
+ Delegate d = (Delegate)p->ctx;
803
+ int rate = NUM2INT(value);
804
+
805
+ if (rate < 0) {
806
+ rate = 0;
807
+ } else if (3 < rate) {
808
+ rate = 3;
809
+ }
810
+ d->cache_xrate = (uint8_t)rate;
811
+ cache_set_expunge_rate(d->str_cache, rate);
812
+ cache_set_expunge_rate(d->attr_cache, rate);
813
+ if (NULL != d->sym_cache) {
814
+ cache_set_expunge_rate(d->sym_cache, rate);
815
+ }
816
+ return INT2NUM((int)rate);
817
+ }
818
+
790
819
  static VALUE opt_capacity(ojParser p, VALUE value) {
791
820
  Delegate d = (Delegate)p->ctx;
792
821
 
@@ -825,11 +854,7 @@ static VALUE opt_class_cache_set(ojParser p, VALUE value) {
825
854
 
826
855
  if (Qtrue == value) {
827
856
  if (NULL == d->class_cache) {
828
- if (MISS_AUTO == d->miss_class) {
829
- d->class_cache = cache_create(0, form_class_auto, true);
830
- } else {
831
- d->class_cache = cache_create(0, form_class, false);
832
- }
857
+ d->class_cache = cache_create(0, form_class_auto, MISS_AUTO == d->miss_class, false);
833
858
  }
834
859
  } else if (NULL != d->class_cache) {
835
860
  cache_free(d->class_cache);
@@ -903,7 +928,7 @@ static VALUE opt_decimal_set(ojParser p, VALUE value) {
903
928
  switch (rb_type(value)) {
904
929
  case T_STRING: mode = RSTRING_PTR(value); break;
905
930
  case T_SYMBOL:
906
- s = rb_sym_to_s(value);
931
+ s = rb_sym2str(value);
907
932
  mode = RSTRING_PTR(s);
908
933
  break;
909
934
  default:
@@ -1020,7 +1045,7 @@ static VALUE opt_missing_class_set(ojParser p, VALUE value) {
1020
1045
  switch (rb_type(value)) {
1021
1046
  case T_STRING: mode = RSTRING_PTR(value); break;
1022
1047
  case T_SYMBOL:
1023
- s = rb_sym_to_s(value);
1048
+ s = rb_sym2str(value);
1024
1049
  mode = RSTRING_PTR(s);
1025
1050
  break;
1026
1051
  default:
@@ -1073,7 +1098,8 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1073
1098
  Delegate d = (Delegate)p->ctx;
1074
1099
 
1075
1100
  if (Qtrue == value) {
1076
- d->sym_cache = cache_create(0, form_sym, true);
1101
+ d->sym_cache = cache_create(0, form_sym, true, false);
1102
+ cache_set_expunge_rate(d->sym_cache, d->cache_xrate);
1077
1103
  d->key_cache = d->sym_cache;
1078
1104
  if (!d->cache_keys) {
1079
1105
  d->get_key = sym_key;
@@ -1091,13 +1117,16 @@ static VALUE opt_symbol_keys_set(ojParser p, VALUE value) {
1091
1117
  }
1092
1118
 
1093
1119
  static VALUE option(ojParser p, const char *key, VALUE value) {
1094
- struct opt opts[] = {
1120
+ struct opt *op;
1121
+ struct opt opts[] = {
1095
1122
  {.name = "array_class", .func = opt_array_class},
1096
1123
  {.name = "array_class=", .func = opt_array_class_set},
1097
1124
  {.name = "cache_keys", .func = opt_cache_keys},
1098
1125
  {.name = "cache_keys=", .func = opt_cache_keys_set},
1099
1126
  {.name = "cache_strings", .func = opt_cache_strings},
1100
1127
  {.name = "cache_strings=", .func = opt_cache_strings_set},
1128
+ {.name = "cache_expunge", .func = opt_cache_expunge},
1129
+ {.name = "cache_expunge=", .func = opt_cache_expunge_set},
1101
1130
  {.name = "capacity", .func = opt_capacity},
1102
1131
  {.name = "capacity=", .func = opt_capacity_set},
1103
1132
  {.name = "class_cache", .func = opt_class_cache},
@@ -1119,7 +1148,7 @@ static VALUE option(ojParser p, const char *key, VALUE value) {
1119
1148
  {.name = NULL},
1120
1149
  };
1121
1150
 
1122
- for (struct opt *op = opts; NULL != op->name; op++) {
1151
+ for (op = opts; NULL != op->name; op++) {
1123
1152
  if (0 == strcmp(key, op->name)) {
1124
1153
  return op->func(p, value);
1125
1154
  }
@@ -1157,6 +1186,7 @@ void oj_set_parser_usual(ojParser p) {
1157
1186
  d->create_id = NULL;
1158
1187
  d->create_id_len = 0;
1159
1188
  d->miss_class = MISS_IGNORE;
1189
+ d->cache_xrate = 1;
1160
1190
 
1161
1191
  Funcs f = &p->funcs[TOP_FUN];
1162
1192
  f->add_null = add_null;
@@ -1197,8 +1227,8 @@ void oj_set_parser_usual(ojParser p) {
1197
1227
  f->open_object = open_object_key;
1198
1228
  f->close_object = close_object;
1199
1229
 
1200
- d->str_cache = cache_create(0, form_str, true);
1201
- d->attr_cache = cache_create(0, form_attr, false);
1230
+ d->str_cache = cache_create(0, form_str, true, false);
1231
+ d->attr_cache = cache_create(0, form_attr, false, false);
1202
1232
  d->sym_cache = NULL;
1203
1233
  d->class_cache = NULL;
1204
1234
  d->key_cache = d->str_cache;
data/ext/oj/validate.c CHANGED
@@ -28,8 +28,9 @@ mark(ojParser p) {
28
28
  void oj_set_parser_validator(ojParser p) {
29
29
  p->ctx = NULL;
30
30
  Funcs end = p->funcs + 3;
31
+ Funcs f;
31
32
 
32
- for (Funcs f = p->funcs; f < end; f++) {
33
+ for (f = p->funcs; f < end; f++) {
33
34
  f->add_null = noop;
34
35
  f->add_true = noop;
35
36
  f->add_false = noop;
data/ext/oj/wab.c CHANGED
@@ -305,11 +305,14 @@ static VALUE calc_hash_key(ParseInfo pi, Val parent) {
305
305
  if (Yes == pi->options.cache_keys) {
306
306
  rkey = oj_sym_intern(parent->key, parent->klen);
307
307
  } else {
308
- rkey = rb_str_new(parent->key, parent->klen);
309
- rkey = oj_encode(rkey);
308
+ #if HAVE_RB_ENC_INTERNED_STR
309
+ rkey = rb_enc_interned_str(parent->key, parent->klen, oj_utf8_encoding);
310
+ #else
311
+ rkey = rb_utf8_str_new(parent->key, parent->klen);
310
312
  rkey = rb_str_intern(rkey);
313
+ OBJ_FREEZE(rkey);
314
+ #endif
311
315
  }
312
- OBJ_FREEZE(rkey);
313
316
  return rkey;
314
317
  }
315
318
 
data/lib/oj/error.rb CHANGED
@@ -16,7 +16,7 @@ module Oj
16
16
  # An Exception that is raised if a file fails to load.
17
17
  LoadError = Class.new(Error)
18
18
 
19
- # An Exception that is raised if there is a conflict with mimicing JSON
19
+ # An Exception that is raised if there is a conflict with mimicking JSON
20
20
  MimicError = Class.new(Error)
21
21
 
22
22
  end # Oj
data/lib/oj/state.rb CHANGED
@@ -1,7 +1,7 @@
1
1
 
2
2
  module JSON
3
3
  module Ext
4
- module Generator
4
+ module Generator
5
5
  unless defined?(::JSON::Ext::Generator::State)
6
6
  # This class exists for json gem compatibility only. While it can be
7
7
  # used as the options for other than compatibility a simple Hash is
@@ -44,11 +44,11 @@ module JSON
44
44
  def to_h()
45
45
  return @attrs.dup
46
46
  end
47
-
47
+
48
48
  def to_hash()
49
49
  return @attrs.dup
50
50
  end
51
-
51
+
52
52
  def allow_nan?()
53
53
  @attrs[:allow_nan]
54
54
  end
@@ -104,7 +104,7 @@ module JSON
104
104
  def has_key?(k)
105
105
  @attrs.has_key?(key.to_sym)
106
106
  end
107
-
107
+
108
108
  # Handles requests for Hash values. Others cause an Exception to be raised.
109
109
  # @param [Symbol|String] m method symbol
110
110
  # @return [Boolean] the value of the specified instance variable.
@@ -116,11 +116,12 @@ module JSON
116
116
  m = m.to_s[0..-2]
117
117
  m = m.to_sym
118
118
  return @attrs.store(m, args[0])
119
- else
119
+ end
120
+ if @attrs.has_key?(m.to_sym)
120
121
  raise ArgumentError.new("wrong number of arguments (#{args.size} for 0 with #{m}) to method #{m}") unless args.nil? or args.empty?
121
122
  return @attrs[m.to_sym]
122
- end
123
- raise NoMethodError.new("undefined method #{m}", m)
123
+ end
124
+ return @attrs.send(m, *args, &block)
124
125
  end
125
126
 
126
127
  end # State