jsonnet 0.0.1 → 0.0.2
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.
- checksums.yaml +4 -4
- data/ext/jsonnet/jsonnet.c +305 -27
- data/lib/jsonnet.rb +1 -0
- data/lib/jsonnet/version.rb +1 -1
- data/lib/jsonnet/vm.rb +37 -0
- data/test/test_vm.rb +216 -10
- metadata +4 -6
- data/test/error.jsonnet +0 -5
- data/test/example.jsonnet +0 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b3ba7719f8a07cc8385aef8ffc4b2e1b21924f33
|
4
|
+
data.tar.gz: ca340bf28f5f521aef9b5a7f2e71613e277f7fd4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ba5847ad581b28bde58ee1b14f96e6b5624d72d96125ccf82aabc9543aff3280f6c39f0ba69ba2d4ae7484517e7fd3971d563e2868c8a01bef78adce74d89aab
|
7
|
+
data.tar.gz: 9519135c4c6f81cb94dca96ac22a4fb401839af5e8b6d573e7cd6d7d33a1b000bc92f3a907048a93ee251b15cef9a0727470c4655129d69360b8acf9149fac22
|
data/ext/jsonnet/jsonnet.c
CHANGED
@@ -1,13 +1,30 @@
|
|
1
|
+
#include <string.h>
|
1
2
|
#include <ruby/ruby.h>
|
3
|
+
#include <ruby/intern.h>
|
4
|
+
#include <ruby/encoding.h>
|
2
5
|
#include <libjsonnet.h>
|
3
6
|
|
7
|
+
static ID id_call;
|
8
|
+
static ID id_message;
|
9
|
+
|
4
10
|
/*
|
5
11
|
* Jsonnet evaluator
|
6
12
|
*/
|
7
13
|
static VALUE cVM;
|
8
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
|
+
};
|
9
25
|
|
10
26
|
static void vm_free(void *ptr);
|
27
|
+
|
11
28
|
static const rb_data_type_t jsonnet_vm_type = {
|
12
29
|
"JsonnetVm",
|
13
30
|
{
|
@@ -20,6 +37,91 @@ static const rb_data_type_t jsonnet_vm_type = {
|
|
20
37
|
/* flags = */ RUBY_TYPED_FREE_IMMEDIATELY
|
21
38
|
};
|
22
39
|
|
40
|
+
/**
|
41
|
+
* raises an EvaluationError whose message is \c msg.
|
42
|
+
* @param[in] vm a JsonnetVM
|
43
|
+
* @param[in] msg must be a NUL-terminated string returned by \c vm.
|
44
|
+
* @return never returns
|
45
|
+
* @throw EvaluationError
|
46
|
+
*/
|
47
|
+
static void
|
48
|
+
raise_eval_error(struct JsonnetVm *vm, char *msg, rb_encoding *enc)
|
49
|
+
{
|
50
|
+
VALUE ex = rb_exc_new3(eEvaluationError, rb_enc_str_new_cstr(msg, enc));
|
51
|
+
jsonnet_realloc(vm, msg, 0);
|
52
|
+
rb_exc_raise(ex);
|
53
|
+
}
|
54
|
+
|
55
|
+
/**
|
56
|
+
* Returns a String whose contents is equal to \c json.
|
57
|
+
* It automatically frees \c json just after constructing the return value.
|
58
|
+
*
|
59
|
+
* @param[in] vm a JsonnetVM
|
60
|
+
* @param[in] json must be a NUL-terminated string returned by \c vm.
|
61
|
+
* @return Ruby string equal to \c json.
|
62
|
+
*/
|
63
|
+
static VALUE
|
64
|
+
str_new_json(struct JsonnetVm *vm, char *json, rb_encoding *enc)
|
65
|
+
{
|
66
|
+
VALUE str = rb_enc_str_new_cstr(json, enc);
|
67
|
+
jsonnet_realloc(vm, json, 0);
|
68
|
+
return str;
|
69
|
+
}
|
70
|
+
|
71
|
+
/**
|
72
|
+
* Returns a Hash, whose keys are file names in the multi-mode of Jsonnet,
|
73
|
+
* and whose values are corresponding JSON values.
|
74
|
+
* It automatically frees \c json just after constructing the return value.
|
75
|
+
*
|
76
|
+
* @param[in] vm a JsonnetVM
|
77
|
+
* @param[in] buf NUL-separated and double-NUL-terminated sequence of strings returned by \c vm.
|
78
|
+
* @return Hash
|
79
|
+
*/
|
80
|
+
static VALUE
|
81
|
+
fileset_new(struct JsonnetVm *vm, char *buf, rb_encoding *enc)
|
82
|
+
{
|
83
|
+
VALUE fileset = rb_hash_new();
|
84
|
+
char *ptr, *json;
|
85
|
+
for (ptr = buf; *ptr; ptr = json + strlen(json)+1) {
|
86
|
+
json = ptr + strlen(ptr) + 1;
|
87
|
+
if (!*json) {
|
88
|
+
VALUE ex = rb_exc_new3(
|
89
|
+
eEvaluationError,
|
90
|
+
rb_enc_sprintf(enc, "output file %s without body", ptr));
|
91
|
+
jsonnet_realloc(vm, buf, 0);
|
92
|
+
rb_exc_raise(ex);
|
93
|
+
}
|
94
|
+
|
95
|
+
rb_hash_aset(fileset, rb_enc_str_new_cstr(ptr, enc), rb_enc_str_new_cstr(json, enc));
|
96
|
+
}
|
97
|
+
jsonnet_realloc(vm, buf, 0);
|
98
|
+
return fileset;
|
99
|
+
}
|
100
|
+
|
101
|
+
/**
|
102
|
+
* Allocates a C string whose content is equal to \c str with jsonnet_realloc.
|
103
|
+
*/
|
104
|
+
static char *
|
105
|
+
str_jsonnet_cstr(struct JsonnetVm *vm, VALUE str)
|
106
|
+
{
|
107
|
+
const char *const cstr = StringValueCStr(str);
|
108
|
+
char *const buf = jsonnet_realloc(vm, NULL, strlen(cstr));
|
109
|
+
strcpy(buf, cstr);
|
110
|
+
return buf;
|
111
|
+
}
|
112
|
+
|
113
|
+
static rb_encoding *
|
114
|
+
enc_assert_asciicompat(VALUE str) {
|
115
|
+
rb_encoding *enc = rb_enc_get(str);
|
116
|
+
if (!rb_enc_asciicompat(enc)) {
|
117
|
+
rb_raise(
|
118
|
+
eUnsupportedEncodingError,
|
119
|
+
"jsonnet encoding must be ASCII-compatible but got %s",
|
120
|
+
rb_enc_name(enc));
|
121
|
+
}
|
122
|
+
return enc;
|
123
|
+
}
|
124
|
+
|
23
125
|
/*
|
24
126
|
* call-seq:
|
25
127
|
* Jsonnet.version -> String
|
@@ -27,66 +129,242 @@ static const rb_data_type_t jsonnet_vm_type = {
|
|
27
129
|
* Returns the version of the underlying C++ implementation of Jsonnet.
|
28
130
|
*/
|
29
131
|
static VALUE
|
30
|
-
jw_s_version(VALUE mod)
|
132
|
+
jw_s_version(VALUE mod)
|
133
|
+
{
|
31
134
|
return rb_usascii_str_new_cstr(jsonnet_version());
|
32
135
|
}
|
33
136
|
|
34
137
|
static VALUE
|
35
138
|
vm_s_new(VALUE mod) {
|
36
|
-
struct
|
37
|
-
|
139
|
+
struct jsonnet_vm_wrap *vm;
|
140
|
+
VALUE self = TypedData_Make_Struct(cVM, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
141
|
+
vm->vm = jsonnet_make();
|
142
|
+
vm->callback = Qnil;
|
143
|
+
return self;
|
38
144
|
}
|
39
145
|
|
40
146
|
static void
|
41
147
|
vm_free(void *ptr) {
|
42
|
-
|
148
|
+
struct jsonnet_vm_wrap *vm = (struct jsonnet_vm_wrap*)ptr;
|
149
|
+
jsonnet_destroy(vm->vm);
|
150
|
+
REALLOC_N(vm, struct jsonnet_vm_wrap, 0);
|
43
151
|
}
|
44
152
|
|
45
153
|
static VALUE
|
46
|
-
vm_evaluate_file(VALUE self, VALUE fname)
|
47
|
-
|
154
|
+
vm_evaluate_file(VALUE self, VALUE fname, VALUE encoding, VALUE multi_p)
|
155
|
+
{
|
156
|
+
struct jsonnet_vm_wrap *vm;
|
48
157
|
int error;
|
49
|
-
char*
|
158
|
+
char *result;
|
159
|
+
rb_encoding *const enc = rb_to_encoding(encoding);
|
50
160
|
|
51
|
-
TypedData_Get_Struct(self, struct
|
161
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
52
162
|
FilePathValue(fname);
|
53
|
-
|
163
|
+
if (RTEST(multi_p)) {
|
164
|
+
result = jsonnet_evaluate_file_multi(vm->vm, StringValueCStr(fname), &error);
|
165
|
+
}
|
166
|
+
else {
|
167
|
+
result = jsonnet_evaluate_file(vm->vm, StringValueCStr(fname), &error);
|
168
|
+
}
|
169
|
+
|
54
170
|
if (error) {
|
55
|
-
|
171
|
+
raise_eval_error(vm->vm, result, rb_enc_get(fname));
|
56
172
|
}
|
57
|
-
return
|
173
|
+
return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
|
58
174
|
}
|
59
175
|
|
60
176
|
static VALUE
|
61
|
-
vm_evaluate(
|
62
|
-
|
177
|
+
vm_evaluate(VALUE self, VALUE snippet, VALUE fname, VALUE multi_p)
|
178
|
+
{
|
179
|
+
struct jsonnet_vm_wrap *vm;
|
63
180
|
int error;
|
64
|
-
char*
|
65
|
-
VALUE snippet, fname = Qnil;
|
181
|
+
char *result;
|
66
182
|
|
67
|
-
|
183
|
+
rb_encoding *enc = enc_assert_asciicompat(StringValue(snippet));
|
184
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
185
|
+
FilePathValue(fname);
|
186
|
+
if (RTEST(multi_p)) {
|
187
|
+
result = jsonnet_evaluate_snippet_multi(
|
188
|
+
vm->vm,
|
189
|
+
StringValueCStr(fname), StringValueCStr(snippet), &error);
|
190
|
+
}
|
191
|
+
else {
|
192
|
+
result = jsonnet_evaluate_snippet(
|
193
|
+
vm->vm,
|
194
|
+
StringValueCStr(fname), StringValueCStr(snippet), &error);
|
195
|
+
}
|
68
196
|
|
69
|
-
TypedData_Get_Struct(self, struct JsonnetVm, &jsonnet_vm_type, vm);
|
70
|
-
result = jsonnet_evaluate_snippet(
|
71
|
-
vm,
|
72
|
-
fname == Qnil ? "(jsonnet)" : (FilePathValue(fname), StringValueCStr(fname)),
|
73
|
-
StringValueCStr(snippet),
|
74
|
-
&error);
|
75
197
|
if (error) {
|
76
|
-
|
198
|
+
raise_eval_error(vm->vm, result, rb_enc_get(fname));
|
199
|
+
}
|
200
|
+
return RTEST(multi_p) ? fileset_new(vm->vm, result, enc) : str_new_json(vm->vm, result, enc);
|
201
|
+
}
|
202
|
+
|
203
|
+
static VALUE
|
204
|
+
import_callback_thunk0(VALUE args)
|
205
|
+
{
|
206
|
+
VALUE callback = rb_ary_entry(args, 0);
|
207
|
+
return rb_funcall(callback, id_call, 2, rb_ary_entry(args, 1), rb_ary_entry(args, 2));
|
208
|
+
}
|
209
|
+
|
210
|
+
static char *
|
211
|
+
import_callback_thunk(void *ctx, const char *base, const char *rel, char **found_here, int *success)
|
212
|
+
{
|
213
|
+
struct jsonnet_vm_wrap *const vm = (struct jsonnet_vm_wrap*)ctx;
|
214
|
+
int state;
|
215
|
+
VALUE result, args;
|
216
|
+
|
217
|
+
args = rb_ary_tmp_new(3);
|
218
|
+
rb_ary_push(args, vm->callback);
|
219
|
+
rb_ary_push(args, rb_enc_str_new_cstr(base, rb_filesystem_encoding()));
|
220
|
+
rb_ary_push(args, rb_enc_str_new_cstr(rel, rb_filesystem_encoding()));
|
221
|
+
result = rb_protect(import_callback_thunk0, args, &state);
|
222
|
+
|
223
|
+
if (state) {
|
224
|
+
VALUE err = rb_errinfo();
|
225
|
+
VALUE msg, name;
|
226
|
+
|
227
|
+
rb_set_errinfo(Qnil);
|
228
|
+
name = rb_class_name(rb_obj_class(err));
|
229
|
+
msg = rb_funcall(err, id_message, 0);
|
230
|
+
if (rb_str_strlen(name)) {
|
231
|
+
if (rb_str_strlen(msg)) {
|
232
|
+
msg = rb_str_concat(rb_str_cat_cstr(name, " : "), msg);
|
233
|
+
} else {
|
234
|
+
msg = name;
|
235
|
+
}
|
236
|
+
} else if (!rb_str_strlen(msg)) {
|
237
|
+
msg = rb_sprintf("cannot import %s from %s", rel, base);
|
238
|
+
}
|
239
|
+
*success = 0;
|
240
|
+
return str_jsonnet_cstr(vm->vm, msg);
|
77
241
|
}
|
78
|
-
|
242
|
+
|
243
|
+
result = rb_Array(result);
|
244
|
+
*success = 1;
|
245
|
+
*found_here = str_jsonnet_cstr(vm->vm, rb_ary_entry(result, 1));
|
246
|
+
return str_jsonnet_cstr(vm->vm, rb_ary_entry(result, 0));
|
247
|
+
}
|
248
|
+
|
249
|
+
/**
|
250
|
+
* Sets a custom way to resolve "import" expression.
|
251
|
+
* @param [#call] callback receives two parameters and returns two values.
|
252
|
+
* The first parameter "base" is a base directory to resolve
|
253
|
+
* "rel" from.
|
254
|
+
* The second parameter "rel" is an absolute or a relative
|
255
|
+
* path to the file to import.
|
256
|
+
* The first return value is the content of the imported file.
|
257
|
+
* The second return value is the resolved path of the imported file.
|
258
|
+
*/
|
259
|
+
static VALUE
|
260
|
+
vm_set_import_callback(VALUE self, VALUE callback)
|
261
|
+
{
|
262
|
+
struct jsonnet_vm_wrap *vm;
|
263
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
264
|
+
|
265
|
+
vm->callback = callback;
|
266
|
+
jsonnet_import_callback(vm->vm, import_callback_thunk, vm);
|
267
|
+
return callback;
|
268
|
+
}
|
269
|
+
|
270
|
+
/*
|
271
|
+
* Binds an external variable to a value.
|
272
|
+
* @param [String] key name of the variable
|
273
|
+
* @param [String] val the value
|
274
|
+
*/
|
275
|
+
static VALUE
|
276
|
+
vm_ext_var(VALUE self, VALUE key, VALUE val)
|
277
|
+
{
|
278
|
+
struct jsonnet_vm_wrap *vm;
|
279
|
+
|
280
|
+
enc_assert_asciicompat(StringValue(key));
|
281
|
+
enc_assert_asciicompat(StringValue(val));
|
282
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
283
|
+
jsonnet_ext_var(vm->vm, StringValueCStr(key), StringValueCStr(val));
|
284
|
+
return Qnil;
|
285
|
+
}
|
286
|
+
|
287
|
+
static VALUE
|
288
|
+
vm_set_max_stack(VALUE self, VALUE val)
|
289
|
+
{
|
290
|
+
struct jsonnet_vm_wrap *vm;
|
291
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
292
|
+
jsonnet_max_stack(vm->vm, NUM2UINT(val));
|
293
|
+
return Qnil;
|
294
|
+
}
|
295
|
+
|
296
|
+
static VALUE
|
297
|
+
vm_set_gc_min_objects(VALUE self, VALUE val)
|
298
|
+
{
|
299
|
+
struct jsonnet_vm_wrap *vm;
|
300
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
301
|
+
jsonnet_gc_min_objects(vm->vm, NUM2UINT(val));
|
302
|
+
return Qnil;
|
303
|
+
}
|
304
|
+
|
305
|
+
static VALUE
|
306
|
+
vm_set_gc_growth_trigger(VALUE self, VALUE val)
|
307
|
+
{
|
308
|
+
struct jsonnet_vm_wrap *vm;
|
309
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
310
|
+
jsonnet_gc_growth_trigger(vm->vm, NUM2DBL(val));
|
311
|
+
return Qnil;
|
312
|
+
}
|
313
|
+
|
314
|
+
/*
|
315
|
+
* Let #evalutae and #evaluate_file return a raw String instead of JSON-encoded string if val is true
|
316
|
+
* @param [Boolean] val
|
317
|
+
*/
|
318
|
+
static VALUE
|
319
|
+
vm_set_string_output(VALUE self, VALUE val)
|
320
|
+
{
|
321
|
+
struct jsonnet_vm_wrap *vm;
|
322
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
323
|
+
jsonnet_string_output(vm->vm, RTEST(val));
|
324
|
+
return Qnil;
|
325
|
+
}
|
326
|
+
|
327
|
+
static VALUE
|
328
|
+
vm_set_max_trace(VALUE self, VALUE val)
|
329
|
+
{
|
330
|
+
struct jsonnet_vm_wrap *vm;
|
331
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
332
|
+
jsonnet_max_trace(vm->vm, NUM2UINT(val));
|
333
|
+
return Qnil;
|
334
|
+
}
|
335
|
+
|
336
|
+
static VALUE
|
337
|
+
vm_set_debug_ast(VALUE self, VALUE val)
|
338
|
+
{
|
339
|
+
struct jsonnet_vm_wrap *vm;
|
340
|
+
TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
|
341
|
+
jsonnet_debug_ast(vm->vm, RTEST(val));
|
342
|
+
return Qnil;
|
79
343
|
}
|
80
344
|
|
81
345
|
void
|
82
|
-
Init_jsonnet_wrap(void)
|
346
|
+
Init_jsonnet_wrap(void)
|
347
|
+
{
|
348
|
+
id_call = rb_intern("call");
|
349
|
+
id_message = rb_intern("message");
|
350
|
+
|
83
351
|
VALUE mJsonnet = rb_define_module("Jsonnet");
|
84
352
|
rb_define_singleton_method(mJsonnet, "libversion", jw_s_version, 0);
|
85
353
|
|
86
354
|
cVM = rb_define_class_under(mJsonnet, "VM", rb_cData);
|
87
355
|
rb_define_singleton_method(cVM, "new", vm_s_new, 0);
|
88
|
-
|
89
|
-
|
356
|
+
rb_define_private_method(cVM, "eval_file", vm_evaluate_file, 3);
|
357
|
+
rb_define_private_method(cVM, "eval_snippet", vm_evaluate, 3);
|
358
|
+
rb_define_method(cVM, "ext_var", vm_ext_var, 2);
|
359
|
+
rb_define_method(cVM, "max_stack=", vm_set_max_stack, 1);
|
360
|
+
rb_define_method(cVM, "gc_min_objects=", vm_set_gc_min_objects, 1);
|
361
|
+
rb_define_method(cVM, "gc_growth_trigger=", vm_set_gc_growth_trigger, 1);
|
362
|
+
rb_define_method(cVM, "string_output=", vm_set_string_output, 1);
|
363
|
+
rb_define_method(cVM, "max_trace=", vm_set_max_trace, 1);
|
364
|
+
rb_define_method(cVM, "debug_ast=", vm_set_debug_ast, 1);
|
365
|
+
rb_define_method(cVM, "import_callback=", vm_set_import_callback, 1);
|
90
366
|
|
91
367
|
eEvaluationError = rb_define_class_under(mJsonnet, "EvaluationError", rb_eRuntimeError);
|
368
|
+
eUnsupportedEncodingError =
|
369
|
+
rb_define_class_under(mJsonnet, "UnsupportedEncodingError", rb_eEncodingError);
|
92
370
|
}
|
data/lib/jsonnet.rb
CHANGED
data/lib/jsonnet/version.rb
CHANGED
data/lib/jsonnet/vm.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
module Jsonnet
|
2
|
+
class VM
|
3
|
+
##
|
4
|
+
# Evaluates Jsonnet source.
|
5
|
+
#
|
6
|
+
# @param [String] jsonnet Jsonnet source string.
|
7
|
+
# Must be encoded in an ASCII-compatible encoding.
|
8
|
+
# @param [String] filename filename of the source. Used in stacktrace.
|
9
|
+
# @param [Boolean] multi enables multi-mode
|
10
|
+
# @return [String] a JSON representation of the evaluation result
|
11
|
+
# @raise [EvaluationError] raised when the evaluation results an error.
|
12
|
+
# @raise [UnsupportedEncodingError] raised when the encoding of jsonnet
|
13
|
+
# is not ASCII-compatible.
|
14
|
+
# @note It is recommended to encode the source string in UTF-8 because
|
15
|
+
# Jsonnet expects it is ASCII-compatible, the result JSON string
|
16
|
+
# shall be UTF-{8,16,32} according to RFC 7159 thus the only
|
17
|
+
# intersection between the requirements is UTF-8.
|
18
|
+
def evaluate(jsonnet, filename: "(jsonnet)", multi: false)
|
19
|
+
eval_snippet(jsonnet, filename, multi)
|
20
|
+
end
|
21
|
+
|
22
|
+
##
|
23
|
+
# Evaluates Jsonnet file.
|
24
|
+
#
|
25
|
+
# @param [String] filename filename of a Jsonnet source file.
|
26
|
+
# @param [Boolean] multi enables multi-mode
|
27
|
+
# @return [String] a JSON representation of the evaluation result
|
28
|
+
# @raise [EvaluationError] raised when the evaluation results an error.
|
29
|
+
# @note It is recommended to encode the source file in UTF-8 because
|
30
|
+
# Jsonnet expects it is ASCII-compatible, the result JSON string
|
31
|
+
# shall be UTF-{8,16,32} according to RFC 7159 thus the only
|
32
|
+
# intersection between the requirements is UTF-8.
|
33
|
+
def evaluate_file(filename, encoding: Encoding.default_external, multi: false)
|
34
|
+
eval_file(filename, encoding, multi)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
data/test/test_vm.rb
CHANGED
@@ -1,28 +1,63 @@
|
|
1
|
+
# -*- coding: UTF-8 -*-
|
1
2
|
require 'jsonnet'
|
2
3
|
|
3
4
|
require 'json'
|
5
|
+
require 'tempfile'
|
4
6
|
require 'test/unit'
|
5
7
|
|
6
8
|
class TestVM < Test::Unit::TestCase
|
7
9
|
test 'Jsonnet::VM#evaluate_file evaluates file' do
|
8
10
|
vm = Jsonnet::VM.new
|
9
|
-
|
10
|
-
|
11
|
-
|
11
|
+
with_example_file(%<
|
12
|
+
local myvar = 1;
|
13
|
+
{
|
14
|
+
["foo" + myvar]: myvar,
|
15
|
+
}
|
16
|
+
>) {|fname|
|
17
|
+
result = vm.evaluate_file(fname)
|
18
|
+
assert_equal JSON.parse(<<-EOS), JSON.parse(result)
|
12
19
|
{"foo1": 1}
|
13
|
-
|
20
|
+
EOS
|
21
|
+
}
|
14
22
|
end
|
15
23
|
|
16
24
|
test 'Jsonnet::VM#evaluate_file raises an EvaluationError on error' do
|
17
25
|
vm = Jsonnet::VM.new
|
18
|
-
|
19
|
-
|
26
|
+
with_example_file(%<
|
27
|
+
{
|
28
|
+
// unbound variable
|
29
|
+
["foo" + myvar]: myvar,
|
30
|
+
}
|
31
|
+
>) {|fname|
|
32
|
+
assert_raise(Jsonnet::EvaluationError) do
|
33
|
+
vm.evaluate_file(fname)
|
34
|
+
end
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
test "Jsonnet::VM#evaluate_file returns the same encoding as source" do
|
39
|
+
vm = Jsonnet::VM.new
|
40
|
+
with_example_file(%Q{ ["テスト"] }.encode(Encoding::EUC_JP)) {|fname|
|
41
|
+
result = vm.evaluate_file(fname, encoding: Encoding::EUC_JP)
|
42
|
+
assert_equal Encoding::EUC_JP, result.encoding
|
43
|
+
}
|
44
|
+
end
|
45
|
+
|
46
|
+
test "Jsonnet::VM#evaluate_file raises an error in the encoding of filename" do
|
47
|
+
vm = Jsonnet::VM.new
|
48
|
+
begin
|
49
|
+
with_example_file(%q{ ["unterminated string }) {|fname|
|
50
|
+
vm.evaluate_file(fname.encode(Encoding::SJIS))
|
51
|
+
}
|
52
|
+
rescue Jsonnet::EvaluationError => e
|
53
|
+
assert_equal Encoding::SJIS, e.message.encoding
|
20
54
|
end
|
21
55
|
end
|
22
56
|
|
57
|
+
|
23
58
|
test 'Jsonnet::VM#evaluate evaluates snippet' do
|
24
59
|
vm = Jsonnet::VM.new
|
25
|
-
result = vm.evaluate(<<-EOS, 'example.snippet')
|
60
|
+
result = vm.evaluate(<<-EOS, filename: 'example.snippet')
|
26
61
|
local myvar = 1;
|
27
62
|
{
|
28
63
|
["foo" + myvar]: myvar,
|
@@ -51,7 +86,7 @@ class TestVM < Test::Unit::TestCase
|
|
51
86
|
test 'Jsonnet::VM#evaluate raises an EvaluationError on error' do
|
52
87
|
vm = Jsonnet::VM.new
|
53
88
|
assert_raise(Jsonnet::EvaluationError) do
|
54
|
-
vm.evaluate(<<-EOS, 'example.snippet')
|
89
|
+
vm.evaluate(<<-EOS, filename: 'example.snippet')
|
55
90
|
{
|
56
91
|
// unbound variable
|
57
92
|
["foo" + myvar]: myvar,
|
@@ -60,9 +95,180 @@ class TestVM < Test::Unit::TestCase
|
|
60
95
|
end
|
61
96
|
end
|
62
97
|
|
98
|
+
test "Jsonnet::VM#evaluate returns the same encoding as source" do
|
99
|
+
vm = Jsonnet::VM.new
|
100
|
+
result = vm.evaluate(%Q{ ["テスト"] }.encode(Encoding::EUC_JP))
|
101
|
+
assert_equal Encoding::EUC_JP, result.encoding
|
102
|
+
end
|
103
|
+
|
104
|
+
test "Jsonnet::VM#evaluate raises an error in the encoding of filename" do
|
105
|
+
vm = Jsonnet::VM.new
|
106
|
+
begin
|
107
|
+
vm.evaluate(%Q{ ["unterminated string }, filename: "テスト.json".encode(Encoding::SJIS))
|
108
|
+
rescue Jsonnet::EvaluationError => e
|
109
|
+
assert_equal Encoding::SJIS, e.message.encoding
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
test "Jsonnet::VM#ext_var binds a variable" do
|
114
|
+
vm = Jsonnet::VM.new
|
115
|
+
vm.ext_var("var1", "foo")
|
116
|
+
result = vm.evaluate('[std.extVar("var1")]')
|
117
|
+
assert_equal JSON.parse('["foo"]'), JSON.parse(result)
|
118
|
+
end
|
119
|
+
|
120
|
+
test 'Jsonnet::VM#evaluate returns a JSON per filename on multi mode' do
|
121
|
+
vm = Jsonnet::VM.new
|
122
|
+
[
|
123
|
+
[ "{}", {} ],
|
124
|
+
[
|
125
|
+
%<
|
126
|
+
local myvar = 1;
|
127
|
+
{ ["foo" + myvar]: [myvar] }
|
128
|
+
>,
|
129
|
+
{
|
130
|
+
'foo1' => [1],
|
131
|
+
}
|
132
|
+
],
|
133
|
+
[
|
134
|
+
%<
|
135
|
+
local myvar = 1;
|
136
|
+
{
|
137
|
+
["foo" + myvar]: [myvar],
|
138
|
+
["bar" + myvar]: {
|
139
|
+
["baz" + (myvar+1)]: myvar+1,
|
140
|
+
},
|
141
|
+
}
|
142
|
+
>,
|
143
|
+
{
|
144
|
+
'foo1' => [1],
|
145
|
+
'bar1' => {'baz2' => 2},
|
146
|
+
}
|
147
|
+
],
|
148
|
+
].each do |jsonnet, expected|
|
149
|
+
result = vm.evaluate(jsonnet, multi: true)
|
150
|
+
assert_equal expected.keys.sort, result.keys.sort
|
151
|
+
expected.each do |fname, value|
|
152
|
+
assert_not_nil result[fname]
|
153
|
+
assert_equal value, JSON.parse(result[fname])
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
test 'Jsonnet::VM#evaluate_file returns a JSON per filename on multi mode' do
|
159
|
+
vm = Jsonnet::VM.new
|
160
|
+
[
|
161
|
+
[ "{}", {} ],
|
162
|
+
[
|
163
|
+
%<
|
164
|
+
local myvar = 1;
|
165
|
+
{ ["foo" + myvar]: [myvar] }
|
166
|
+
>,
|
167
|
+
{
|
168
|
+
'foo1' => [1],
|
169
|
+
}
|
170
|
+
],
|
171
|
+
[
|
172
|
+
%<
|
173
|
+
local myvar = 1;
|
174
|
+
{
|
175
|
+
["foo" + myvar]: [myvar],
|
176
|
+
["bar" + myvar]: {
|
177
|
+
["baz" + (myvar+1)]: myvar+1,
|
178
|
+
},
|
179
|
+
}
|
180
|
+
>,
|
181
|
+
{
|
182
|
+
'foo1' => [1],
|
183
|
+
'bar1' => {'baz2' => 2},
|
184
|
+
}
|
185
|
+
],
|
186
|
+
].each do |jsonnet, expected|
|
187
|
+
with_example_file(jsonnet) {|fname|
|
188
|
+
result = vm.evaluate_file(fname, multi: true)
|
189
|
+
assert_equal expected.keys.sort, result.keys.sort
|
190
|
+
expected.each do |fname, value|
|
191
|
+
assert_not_nil result[fname]
|
192
|
+
assert_equal value, JSON.parse(result[fname])
|
193
|
+
end
|
194
|
+
}
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
test "Jsonnet::VM responds to max_stack=" do
|
199
|
+
Jsonnet::VM.new.max_stack = 1
|
200
|
+
end
|
201
|
+
|
202
|
+
test "Jsonnet::VM responds to gc_min_objects=" do
|
203
|
+
Jsonnet::VM.new.gc_min_objects = 1
|
204
|
+
end
|
205
|
+
|
206
|
+
test "Jsonnet::VM responds to gc_growth_trigger=" do
|
207
|
+
Jsonnet::VM.new.gc_growth_trigger = 1.5
|
208
|
+
end
|
209
|
+
|
210
|
+
test "Jsonnet::VM responds to max_trace=" do
|
211
|
+
Jsonnet::VM.new.max_trace = 1
|
212
|
+
end
|
213
|
+
|
214
|
+
test "Jsonnet::VM responds to debug_ast=" do
|
215
|
+
Jsonnet::VM.new.debug_ast = true
|
216
|
+
end
|
217
|
+
|
218
|
+
test "Jsonnet::VM#string_output lets the VM output a raw string" do
|
219
|
+
vm = Jsonnet::VM.new
|
220
|
+
vm.string_output = true
|
221
|
+
assert_equal "foo\n", vm.evaluate(%q[ "foo" ])
|
222
|
+
vm.string_output = false
|
223
|
+
assert_equal ["foo"], JSON.parse(vm.evaluate(%q[ ["foo"] ]))
|
224
|
+
end
|
225
|
+
|
226
|
+
test "Jsonnet::VM#import_callback customizes import file resolution" do
|
227
|
+
vm = Jsonnet::VM.new
|
228
|
+
vm.import_callback = ->(base, rel) {
|
229
|
+
case [base, rel]
|
230
|
+
when ['/path/to/base/', 'imported1.jsonnet']
|
231
|
+
return <<-EOS, '/path/to/imported1/imported1.jsonnet'
|
232
|
+
import "imported2.jsonnet" {
|
233
|
+
b: 2,
|
234
|
+
}
|
235
|
+
EOS
|
236
|
+
when ['/path/to/imported1/', "imported2.jsonnet"]
|
237
|
+
return <<-EOS, '/path/to/imported2/imported2.jsonnet'
|
238
|
+
{ a: 1 }
|
239
|
+
EOS
|
240
|
+
else
|
241
|
+
raise Errno::ENOENT, "#{rel} at #{base}"
|
242
|
+
end
|
243
|
+
}
|
244
|
+
result = vm.evaluate(<<-EOS, filename: "/path/to/base/example.jsonnet")
|
245
|
+
import "imported1.jsonnet" { c: 3 }
|
246
|
+
EOS
|
247
|
+
|
248
|
+
expected = {"a" => 1, "b" => 2, "c" => 3}
|
249
|
+
assert_equal expected, JSON.parse(result)
|
250
|
+
end
|
251
|
+
|
252
|
+
test "Jsonnet::VM#evaluate returns an error if customized import callback raises an exception" do
|
253
|
+
vm = Jsonnet::VM.new
|
254
|
+
called = false
|
255
|
+
vm.import_callback = ->(base, rel) { called = true; raise }
|
256
|
+
assert_raise(Jsonnet::EvaluationError) {
|
257
|
+
vm.evaluate(<<-EOS)
|
258
|
+
import "a.jsonnet" {}
|
259
|
+
EOS
|
260
|
+
}
|
261
|
+
assert_true called
|
262
|
+
end
|
263
|
+
|
63
264
|
private
|
64
|
-
def
|
65
|
-
|
265
|
+
def with_example_file(content)
|
266
|
+
Tempfile.open("example.jsonnet") {|f|
|
267
|
+
f.print content
|
268
|
+
f.flush
|
269
|
+
f.rewind
|
270
|
+
yield f.path
|
271
|
+
}
|
66
272
|
end
|
67
273
|
end
|
68
274
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jsonnet
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yuki Yugui Sonoda
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-09-
|
11
|
+
date: 2015-09-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -85,8 +85,7 @@ files:
|
|
85
85
|
- jsonnet.gemspec
|
86
86
|
- lib/jsonnet.rb
|
87
87
|
- lib/jsonnet/version.rb
|
88
|
-
-
|
89
|
-
- test/example.jsonnet
|
88
|
+
- lib/jsonnet/vm.rb
|
90
89
|
- test/test_jsonnet.rb
|
91
90
|
- test/test_vm.rb
|
92
91
|
homepage: ''
|
@@ -114,7 +113,6 @@ signing_key:
|
|
114
113
|
specification_version: 4
|
115
114
|
summary: Jsonnet library
|
116
115
|
test_files:
|
117
|
-
- test/error.jsonnet
|
118
|
-
- test/example.jsonnet
|
119
116
|
- test/test_jsonnet.rb
|
120
117
|
- test/test_vm.rb
|
118
|
+
has_rdoc:
|
data/test/error.jsonnet
DELETED
data/test/example.jsonnet
DELETED