jsonnet 0.1.0 → 0.4.0

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.
@@ -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
  }