mirror of
https://github.com/ruby/ruby.git
synced 2022-11-09 12:17:21 -05:00
Make eval(code, binding) use (eval) as __FILE__ and 1 as __LINE__
This removes the warning that was added in
3802fb92ff
, and switches the behavior
so that the eval does not use the binding's __FILE__ and __LINE__
implicitly.
Fixes [Bug #4352]
This commit is contained in:
parent
170f4dbb9b
commit
0eeed5bcc5
Notes:
git
2020-01-04 13:13:49 +09:00
7 changed files with 103 additions and 67 deletions
24
parse.y
24
parse.y
|
@ -315,7 +315,6 @@ struct parser_params {
|
|||
unsigned int do_loop: 1;
|
||||
unsigned int do_chomp: 1;
|
||||
unsigned int do_split: 1;
|
||||
unsigned int warn_location: 1;
|
||||
|
||||
NODE *eval_tree_begin;
|
||||
NODE *eval_tree;
|
||||
|
@ -9917,19 +9916,6 @@ past_dvar_p(struct parser_params *p, ID id)
|
|||
}
|
||||
# endif
|
||||
|
||||
/* As Ripper#warn does not have arguments for the location, so the
|
||||
* following messages cannot be separated */
|
||||
#define WARN_LOCATION(type) do { \
|
||||
if (p->warn_location) { \
|
||||
int line; \
|
||||
VALUE file = rb_source_location(&line); \
|
||||
rb_warn3(type" in eval may not return location in binding;" \
|
||||
" use Binding#source_location instead\n" \
|
||||
"%"PRIsWARN":%d: warning: in `%"PRIsWARN"'", \
|
||||
file, WARN_I(line), rb_id2str(rb_frame_this_func())); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
static int
|
||||
numparam_nested_p(struct parser_params *p)
|
||||
{
|
||||
|
@ -9963,7 +9949,6 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
|
|||
case keyword_false:
|
||||
return NEW_FALSE(loc);
|
||||
case keyword__FILE__:
|
||||
WARN_LOCATION("__FILE__");
|
||||
{
|
||||
VALUE file = p->ruby_sourcefile_string;
|
||||
if (NIL_P(file))
|
||||
|
@ -9975,7 +9960,6 @@ gettable(struct parser_params *p, ID id, const YYLTYPE *loc)
|
|||
}
|
||||
return node;
|
||||
case keyword__LINE__:
|
||||
WARN_LOCATION("__LINE__");
|
||||
return NEW_LIT(INT2FIX(p->tokline), loc);
|
||||
case keyword__ENCODING__:
|
||||
node = NEW_LIT(rb_enc_from_encoding(p->enc), loc);
|
||||
|
@ -12248,14 +12232,6 @@ rb_parser_set_options(VALUE vparser, int print, int loop, int chomp, int split)
|
|||
p->do_split = split;
|
||||
}
|
||||
|
||||
void
|
||||
rb_parser_warn_location(VALUE vparser, int warn)
|
||||
{
|
||||
struct parser_params *p;
|
||||
TypedData_Get_Struct(vparser, struct parser_params, &parser_data_type, p);
|
||||
p->warn_location = warn;
|
||||
}
|
||||
|
||||
static NODE *
|
||||
parser_append_options(struct parser_params *p, NODE *node)
|
||||
{
|
||||
|
|
|
@ -23,29 +23,58 @@ describe "Binding#eval" do
|
|||
bind2.local_variables.should == []
|
||||
end
|
||||
|
||||
it "inherits __LINE__ from the enclosing scope" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
|
||||
ruby_version_is ""..."2.8" do
|
||||
it "inherits __LINE__ from the enclosing scope" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
|
||||
end
|
||||
|
||||
it "preserves __LINE__ across multiple calls to eval" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
|
||||
suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
|
||||
end
|
||||
|
||||
it "increments __LINE__ on each line of a multiline eval" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("#foo\n__LINE__")}.should == obj.get_line_of_binding + 1
|
||||
end
|
||||
|
||||
it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind, line = obj.get_binding_with_send_and_line
|
||||
suppress_warning {bind.eval("__LINE__")}.should == line
|
||||
end
|
||||
end
|
||||
|
||||
it "preserves __LINE__ across multiple calls to eval" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
|
||||
suppress_warning {bind.eval("__LINE__")}.should == obj.get_line_of_binding
|
||||
end
|
||||
ruby_version_is "2.8" do
|
||||
it "starts with line 1 if single argument is given" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
bind.eval("__LINE__").should == 1
|
||||
end
|
||||
|
||||
it "increments __LINE__ on each line of a multiline eval" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("#foo\n__LINE__")}.should == obj.get_line_of_binding + 1
|
||||
end
|
||||
it "preserves __LINE__ across multiple calls to eval" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
bind.eval("__LINE__").should == 1
|
||||
bind.eval("__LINE__").should == 1
|
||||
end
|
||||
|
||||
it "inherits __LINE__ from the enclosing scope even if the Binding is created with #send" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind, line = obj.get_binding_with_send_and_line
|
||||
suppress_warning {bind.eval("__LINE__")}.should == line
|
||||
it "increments __LINE__ on each line of a multiline eval" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
bind.eval("#foo\n__LINE__").should == 2
|
||||
end
|
||||
|
||||
it "starts with line 1 if the Binding is created with #send" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind, line = obj.get_binding_with_send_and_line
|
||||
bind.eval("__LINE__").should == 1
|
||||
end
|
||||
end
|
||||
|
||||
it "starts with a __LINE__ of 1 if a filename is passed" do
|
||||
|
@ -60,10 +89,20 @@ describe "Binding#eval" do
|
|||
bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
|
||||
end
|
||||
|
||||
it "inherits __FILE__ from the enclosing scope" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("__FILE__")}.should == obj.get_file_of_binding
|
||||
ruby_version_is ""..."2.8" do
|
||||
it "inherits __FILE__ from the enclosing scope" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
suppress_warning {bind.eval("__FILE__")}.should == obj.get_file_of_binding
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "2.8" do
|
||||
it "Uses (eval) as __FILE__ if single argument given" do
|
||||
obj = BindingSpecs::Demo.new(1)
|
||||
bind = obj.get_binding
|
||||
bind.eval("__FILE__").should == '(eval)'
|
||||
end
|
||||
end
|
||||
|
||||
it "uses the __FILE__ that is passed in" do
|
||||
|
|
|
@ -12,9 +12,19 @@ describe "Kernel#__dir__" do
|
|||
end
|
||||
end
|
||||
|
||||
context "when used in eval with top level binding" do
|
||||
it "returns the real name of the directory containing the currently-executing file" do
|
||||
eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
|
||||
ruby_version_is ""..."2.7" do
|
||||
context "when used in eval with top level binding" do
|
||||
it "returns the real name of the directory containing the currently-executing file" do
|
||||
eval("__dir__", binding).should == File.realpath(File.dirname(__FILE__))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "2.7" do
|
||||
context "when used in eval with top level binding" do
|
||||
it "returns nil" do
|
||||
eval("__dir__", binding).should == nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
@ -159,13 +159,27 @@ describe "Kernel#eval" do
|
|||
end
|
||||
end
|
||||
|
||||
it "uses the filename of the binding if none is provided" do
|
||||
eval("__FILE__").should == "(eval)"
|
||||
suppress_warning {eval("__FILE__", binding)}.should == __FILE__
|
||||
eval("__FILE__", binding, "success").should == "success"
|
||||
suppress_warning {eval("eval '__FILE__', binding")}.should == "(eval)"
|
||||
suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__
|
||||
suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success'
|
||||
ruby_version_is ""..."2.8" do
|
||||
it "uses the filename of the binding if none is provided" do
|
||||
eval("__FILE__").should == "(eval)"
|
||||
suppress_warning {eval("__FILE__", binding)}.should == __FILE__
|
||||
eval("__FILE__", binding, "success").should == "success"
|
||||
suppress_warning {eval("eval '__FILE__', binding")}.should == "(eval)"
|
||||
suppress_warning {eval("eval '__FILE__', binding", binding)}.should == __FILE__
|
||||
suppress_warning {eval("eval '__FILE__', binding", binding, 'success')}.should == 'success'
|
||||
end
|
||||
end
|
||||
|
||||
ruby_version_is "2.8" do
|
||||
it "uses (eval) filename if none is provided" do
|
||||
eval("__FILE__").should == "(eval)"
|
||||
eval("__FILE__", binding).should == "(eval)"
|
||||
eval("__FILE__", binding, "success").should == "success"
|
||||
eval("eval '__FILE__', binding").should == "(eval)"
|
||||
eval("eval '__FILE__', binding", binding).should == "(eval)"
|
||||
eval("eval '__FILE__', binding", binding, 'success').should == '(eval)'
|
||||
eval("eval '__FILE__', binding, 'success'", binding).should == 'success'
|
||||
end
|
||||
end
|
||||
|
||||
# Found via Rubinius bug github:#149
|
||||
|
|
|
@ -470,9 +470,12 @@ class TestEval < Test::Unit::TestCase
|
|||
end
|
||||
|
||||
def test_eval_location_binding
|
||||
assert_warning(/__FILE__ in eval/) do
|
||||
assert_equal(__FILE__, eval("__FILE__", binding))
|
||||
end
|
||||
assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", nil))
|
||||
assert_equal(['(eval)', 1], eval("[__FILE__, __LINE__]", binding))
|
||||
assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", nil, 'foo'))
|
||||
assert_equal(['foo', 1], eval("[__FILE__, __LINE__]", binding, 'foo'))
|
||||
assert_equal(['foo', 2], eval("[__FILE__, __LINE__]", nil, 'foo', 2))
|
||||
assert_equal(['foo', 2], eval("[__FILE__, __LINE__]", binding, 'foo', 2))
|
||||
end
|
||||
|
||||
def test_fstring_instance_eval
|
||||
|
|
|
@ -790,7 +790,7 @@ class TestMethod < Test::Unit::TestCase
|
|||
assert_instance_of String, __dir__
|
||||
assert_equal(File.dirname(File.realpath(__FILE__)), __dir__)
|
||||
bug8436 = '[ruby-core:55123] [Bug #8436]'
|
||||
assert_equal(__dir__, eval("__dir__", binding), bug8436)
|
||||
assert_equal(__dir__, eval("__dir__", binding, *binding.source_location), bug8436)
|
||||
bug8662 = '[ruby-core:56099] [Bug #8662]'
|
||||
assert_equal("arbitrary", eval("__dir__", binding, "arbitrary/file.rb"), bug8662)
|
||||
assert_equal("arbitrary", Object.new.instance_eval("__dir__", "arbitrary/file.rb"), bug8662)
|
||||
|
|
|
@ -1497,12 +1497,6 @@ eval_make_iseq(VALUE src, VALUE fname, int line, const rb_binding_t *bind,
|
|||
if (!NIL_P(fname)) fname = rb_fstring(fname);
|
||||
realpath = fname;
|
||||
}
|
||||
else if (bind) {
|
||||
fname = pathobj_path(bind->pathobj);
|
||||
realpath = pathobj_realpath(bind->pathobj);
|
||||
line = bind->first_lineno;
|
||||
rb_parser_warn_location(parser, TRUE);
|
||||
}
|
||||
else {
|
||||
fname = rb_fstring_lit("(eval)");
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue