i18nema 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- data/ext/i18nema/i18nema.c +109 -33
- data/test/i18nema_test.rb +15 -6
- metadata +2 -2
data/ext/i18nema/i18nema.c
CHANGED
@@ -12,13 +12,20 @@ struct i_key_value;
|
|
12
12
|
static VALUE array_to_rarray(struct i_object *array);
|
13
13
|
static VALUE hash_to_rhash(struct i_object *hash);
|
14
14
|
static void merge_hash(struct i_object *hash, struct i_object *other_hash);
|
15
|
-
static void delete_hash(struct i_key_value **hash);
|
16
|
-
static void delete_object(struct i_object *object);
|
15
|
+
static void delete_hash(struct i_key_value **hash, int delete_child_objects);
|
16
|
+
static void delete_object(struct i_object *object, int delete_child_objects);
|
17
17
|
|
18
18
|
enum i_object_type {
|
19
|
+
i_type_none,
|
19
20
|
i_type_string,
|
20
21
|
i_type_array,
|
21
|
-
i_type_hash
|
22
|
+
i_type_hash,
|
23
|
+
i_type_int,
|
24
|
+
i_type_float,
|
25
|
+
i_type_symbol,
|
26
|
+
i_type_true,
|
27
|
+
i_type_false,
|
28
|
+
i_type_null
|
22
29
|
};
|
23
30
|
|
24
31
|
union i_object_data {
|
@@ -42,11 +49,17 @@ typedef struct i_key_value
|
|
42
49
|
} i_key_value_t;
|
43
50
|
|
44
51
|
static int current_translation_count = 0;
|
45
|
-
static ID
|
46
|
-
|
52
|
+
static ID s_init_translations,
|
53
|
+
s_to_f,
|
54
|
+
s_to_s,
|
55
|
+
s_to_sym;
|
56
|
+
static i_object_t i_object_null,
|
57
|
+
i_object_true,
|
58
|
+
i_object_false;
|
47
59
|
|
48
60
|
static VALUE
|
49
61
|
i_object_to_robject(i_object_t *object) {
|
62
|
+
VALUE s;
|
50
63
|
if (object == NULL)
|
51
64
|
return Qnil;
|
52
65
|
switch (object->type) {
|
@@ -56,8 +69,20 @@ i_object_to_robject(i_object_t *object) {
|
|
56
69
|
return array_to_rarray(object);
|
57
70
|
case i_type_hash:
|
58
71
|
return hash_to_rhash(object);
|
72
|
+
case i_type_int:
|
73
|
+
return rb_cstr2inum(object->data.string, 10);
|
74
|
+
case i_type_float:
|
75
|
+
s = rb_str_new(object->data.string, object->size);
|
76
|
+
return rb_funcall(s, s_to_f, 0);
|
77
|
+
case i_type_symbol:
|
78
|
+
return ID2SYM(rb_intern(object->data.string));
|
79
|
+
case i_type_true:
|
80
|
+
return Qtrue;
|
81
|
+
case i_type_false:
|
82
|
+
return Qfalse;
|
83
|
+
default:
|
84
|
+
return Qnil;
|
59
85
|
}
|
60
|
-
return Qnil;
|
61
86
|
}
|
62
87
|
|
63
88
|
static VALUE
|
@@ -118,49 +143,60 @@ direct_lookup(int argc, VALUE *argv, VALUE self)
|
|
118
143
|
}
|
119
144
|
|
120
145
|
static void
|
121
|
-
empty_object(i_object_t *object)
|
146
|
+
empty_object(i_object_t *object, int delete_child_objects)
|
122
147
|
{
|
123
148
|
if (object == NULL)
|
124
149
|
return;
|
125
150
|
|
126
151
|
switch (object->type) {
|
127
|
-
case i_type_string:
|
128
|
-
xfree(object->data.string);
|
129
|
-
break;
|
130
152
|
case i_type_array:
|
131
|
-
|
132
|
-
|
153
|
+
if (delete_child_objects) {
|
154
|
+
for (unsigned long i = 0; i < object->size; i++)
|
155
|
+
delete_object(object->data.array[i], 1);
|
156
|
+
}
|
133
157
|
xfree(object->data.array);
|
134
158
|
break;
|
135
159
|
case i_type_hash:
|
136
|
-
delete_hash(&object->data.hash);
|
160
|
+
delete_hash(&object->data.hash, delete_child_objects);
|
161
|
+
break;
|
162
|
+
case i_type_none:
|
163
|
+
break;
|
164
|
+
default:
|
165
|
+
xfree(object->data.string);
|
137
166
|
break;
|
138
167
|
}
|
139
168
|
}
|
140
169
|
|
141
170
|
static void
|
142
|
-
|
171
|
+
delete_object_r(i_object_t *object)
|
143
172
|
{
|
144
|
-
|
145
|
-
|
173
|
+
delete_object(object, 1);
|
174
|
+
}
|
175
|
+
|
176
|
+
static void
|
177
|
+
delete_object(i_object_t *object, int delete_child_objects)
|
178
|
+
{
|
179
|
+
empty_object(object, delete_child_objects);
|
180
|
+
if (object->type != i_type_null && object->type != i_type_true && object->type != i_type_false)
|
181
|
+
xfree(object);
|
146
182
|
}
|
147
183
|
|
148
184
|
static void
|
149
185
|
delete_key_value(i_key_value_t *kv, int delete_value)
|
150
186
|
{
|
151
187
|
if (delete_value)
|
152
|
-
delete_object(kv->value);
|
188
|
+
delete_object(kv->value, 1);
|
153
189
|
xfree(kv->key);
|
154
190
|
xfree(kv);
|
155
191
|
}
|
156
192
|
|
157
193
|
static void
|
158
|
-
delete_hash(i_key_value_t **hash)
|
194
|
+
delete_hash(i_key_value_t **hash, int delete_child_objects)
|
159
195
|
{
|
160
196
|
i_key_value_t *kv, *tmp;
|
161
197
|
HASH_ITER(hh, *hash, kv, tmp) {
|
162
198
|
HASH_DEL(*hash, kv);
|
163
|
-
delete_key_value(kv,
|
199
|
+
delete_key_value(kv, delete_child_objects);
|
164
200
|
}
|
165
201
|
}
|
166
202
|
|
@@ -191,12 +227,16 @@ merge_hash(i_object_t *hash, i_object_t *other_hash)
|
|
191
227
|
HASH_DEL(other_hash->data.hash, kv);
|
192
228
|
add_key_value(&hash->data.hash, kv);
|
193
229
|
}
|
194
|
-
delete_object(other_hash);
|
230
|
+
delete_object(other_hash, 1);
|
195
231
|
}
|
196
232
|
|
197
233
|
static int
|
198
234
|
delete_syck_st_entry(char *key, char *value, char *arg)
|
199
235
|
{
|
236
|
+
i_object_t *object = (i_object_t *)value;
|
237
|
+
// key object whose string we have yoinked into a kv
|
238
|
+
if (object->type == i_type_none)
|
239
|
+
delete_object(object, 1);
|
200
240
|
return ST_DELETE;
|
201
241
|
}
|
202
242
|
|
@@ -204,7 +244,7 @@ static int
|
|
204
244
|
delete_syck_object(char *key, char *value, char *arg)
|
205
245
|
{
|
206
246
|
i_object_t *object = (i_object_t *)value;
|
207
|
-
delete_object(object);
|
247
|
+
delete_object(object, 0); // objects are in the syck symbol table, thus we don't want to double-free
|
208
248
|
return ST_DELETE;
|
209
249
|
}
|
210
250
|
|
@@ -230,23 +270,52 @@ handle_syck_badanchor(SyckParser *parser, char *anchor)
|
|
230
270
|
return NULL;
|
231
271
|
}
|
232
272
|
|
273
|
+
static i_object_t*
|
274
|
+
new_string_object(char *str, long len)
|
275
|
+
{
|
276
|
+
i_object_t *object = ALLOC(i_object_t);
|
277
|
+
object->type = i_type_string;
|
278
|
+
object->size = len;
|
279
|
+
object->data.string = xmalloc(len + 1);
|
280
|
+
strncpy(object->data.string, str, len);
|
281
|
+
object->data.string[len] = '\0';
|
282
|
+
return object;
|
283
|
+
}
|
284
|
+
|
233
285
|
static SYMID
|
234
286
|
handle_syck_node(SyckParser *parser, SyckNode *node)
|
235
287
|
{
|
236
288
|
i_object_t *result;
|
237
|
-
result = ALLOC(i_object_t);
|
238
289
|
SYMID oid;
|
239
290
|
|
240
291
|
switch (node->kind) {
|
241
292
|
case syck_str_kind:
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
293
|
+
if (node->type_id == NULL) {
|
294
|
+
result = new_string_object(node->data.str->ptr, node->data.str->len);
|
295
|
+
} else if (strcmp(node->type_id, "null") == 0) {
|
296
|
+
result = &i_object_null;
|
297
|
+
} else if (strcmp(node->type_id, "bool#yes") == 0) {
|
298
|
+
result = &i_object_true;
|
299
|
+
} else if (strcmp(node->type_id, "bool#no") == 0) {
|
300
|
+
result = &i_object_false;
|
301
|
+
} else if (strcmp(node->type_id, "int") == 0) {
|
302
|
+
syck_str_blow_away_commas(node);
|
303
|
+
result = new_string_object(node->data.str->ptr, node->data.str->len);
|
304
|
+
result->type = i_type_int;
|
305
|
+
} else if (strcmp(node->type_id, "float#fix") == 0 || strcmp(node->type_id, "float#exp") == 0) {
|
306
|
+
syck_str_blow_away_commas(node);
|
307
|
+
result = new_string_object(node->data.str->ptr, node->data.str->len);
|
308
|
+
result->type = i_type_float;
|
309
|
+
} else if (node->data.str->style == scalar_plain && node->data.str->len > 1 && strncmp(node->data.str->ptr, ":", 1) == 0) {
|
310
|
+
result = new_string_object(node->data.str->ptr + 1, node->data.str->len - 1);
|
311
|
+
result->type = i_type_symbol;
|
312
|
+
} else {
|
313
|
+
// legit strings, and everything else get the string treatment (binary, int#hex, timestamp, etc.)
|
314
|
+
result = new_string_object(node->data.str->ptr, node->data.str->len);
|
315
|
+
}
|
248
316
|
break;
|
249
317
|
case syck_seq_kind:
|
318
|
+
result = ALLOC(i_object_t);
|
250
319
|
result->type = i_type_array;
|
251
320
|
result->size = node->data.list->idx;
|
252
321
|
result->data.array = ALLOC_N(i_object_t*, node->data.list->idx);
|
@@ -261,6 +330,7 @@ handle_syck_node(SyckParser *parser, SyckNode *node)
|
|
261
330
|
}
|
262
331
|
break;
|
263
332
|
case syck_map_kind:
|
333
|
+
result = ALLOC(i_object_t);
|
264
334
|
result->type = i_type_hash;
|
265
335
|
result->data.hash = NULL;
|
266
336
|
for (long i = 0; i < node->data.pairs->idx; i++) {
|
@@ -274,7 +344,7 @@ handle_syck_node(SyckParser *parser, SyckNode *node)
|
|
274
344
|
i_key_value_t *kv;
|
275
345
|
kv = ALLOC(i_key_value_t);
|
276
346
|
kv->key = key->data.string;
|
277
|
-
|
347
|
+
key->type = i_type_none; // so we know to free this node in delete_syck_st_entry
|
278
348
|
kv->value = value;
|
279
349
|
if (value->type == i_type_string)
|
280
350
|
current_translation_count++;
|
@@ -317,7 +387,7 @@ load_yml_string(VALUE self, VALUE yml)
|
|
317
387
|
st_foreach(parser->syms, delete_syck_st_entry, 0);
|
318
388
|
syck_free_parser(parser);
|
319
389
|
if (new_root_object == NULL || new_root_object->type != i_type_hash) {
|
320
|
-
delete_object(new_root_object);
|
390
|
+
delete_object(new_root_object, 1);
|
321
391
|
rb_raise(I18nemaBackendLoadError, "root yml node is not a hash");
|
322
392
|
}
|
323
393
|
merge_hash(root_object, new_root_object);
|
@@ -362,7 +432,7 @@ static VALUE
|
|
362
432
|
reload(VALUE self)
|
363
433
|
{
|
364
434
|
i_object_t *root_object = root_object_get(self);
|
365
|
-
empty_object(root_object);
|
435
|
+
empty_object(root_object, 1);
|
366
436
|
rb_iv_set(self, "@initialized", Qfalse);
|
367
437
|
root_object = NULL;
|
368
438
|
return Qtrue;
|
@@ -375,7 +445,7 @@ initialize(VALUE self)
|
|
375
445
|
i_object_t *root_object = ALLOC(i_object_t);
|
376
446
|
root_object->type = i_type_hash;
|
377
447
|
root_object->data.hash = NULL;
|
378
|
-
translations = Data_Wrap_Struct(I18nemaBackend, 0,
|
448
|
+
translations = Data_Wrap_Struct(I18nemaBackend, 0, delete_object_r, root_object);
|
379
449
|
rb_iv_set(self, "@translations", translations);
|
380
450
|
return self;
|
381
451
|
}
|
@@ -387,8 +457,14 @@ Init_i18nema()
|
|
387
457
|
I18nemaBackend = rb_define_class_under(I18nema, "Backend", rb_cObject);
|
388
458
|
I18nemaBackendLoadError = rb_define_class_under(I18nemaBackend, "LoadError", rb_eStandardError);
|
389
459
|
|
390
|
-
s_to_s = rb_intern("to_s");
|
391
460
|
s_init_translations = rb_intern("init_translations");
|
461
|
+
s_to_f = rb_intern("to_f");
|
462
|
+
s_to_s = rb_intern("to_s");
|
463
|
+
s_to_sym = rb_intern("to_sym");
|
464
|
+
|
465
|
+
i_object_null.type = i_type_null;
|
466
|
+
i_object_true.type = i_type_true;
|
467
|
+
i_object_false.type = i_type_false;
|
392
468
|
|
393
469
|
rb_define_method(I18nemaBackend, "initialize", initialize, 0);
|
394
470
|
rb_define_method(I18nemaBackend, "load_yml_string", load_yml_string, 1);
|
data/test/i18nema_test.rb
CHANGED
@@ -10,7 +10,16 @@ class I18nemaTest < Test::Unit::TestCase
|
|
10
10
|
baz: %w{
|
11
11
|
asdf
|
12
12
|
qwerty
|
13
|
-
}
|
13
|
+
},
|
14
|
+
stuff: [
|
15
|
+
true,
|
16
|
+
true,
|
17
|
+
false,
|
18
|
+
nil,
|
19
|
+
1,
|
20
|
+
1.1,
|
21
|
+
:foo
|
22
|
+
]
|
14
23
|
}
|
15
24
|
@backend = I18nema::Backend.new
|
16
25
|
@backend.store_translations :en, @data
|
@@ -63,11 +72,11 @@ class I18nemaTest < Test::Unit::TestCase
|
|
63
72
|
# i_object_t as the root node, causing delete_object to asplode when
|
64
73
|
# it tries to free a garbage pointer
|
65
74
|
#
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
75
|
+
exception = assert_raise(I18nema::Backend::LoadError) {
|
76
|
+
backend.load_yml_string("en:\n foo: \"lol\"\n\tbar: notabs!")
|
77
|
+
}
|
78
|
+
assert_match(/syntax error/, exception.message)
|
79
|
+
assert_equal({}, backend.direct_lookup)
|
71
80
|
|
72
81
|
exception = assert_raise(I18nema::Backend::LoadError) {
|
73
82
|
backend.load_yml_string("en:\n &a [*a]")
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: i18nema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2013-05-
|
12
|
+
date: 2013-05-30 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: i18n
|