summaryrefslogtreecommitdiff
path: root/spec/ruby/core/binding/eval_spec.rb
blob: b36bec799ecbb2382eee67b52563b5e8b894be46 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
require_relative '../../spec_helper'
require_relative 'fixtures/classes'

describe "Binding#eval" do
  it "behaves like Kernel.eval(..., self)" do
    obj = BindingSpecs::Demo.new(1)
    bind = obj.get_binding

    bind.eval("@secret += square(3)").should == 10
    bind.eval("a").should be_true

    bind.eval("class Inside; end")
    bind.eval("Inside.name").should == "BindingSpecs::Demo::Inside"
  end

  it "does not leak variables to cloned bindings" do
    obj = BindingSpecs::Demo.new(1)
    bind = obj.get_empty_binding
    bind2 = bind.dup

    bind.eval("x = 72")
    bind.local_variables.should == [:x]
    bind2.local_variables.should == []
  end

  ruby_version_is ""..."3.0" 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

  ruby_version_is "3.0" 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 "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 "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
    bind = BindingSpecs::Demo.new(1).get_binding
    bind.eval("__LINE__", "(test)").should == 1
    bind.eval("#foo\n__LINE__", "(test)").should == 2
  end

  it "starts with a __LINE__ from the third argument if passed" do
    bind = BindingSpecs::Demo.new(1).get_binding
    bind.eval("__LINE__", "(test)", 88).should == 88
    bind.eval("#foo\n__LINE__", "(test)", 88).should == 89
  end

  ruby_version_is ""..."3.0" 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 "3.0" 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
    bind = BindingSpecs::Demo.new(1).get_binding
    bind.eval("__FILE__", "(test)").should == "(test)"
  end

  describe "with a file given" do
    it "does not store the filename permanently" do
      obj = BindingSpecs::Demo.new(1)
      bind = obj.get_binding

      bind.eval("__FILE__", "test.rb").should == "test.rb"
      suppress_warning {bind.eval("__FILE__")}.should_not == "test.rb"
    end
  end

  it "with __method__ returns the method where the Binding was created" do
    obj = BindingSpecs::Demo.new(1)
    bind, meth = obj.get_binding_and_method
    bind.eval("__method__").should == meth
  end

  it "with __method__ returns the method where the Binding was created, ignoring #send" do
    obj = BindingSpecs::Demo.new(1)
    bind, meth = obj.get_binding_with_send_and_method
    bind.eval("__method__").should == meth
  end

  it "reflects refinements activated in the binding scope" do
    bind = BindingSpecs::Refined.refined_binding

    bind.eval("'bar'.foo").should == "foo"
  end
end