Skip to content

Commit d2dc0a2

Browse files
committed
Improve test for Hashes with omitted values
1 parent 2159b53 commit d2dc0a2

File tree

1 file changed

+152
-10
lines changed

1 file changed

+152
-10
lines changed

language/hash_spec.rb

Lines changed: 152 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -254,19 +254,161 @@ 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+
# 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
263322

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)
267339
RUBY
340+
end
341+
342+
it "can call methods" do
343+
result = sandboxed_eval <<~RUBY
344+
def m = "a statically defined method"
268345
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
270412
end
271413

272414
it "raises a SyntaxError when the Hash key ends with `!`" do

0 commit comments

Comments
 (0)