Skip to content
Open
Show file tree
Hide file tree
Changes from 4 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
159 changes: 159 additions & 0 deletions language/reserved_keywords.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
require_relative '../spec_helper'

describe "Ruby's reserved keywords" do
# Copied from Prism::Translation::Ripper
keywords = %w[
alias
and
begin
BEGIN
break
case
class
def
defined?
do
else
elsif
end
END
ensure
false
for
if
in
module
next
nil
not
or
redo
rescue
retry
return
self
super
then
true
undef
unless
until
when
while
yield
__ENCODING__
__FILE__
__LINE__
]

keywords.each do |kw|
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
keywords.each do |kw|
keywords.each do |name|

kw feels too confusing here, especially since there is a spec about keyword arguments below.
Since we are mostly testing names for variables/methods, name seems clearer in usages.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Mmmmm I disagree, in a spec focused on describing the behaviour of keywords, I would expect "keyword" to a be prominent term. It's an overloaded term, but that's just how Ruby is already. Perhaps keyword is better than kw?

Anyway, I renamed to name

describe "keyword '#{kw}'" do
it "can't be used as local variable name" do
-> { eval(<<~RUBY) }.should raise_error(SyntaxError)
#{kw} = "a local variable named '#{kw}'"
RUBY
end

invalid_ivar_names = ["defined?"]

if invalid_ivar_names.include?(kw)
it "can't be used as an instance variable name" do
-> { eval(<<~RUBY) }.should raise_error(SyntaxError)
@#{kw} = "an instance variable named '#{kw}'"
RUBY
end
else
it "can be used as an instance variable name" do
result = eval <<~RUBY
@#{kw} = "an instance variable named '#{kw}'"
@#{kw}
RUBY

result.should == "an instance variable named '#{kw}'"
end
end

invalid_class_var_names = ["defined?"]

if invalid_class_var_names.include?(kw)
it "can't be used as a class variable name" do
-> { eval(<<~RUBY) }.should raise_error(SyntaxError)
class C
@@#{kw} = "a class variable named '#{kw}'"
end
RUBY
end
else
it "can be used as a class variable name" do
result = eval <<~RUBY
class C
@@#{kw} = "a class variable named '#{kw}'"
@@#{kw}
end
RUBY

result.should == "a class variable named '#{kw}'"
end
end

invalid_global_var_names = ["defined?"]

if invalid_global_var_names.include?(kw)
it "can't be used as a global variable name" do
-> { eval(<<~RUBY) }.should raise_error(SyntaxError)
$#{kw} = "a global variable named '#{kw}'"
RUBY
end
else
it "can be used as a global variable name" do
result = eval <<~RUBY
$#{kw} = "a global variable named '#{kw}'"
$#{kw}
RUBY

result.should == "a global variable named '#{kw}'"
end
end

it "can't be used as a positional parameter name" do
-> { eval(<<~RUBY) }.should raise_error(SyntaxError)
def x(#{kw}); end
RUBY
end

invalid_kw_param_names = ["BEGIN","END","defined?"]

if invalid_kw_param_names.include?(kw)
it "can't be used a keyword parameter name" do
-> { eval(<<~RUBY) }.should raise_error(SyntaxError)
def self.m(#{kw}:); end
RUBY
end
else
it "can be used a keyword parameter name" do
result = eval <<~RUBY
def self.m(#{kw}:)
binding.local_variable_get(:#{kw})
end
m(#{kw}: "an argument to '#{kw}'")
RUBY

result.should == "an argument to '#{kw}'"
end
end

it "can be used as a method name" do
result = eval <<~RUBY
def self.#{kw}
"a method named '#{kw}'"
end
send(:#{kw})
RUBY

result.should == "a method named '#{kw}'"
end
end
end
end
10 changes: 10 additions & 0 deletions spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,13 @@ def report_on_exception=(value)
ARGV.unshift $0
MSpecRun.main
end

# Evaluates the given Ruby source in a temporary Module, to prevent
# the surrounding context from being polluted with the new methods.
def sandboxed_eval(ruby_src)
Module.new do
# Allows instance methods defined by `ruby_src` to be called directly.
extend self
end
.class_eval(ruby_src)
end