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