i18nema 0.0.3 → 0.0.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/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
|