jsonnet 0.1.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,74 @@
1
+ #include <string.h>
2
+
3
+ #include <libjsonnet.h>
4
+ #include <ruby/ruby.h>
5
+ #include <ruby/encoding.h>
6
+
7
+ #include "ruby_jsonnet.h"
8
+
9
+ static ID id_message;
10
+
11
+ /*
12
+ * Indicates that the encoding of the given string is not allowed by
13
+ * the C++ implementation of Jsonnet.
14
+ */
15
+ static VALUE eUnsupportedEncodingError;
16
+
17
+ /**
18
+ * Asserts that the given string-like object is in an
19
+ * ASCII-compatible encoding.
20
+ *
21
+ * @param[in] str a String-like object
22
+ * @throw UnsupportedEncodingError on assertion failure.
23
+ */
24
+ rb_encoding *
25
+ rubyjsonnet_assert_asciicompat(VALUE str)
26
+ {
27
+ rb_encoding *enc = rb_enc_get(str);
28
+ if (!rb_enc_asciicompat(enc)) {
29
+ rb_raise(eUnsupportedEncodingError, "jsonnet encoding must be ASCII-compatible but got %s",
30
+ rb_enc_name(enc));
31
+ }
32
+ return enc;
33
+ }
34
+
35
+ /**
36
+ * Allocates a C string whose content is equal to \c str with jsonnet_realloc.
37
+ */
38
+ char *
39
+ rubyjsonnet_str_to_cstr(struct JsonnetVm *vm, VALUE str)
40
+ {
41
+ const char *const cstr = StringValueCStr(str);
42
+ char *const buf = jsonnet_realloc(vm, NULL, strlen(cstr));
43
+ strcpy(buf, cstr);
44
+ return buf;
45
+ }
46
+
47
+ /**
48
+ * @return a human readable string which contains the class name of the
49
+ * exception and its message. It might be nil on failure
50
+ */
51
+ VALUE
52
+ rubyjsonnet_format_exception(VALUE exc)
53
+ {
54
+ VALUE name = rb_class_name(rb_obj_class(exc));
55
+ VALUE msg = rb_funcall(exc, id_message, 0);
56
+ if (RB_TYPE_P(name, RUBY_T_STRING) && rb_str_strlen(name)) {
57
+ if (RB_TYPE_P(msg, RUBY_T_STRING) && rb_str_strlen(msg)) {
58
+ return rb_str_concat(rb_str_cat_cstr(name, " : "), msg);
59
+ } else {
60
+ return name;
61
+ }
62
+ } else if (RB_TYPE_P(msg, RUBY_T_STRING) && rb_str_strlen(msg)) {
63
+ return msg;
64
+ }
65
+ return Qnil;
66
+ }
67
+
68
+ void
69
+ rubyjsonnet_init_helpers(VALUE mJsonnet)
70
+ {
71
+ id_message = rb_intern("message");
72
+ eUnsupportedEncodingError =
73
+ rb_define_class_under(mJsonnet, "UnsupportedEncodingError", rb_eEncodingError);
74
+ }
@@ -1,127 +1,8 @@
1
- #include <string.h>
1
+ #include <libjsonnet.h>
2
2
  #include <ruby/ruby.h>
3
- #include <ruby/intern.h>
4
3
  #include <ruby/encoding.h>
5
- #include <libjsonnet.h>
6
4
 
7
- static ID id_call;
8
- static ID id_message;
9
-
10
- /*
11
- * Jsonnet evaluator
12
- */
13
- static VALUE cVM;
14
- static VALUE eEvaluationError;
15
- /**
16
- * Indicates that the encoding of the given string is not allowed by
17
- * the C++ implementation of Jsonnet.
18
- */
19
- static VALUE eUnsupportedEncodingError;
20
-
21
- struct jsonnet_vm_wrap {
22
- struct JsonnetVm *vm;
23
- VALUE callback;
24
- };
25
-
26
- static void vm_free(void *ptr);
27
- static void vm_mark(void *ptr);
28
-
29
- static const rb_data_type_t jsonnet_vm_type = {
30
- "JsonnetVm",
31
- {
32
- /* dmark = */ vm_mark,
33
- /* dfree = */ vm_free,
34
- /* dsize = */ 0,
35
- },
36
- /* parent = */ 0,
37
- /* data = */ 0,
38
- /* flags = */ RUBY_TYPED_FREE_IMMEDIATELY
39
- };
40
-
41
- /**
42
- * raises an EvaluationError whose message is \c msg.
43
- * @param[in] vm a JsonnetVM
44
- * @param[in] msg must be a NUL-terminated string returned by \c vm.
45
- * @return never returns
46
- * @throw EvaluationError
47
- */
48
- static void
49
- raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc)
50
- {
51
- VALUE ex = rb_exc_new3(eEvaluationError, rb_enc_str_new_cstr(msg, enc));
52
- jsonnet_realloc(vm, msg, 0);
53
- rb_exc_raise(ex);
54
- }
55
-
56
- /**
57
- * Returns a String whose contents is equal to \c json.
58
- * It automatically frees \c json just after constructing the return value.
59
- *
60
- * @param[in] vm a JsonnetVM
61
- * @param[in] json must be a NUL-terminated string returned by \c vm.
62
- * @return Ruby string equal to \c json.
63
- */
64
- static VALUE
65
- str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc)
66
- {
67
- VALUE str = rb_enc_str_new_cstr(json, enc);
68
- jsonnet_realloc(vm, json, 0);
69
- return str;
70
- }
71
-
72
- /**
73
- * Returns a Hash, whose keys are file names in the multi-mode of Jsonnet,
74
- * and whose values are corresponding JSON values.
75
- * It automatically frees \c json just after constructing the return value.
76
- *
77
- * @param[in] vm a JsonnetVM
78
- * @param[in] buf NUL-separated and double-NUL-terminated sequence of strings returned by \c vm.
79
- * @return Hash
80
- */
81
- static VALUE
82
- fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc)
83
- {
84
- VALUE fileset = rb_hash_new();
85
- char *ptr, *json;
86
- for (ptr = buf; *ptr; ptr = json + strlen(json)+1) {
87
- json = ptr + strlen(ptr) + 1;
88
- if (!*json) {
89
- VALUE ex = rb_exc_new3(
90
- eEvaluationError,
91
- rb_enc_sprintf(enc, "output file %s without body", ptr));
92
- jsonnet_realloc(vm, buf, 0);
93
- rb_exc_raise(ex);
94
- }
95
-
96
- rb_hash_aset(fileset, rb_enc_str_new_cstr(ptr, enc), rb_enc_str_new_cstr(json, enc));
97
- }
98
- jsonnet_realloc(vm, buf, 0);
99
- return fileset;
100
- }
101
-
102
- /**
103
- * Allocates a C string whose content is equal to \c str with jsonnet_realloc.
104
- */
105
- static char *
106
- str_jsonnet_cstr(struct JsonnetVm *vm, VALUE str)
107
- {
108
- const char *const cstr = StringValueCStr(str);
109
- char *const buf = jsonnet_realloc(vm, NULL, strlen(cstr));
110
- strcpy(buf, cstr);
111
- return buf;
112
- }
113
-
114
- static rb_encoding *
115
- enc_assert_asciicompat(VALUE str) {
116
- rb_encoding *enc = rb_enc_get(str);
117
- if (!rb_enc_asciicompat(enc)) {
118
- rb_raise(
119
- eUnsupportedEncodingError,
120
- "jsonnet encoding must be ASCII-compatible but got %s",
121
- rb_enc_name(enc));
122
- }
123
- return enc;
124
- }
5
+ #include "ruby_jsonnet.h"
125
6
 
126
7
  /*
127
8
  * call-seq:
@@ -135,246 +16,12 @@ jw_s_version(VALUE mod)
135
16
  return rb_usascii_str_new_cstr(jsonnet_version());
136
17
  }
137
18
 
138
- static VALUE
139
- vm_s_new(VALUE mod)
140
- {
141
- struct jsonnet_vm_wrap *vm;
142
- VALUE self = TypedData_Make_Struct(cVM, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
143
- vm->vm = jsonnet_make();
144
- vm->callback = Qnil;
145
- return self;
146
- }
147
-
148
- static void
149
- vm_free(void *ptr)
150
- {
151
- struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap*)ptr;
152
- jsonnet_destroy(vm->vm);
153
- REALLOC_N(vm, struct jsonnet_vm_wrap, 0);
154
- }
155
-
156
- static void
157
- vm_mark(void *ptr)
158
- {
159
- struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap*)ptr;
160
- rb_gc_mark(vm->callback);
161
- }
162
-
163
- static VALUE
164
- vm_evaluate_file(VALUE self, VALUE fname, VALUE encoding, VALUE multi_p)
165
- {
166
- struct jsonnet_vm_wrap *vm;
167
- int error;
168
- char *result;
169
- rb_encoding *const enc = rb_to_encoding(encoding);
170
-
171
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
172
- FilePathValue(fname);
173
- if (RTEST(multi_p)) {
174
- result = jsonnet_evaluate_file_multi(vm->vm, StringValueCStr(fname), &error);
175
- }
176
- else {
177
- result = jsonnet_evaluate_file(vm->vm, StringValueCStr(fname), &error);
178
- }
179
-
180
- if (error) {
181
- raise_eval_error(vm->vm, result, rb_enc_get(fname));
182
- }
183
- return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
184
- }
185
-
186
- static VALUE
187
- vm_evaluate(VALUE self, VALUE snippet, VALUE fname, VALUE multi_p)
188
- {
189
- struct jsonnet_vm_wrap *vm;
190
- int error;
191
- char *result;
192
-
193
- rb_encoding *enc = enc_assert_asciicompat(StringValue(snippet));
194
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
195
- FilePathValue(fname);
196
- if (RTEST(multi_p)) {
197
- result = jsonnet_evaluate_snippet_multi(
198
- vm->vm,
199
- StringValueCStr(fname), StringValueCStr(snippet), &error);
200
- }
201
- else {
202
- result = jsonnet_evaluate_snippet(
203
- vm->vm,
204
- StringValueCStr(fname), StringValueCStr(snippet), &error);
205
- }
206
-
207
- if (error) {
208
- raise_eval_error(vm->vm, result, rb_enc_get(fname));
209
- }
210
- return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
211
- }
212
-
213
- static VALUE
214
- import_callback_thunk0(VALUE args)
215
- {
216
- VALUE callback = rb_ary_entry(args, 0);
217
- return rb_funcall(callback, id_call, 2, rb_ary_entry(args, 1), rb_ary_entry(args, 2));
218
- }
219
-
220
- static char *
221
- import_callback_thunk(void *ctx, const char *base, const char *rel, char **found_here, int *success)
222
- {
223
- struct jsonnet_vm_wrap *const vm = (struct jsonnet_vm_wrap*)ctx;
224
- int state;
225
- VALUE result, args;
226
-
227
- args = rb_ary_tmp_new(3);
228
- rb_ary_push(args, vm->callback);
229
- rb_ary_push(args, rb_enc_str_new_cstr(base, rb_filesystem_encoding()));
230
- rb_ary_push(args, rb_enc_str_new_cstr(rel, rb_filesystem_encoding()));
231
- result = rb_protect(import_callback_thunk0, args, &state);
232
-
233
- if (state) {
234
- VALUE err = rb_errinfo();
235
- VALUE msg, name;
236
-
237
- rb_set_errinfo(Qnil);
238
- name = rb_class_name(rb_obj_class(err));
239
- msg = rb_funcall(err, id_message, 0);
240
- if (rb_str_strlen(name)) {
241
- if (rb_str_strlen(msg)) {
242
- msg = rb_str_concat(rb_str_cat_cstr(name, " : "), msg);
243
- } else {
244
- msg = name;
245
- }
246
- } else if (!rb_str_strlen(msg)) {
247
- msg = rb_sprintf("cannot import %s from %s", rel, base);
248
- }
249
- *success = 0;
250
- return str_jsonnet_cstr(vm->vm, msg);
251
- }
252
-
253
- result = rb_Array(result);
254
- *success = 1;
255
- *found_here = str_jsonnet_cstr(vm->vm, rb_ary_entry(result, 1));
256
- return str_jsonnet_cstr(vm->vm, rb_ary_entry(result, 0));
257
- }
258
-
259
- /**
260
- * Sets a custom way to resolve "import" expression.
261
- * @param [#call] callback receives two parameters and returns two values.
262
- * The first parameter "base" is a base directory to resolve
263
- * "rel" from.
264
- * The second parameter "rel" is an absolute or a relative
265
- * path to the file to import.
266
- * The first return value is the content of the imported file.
267
- * The second return value is the resolved path of the imported file.
268
- */
269
- static VALUE
270
- vm_set_import_callback(VALUE self, VALUE callback)
271
- {
272
- struct jsonnet_vm_wrap *vm;
273
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
274
-
275
- vm->callback = callback;
276
- jsonnet_import_callback(vm->vm, import_callback_thunk, vm);
277
- return callback;
278
- }
279
-
280
- /*
281
- * Binds an external variable to a value.
282
- * @param [String] key name of the variable
283
- * @param [String] val the value
284
- */
285
- static VALUE
286
- vm_ext_var(VALUE self, VALUE key, VALUE val)
287
- {
288
- struct jsonnet_vm_wrap *vm;
289
-
290
- enc_assert_asciicompat(StringValue(key));
291
- enc_assert_asciicompat(StringValue(val));
292
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
293
- jsonnet_ext_var(vm->vm, StringValueCStr(key), StringValueCStr(val));
294
- return Qnil;
295
- }
296
-
297
- static VALUE
298
- vm_set_max_stack(VALUE self, VALUE val)
299
- {
300
- struct jsonnet_vm_wrap *vm;
301
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
302
- jsonnet_max_stack(vm->vm, NUM2UINT(val));
303
- return Qnil;
304
- }
305
-
306
- static VALUE
307
- vm_set_gc_min_objects(VALUE self, VALUE val)
308
- {
309
- struct jsonnet_vm_wrap *vm;
310
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
311
- jsonnet_gc_min_objects(vm->vm, NUM2UINT(val));
312
- return Qnil;
313
- }
314
-
315
- static VALUE
316
- vm_set_gc_growth_trigger(VALUE self, VALUE val)
317
- {
318
- struct jsonnet_vm_wrap *vm;
319
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
320
- jsonnet_gc_growth_trigger(vm->vm, NUM2DBL(val));
321
- return Qnil;
322
- }
323
-
324
- /*
325
- * Let #evalutae and #evaluate_file return a raw String instead of JSON-encoded string if val is true
326
- * @param [Boolean] val
327
- */
328
- static VALUE
329
- vm_set_string_output(VALUE self, VALUE val)
330
- {
331
- struct jsonnet_vm_wrap *vm;
332
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
333
- jsonnet_string_output(vm->vm, RTEST(val));
334
- return Qnil;
335
- }
336
-
337
- static VALUE
338
- vm_set_max_trace(VALUE self, VALUE val)
339
- {
340
- struct jsonnet_vm_wrap *vm;
341
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
342
- jsonnet_max_trace(vm->vm, NUM2UINT(val));
343
- return Qnil;
344
- }
345
-
346
- static VALUE
347
- vm_set_debug_ast(VALUE self, VALUE val)
348
- {
349
- struct jsonnet_vm_wrap *vm;
350
- TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
351
- jsonnet_debug_ast(vm->vm, RTEST(val));
352
- return Qnil;
353
- }
354
-
355
19
  void
356
20
  Init_jsonnet_wrap(void)
357
21
  {
358
- id_call = rb_intern("call");
359
- id_message = rb_intern("message");
360
-
361
22
  VALUE mJsonnet = rb_define_module("Jsonnet");
362
23
  rb_define_singleton_method(mJsonnet, "libversion", jw_s_version, 0);
363
24
 
364
- cVM = rb_define_class_under(mJsonnet, "VM", rb_cData);
365
- rb_define_singleton_method(cVM, "new", vm_s_new, 0);
366
- rb_define_private_method(cVM, "eval_file", vm_evaluate_file, 3);
367
- rb_define_private_method(cVM, "eval_snippet", vm_evaluate, 3);
368
- rb_define_method(cVM, "ext_var", vm_ext_var, 2);
369
- rb_define_method(cVM, "max_stack=", vm_set_max_stack, 1);
370
- rb_define_method(cVM, "gc_min_objects=", vm_set_gc_min_objects, 1);
371
- rb_define_method(cVM, "gc_growth_trigger=", vm_set_gc_growth_trigger, 1);
372
- rb_define_method(cVM, "string_output=", vm_set_string_output, 1);
373
- rb_define_method(cVM, "max_trace=", vm_set_max_trace, 1);
374
- rb_define_method(cVM, "debug_ast=", vm_set_debug_ast, 1);
375
- rb_define_method(cVM, "import_callback=", vm_set_import_callback, 1);
376
-
377
- eEvaluationError = rb_define_class_under(mJsonnet, "EvaluationError", rb_eRuntimeError);
378
- eUnsupportedEncodingError =
379
- rb_define_class_under(mJsonnet, "UnsupportedEncodingError", rb_eEncodingError);
25
+ rubyjsonnet_init_helpers(mJsonnet);
26
+ rubyjsonnet_init_vm(mJsonnet);
380
27
  }