@@ -254,19 +254,152 @@ def h.to_hash; {:b => 2, :c => 3}; end
254254 eval ( '{a: 1, :b => 2, "c" => 3, "d": 4, e: 5}' ) . should == h
255255 end
256256
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+ it "can resolve local variables" do
315+ a = 1
316+ b = 2
317+
318+ eval ( '{ a:, b: }.should == { a: 1, b: 2 }' )
319+ end
263320
264- def foo(val)
265- {bar:, val:}
266- end
321+ it "cannot find dynamically defined local variables" do
322+ b = binding
323+ b . local_variable_set ( :abc , "a dynamically defined local var" )
324+
325+ eval <<~RUBY
326+ # The local variable definitely exists:
327+ b.local_variable_get(:abc).should == "a dynamically defined local var"
328+ # but we can't get it via value omission:
329+ -> { { abc: } }.should raise_error(NameError)
330+ RUBY
331+ end
332+
333+ it "can call methods" do
334+ result = sandboxed_eval <<~RUBY
335+ def m = "a statically defined method"
336+
337+ { m: }
338+ RUBY
339+
340+ result . should == { m : "a statically defined method" }
341+ end
342+
343+ it "can call dynamically defined methods" do
344+ result = sandboxed_eval <<~RUBY
345+ define_method(:m) { "a dynamically defined method" }
346+
347+ { m: }
348+ RUBY
349+
350+ result . should == { m : "a dynamically defined method" }
351+ end
352+
353+ it "prefers local variables over methods" do
354+ result = sandboxed_eval <<~RUBY
355+ x = "from a local var"
356+ def x; "from a method"; end
357+ { x: }
267358 RUBY
268359
269- a . new . foo ( 1 ) . should == { bar : "baz" , val : 1 }
360+ result . should == { x : "from a local var" }
361+ end
362+
363+ describe "handling keywords" do
364+ keywords . each do |kw |
365+ describe "keyword '#{ kw } '" do
366+ # None of these keywords can be used as local variables,
367+ # so it's not possible to resolve them via shorthand Hash syntax.
368+ # See `reserved_keywords.rb`
369+
370+ unless invalid_kw_param_names . include? ( kw )
371+ it "can resolve to a parameter whose name is a keyword" do
372+ result = sandboxed_eval <<~RUBY
373+ def m(#{ kw } :) = { #{ kw } : }
374+
375+ m(#{ kw } : "an argument to '#{ kw } '")
376+ RUBY
377+
378+ result . should == { kw . to_sym => "an argument to '#{ kw } '" }
379+ end
380+ end
381+
382+ unless invalid_method_names . include? ( kw )
383+ it "can resolve to a method whose name is a keyword" do
384+ result = sandboxed_eval <<~RUBY
385+ def #{ kw } = "a method named '#{ kw } '"
386+
387+ { #{ kw } : }
388+ RUBY
389+
390+ result . should == { kw . to_sym => "a method named '#{ kw } '" }
391+ end
392+ end
393+ end
394+ end
395+
396+ describe "keyword 'self:'" do
397+ it "does not refer to actual 'self'" do
398+ eval <<~RUBY
399+ -> { { self: } }.should raise_error(NameError)
400+ RUBY
401+ end
402+ end
270403 end
271404
272405 it "raises a SyntaxError when the Hash key ends with `!`" do
0 commit comments