jsonnet 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0608c5c013b33c3336b6032b17e8a42266d3b273
4
- data.tar.gz: ce3d29f5b2be96106b458cd93765a1b2b2063287
3
+ metadata.gz: b3ba7719f8a07cc8385aef8ffc4b2e1b21924f33
4
+ data.tar.gz: ca340bf28f5f521aef9b5a7f2e71613e277f7fd4
5
5
  SHA512:
6
- metadata.gz: 830a1cb02c29949849ffa25d116a65096715054fcf077133a854025c1485f57b6ce796ced668d15c0cdd8e243c019708b09a8ff3b87f1b13033834fd11fab18f
7
- data.tar.gz: 3634f878aaa031ff2699963ab4c12c23dba41f52495e1b9915c71073b5ef8cbee8c3f7a4e7053e5f7c7f0fc4c84865a948a7cfb7633c7b7f1e9b71afe90c6809
6
+ metadata.gz: ba5847ad581b28bde58ee1b14f96e6b5624d72d96125ccf82aabc9543aff3280f6c39f0ba69ba2d4ae7484517e7fd3971d563e2868c8a01bef78adce74d89aab
7
+ data.tar.gz: 9519135c4c6f81cb94dca96ac22a4fb401839af5e8b6d573e7cd6d7d33a1b000bc92f3a907048a93ee251b15cef9a0727470c4655129d69360b8acf9149fac22
@@ -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 JsonnetVm *const vm = jsonnet_make();
37
- return TypedData_Wrap_Struct(cVM, &jsonnet_vm_type, vm);
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
- jsonnet_destroy((struct JsonnetVm*)ptr);
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
- struct JsonnetVm *vm;
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* result;
158
+ char *result;
159
+ rb_encoding *const enc = rb_to_encoding(encoding);
50
160
 
51
- TypedData_Get_Struct(self, struct JsonnetVm, &jsonnet_vm_type, vm);
161
+ TypedData_Get_Struct(self, struct jsonnet_vm_wrap, &jsonnet_vm_type, vm);
52
162
  FilePathValue(fname);
53
- result = jsonnet_evaluate_file(vm, StringValueCStr(fname), &error);
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
- rb_raise(eEvaluationError, "%s", result);
171
+ raise_eval_error(vm->vm, result, rb_enc_get(fname));
56
172
  }
57
- return rb_utf8_str_new_cstr(result);
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(int argc, VALUE *argv, VALUE self) {
62
- struct JsonnetVm *vm;
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* result;
65
- VALUE snippet, fname = Qnil;
181
+ char *result;
66
182
 
67
- rb_scan_args(argc, argv, "11", &snippet, &fname);
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
- rb_raise(eEvaluationError, "%s", result);
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
- return rb_utf8_str_new_cstr(result);
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
- rb_define_method(cVM, "evaluate_file", vm_evaluate_file, 1);
89
- rb_define_method(cVM, "evaluate", vm_evaluate, -1);
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
  }
@@ -1,5 +1,6 @@
1
1
  require "jsonnet/version"
2
2
  require "jsonnet/jsonnet_wrap"
3
+ require "jsonnet/vm"
3
4
 
4
5
  module Jsonnet
5
6
  # Your code goes here...
@@ -1,3 +1,3 @@
1
1
  module Jsonnet
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
@@ -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
@@ -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
- result = vm.evaluate_file example_file('example.jsonnet')
10
-
11
- assert_equal JSON.parse(<<-EOS), JSON.parse(result)
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
- EOS
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
- assert_raise(Jsonnet::EvaluationError) do
19
- vm.evaluate_file example_file('error.jsonnet')
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 example_file(name)
65
- File.join(File.dirname(__FILE__), name)
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.1
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-03 00:00:00.000000000 Z
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
- - test/error.jsonnet
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:
@@ -1,5 +0,0 @@
1
- {
2
- // unbound variable
3
- ["foo" + myvar]: myvar,
4
- }
5
-
@@ -1,4 +0,0 @@
1
- local myvar = 1;
2
- {
3
- ["foo" + myvar]: myvar,
4
- }