@@ -254,19 +254,161 @@ def h.to_hash; {:b => 2, :c => 3}; end
254
254
eval ( '{a: 1, :b => 2, "c" => 3, "d": 4, e: 5}' ) . should == h
255
255
end
256
256
257
- it "works with methods and local vars" do
258
- a = Class . new
259
- a . class_eval ( <<-RUBY )
260
- def bar
261
- "baz"
262
- end
257
+ # Copied from Prism::Translation::Ripper
258
+ keywords = [
259
+ "alias" ,
260
+ "and" ,
261
+ "begin" ,
262
+ "BEGIN" ,
263
+ "break" ,
264
+ "case" ,
265
+ "class" ,
266
+ "def" ,
267
+ "defined?" ,
268
+ "do" ,
269
+ "else" ,
270
+ "elsif" ,
271
+ "end" ,
272
+ "END" ,
273
+ "ensure" ,
274
+ "false" ,
275
+ "for" ,
276
+ "if" ,
277
+ "in" ,
278
+ "module" ,
279
+ "next" ,
280
+ "nil" ,
281
+ "not" ,
282
+ "or" ,
283
+ "redo" ,
284
+ "rescue" ,
285
+ "retry" ,
286
+ "return" ,
287
+ "self" ,
288
+ "super" ,
289
+ "then" ,
290
+ "true" ,
291
+ "undef" ,
292
+ "unless" ,
293
+ "until" ,
294
+ "when" ,
295
+ "while" ,
296
+ "yield" ,
297
+ "__ENCODING__" ,
298
+ "__FILE__" ,
299
+ "__LINE__"
300
+ ]
301
+
302
+ invalid_kw_param_names = [
303
+ "BEGIN" ,
304
+ "END" ,
305
+ "defined?" ,
306
+ ]
307
+
308
+ invalid_method_names = [
309
+ "BEGIN" ,
310
+ "END" ,
311
+ "defined?" ,
312
+ ]
313
+
314
+ # Evaluates the given Ruby source in a temporary Module, to prevent
315
+ # the surrounding context from being polluted with the new methods.
316
+ def sandboxed_eval ( ruby_src )
317
+ Module
318
+ # Allows instance methods defined by `ruby_src` to be called directly.
319
+ . new { extend self }
320
+ . class_eval ( ruby_src )
321
+ end
263
322
264
- def foo(val)
265
- {bar:, val:}
266
- end
323
+ it "can reference local variables" do
324
+ a = 1
325
+ b = 2
326
+
327
+ eval ( '{ a:, b: }.should == { a: 1, b: 2 }' )
328
+ end
329
+
330
+ it "cannot find dynamically defined local variables" do
331
+ b = binding
332
+ b . local_variable_set ( :abc , "a dynamically defined local var" )
333
+
334
+ eval <<~RUBY
335
+ # The local variable definitely exists:
336
+ b.local_variable_get(:abc).should == "a dynamically defined local var"
337
+ # but we can't get it via value omission:
338
+ -> { { abc: } }.should raise_error(NameError)
267
339
RUBY
340
+ end
341
+
342
+ it "can call methods" do
343
+ result = sandboxed_eval <<~RUBY
344
+ def m = "a statically defined method"
268
345
269
- a . new . foo ( 1 ) . should == { bar : "baz" , val : 1 }
346
+ { m: }
347
+ RUBY
348
+
349
+ result . should == { m : "a statically defined method" }
350
+ end
351
+
352
+ it "can find dynamically defined methods" do
353
+ result = sandboxed_eval <<~RUBY
354
+ define_method(:m) { "a dynamically defined method" }
355
+
356
+ { m: }
357
+ RUBY
358
+
359
+ result . should == { m : "a dynamically defined method" }
360
+ end
361
+
362
+ it "prefers local variables over methods" do
363
+ result = sandboxed_eval <<~RUBY
364
+ x = "from a local var"
365
+ def x; "from a method"; end
366
+ { x: }
367
+ RUBY
368
+
369
+ result . should == { x : "from a local var" }
370
+ end
371
+
372
+ describe "handling keywords" do
373
+ keywords . each do |kw |
374
+ describe "keyword '#{ kw } '" do
375
+ # None of these keywords can be used as local variables,
376
+ # so it's not possible to resolve them via shorthand Hash syntax.
377
+ # See `reserved_keywords.rb`
378
+
379
+ unless invalid_kw_param_names . include? ( kw )
380
+ it "can be used a keyword parameter name" do
381
+ result = sandboxed_eval <<~RUBY
382
+ def m(#{ kw } :) = { #{ kw } : }
383
+
384
+ m(#{ kw } : "an argument to '#{ kw } '")
385
+ RUBY
386
+
387
+ result . should == { kw . to_sym => "an argument to '#{ kw } '" }
388
+ end
389
+ end
390
+
391
+ unless invalid_method_names . include? ( kw )
392
+ it "can refer to a method called '#{ kw } '" do
393
+ result = sandboxed_eval <<~RUBY
394
+ def #{ kw } = "a method named '#{ kw } '"
395
+
396
+ { #{ kw } : }
397
+ RUBY
398
+
399
+ result . should == { kw . to_sym => "a method named '#{ kw } '" }
400
+ end
401
+ end
402
+ end
403
+ end
404
+
405
+ describe "keyword 'self:'" do
406
+ it "does not refer to actual 'self'" do
407
+ eval <<~RUBY
408
+ -> { { self: } }.should raise_error(NameError)
409
+ RUBY
410
+ end
411
+ end
270
412
end
271
413
272
414
it "raises a SyntaxError when the Hash key ends with `!`" do
0 commit comments