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
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
|
main = self
describe :kernel_load, shared: true do
before :each do
CodeLoadingSpecs.spec_setup
@path = File.expand_path "load_fixture.rb", CODE_LOADING_DIR
end
after :each do
CodeLoadingSpecs.spec_cleanup
end
it "loads a non-extensioned file as a Ruby source file" do
path = File.expand_path "load_fixture", CODE_LOADING_DIR
@object.load(path).should be_true
ScratchPad.recorded.should == [:no_ext]
end
it "loads a non .rb extensioned file as a Ruby source file" do
path = File.expand_path "load_fixture.ext", CODE_LOADING_DIR
@object.load(path).should be_true
ScratchPad.recorded.should == [:no_rb_ext]
end
it "loads from the current working directory" do
Dir.chdir CODE_LOADING_DIR do
@object.load("load_fixture.rb").should be_true
ScratchPad.recorded.should == [:loaded]
end
end
it "loads a file that recursively requires itself" do
path = File.expand_path "recursive_require_fixture.rb", CODE_LOADING_DIR
-> {
@object.load(path).should be_true
}.should complain(/circular require considered harmful/, verbose: true)
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file that recursively loads itself" do
path = File.expand_path "recursive_load_fixture.rb", CODE_LOADING_DIR
@object.load(path).should be_true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file each time the method is called" do
@object.load(@path).should be_true
@object.load(@path).should be_true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads a file even when the name appears in $LOADED_FEATURES" do
$LOADED_FEATURES << @path
@object.load(@path).should be_true
ScratchPad.recorded.should == [:loaded]
end
it "loads a file that has been loaded by #require" do
@object.require(@path).should be_true
@object.load(@path).should be_true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "loads file even after $LOAD_PATH change" do
$LOAD_PATH << CODE_LOADING_DIR
@object.load("load_fixture.rb").should be_true
$LOAD_PATH.unshift CODE_LOADING_DIR + "/gem"
@object.load("load_fixture.rb").should be_true
ScratchPad.recorded.should == [:loaded, :loaded_gem]
end
it "does not cause #require with the same path to fail" do
@object.load(@path).should be_true
@object.require(@path).should be_true
ScratchPad.recorded.should == [:loaded, :loaded]
end
it "does not add the loaded path to $LOADED_FEATURES" do
saved_loaded_features = $LOADED_FEATURES.dup
@object.load(@path).should be_true
$LOADED_FEATURES.should == saved_loaded_features
end
it "raises a LoadError if passed a non-extensioned path that does not exist but a .rb extensioned path does exist" do
path = File.expand_path "load_ext_fixture", CODE_LOADING_DIR
-> { @object.load(path) }.should raise_error(LoadError)
end
describe "when passed true for 'wrap'" do
it "loads from an existing path" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true).should be_true
end
it "sets the enclosing scope to an anonymous module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
Object.const_defined?(:LoadSpecWrap).should be_false
wrap_module = ScratchPad.recorded[1]
wrap_module.should be_an_instance_of(Module)
end
it "allows referencing outside namespaces" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
ScratchPad.recorded[0].should equal(String)
end
it "sets self as a copy of the top-level main" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
top_level = ScratchPad.recorded[2]
top_level.to_s.should == "main"
top_level.method(:to_s).owner.should == top_level.singleton_class
top_level.should_not equal(main)
top_level.should be_an_instance_of(Object)
end
it "includes modules included in main's singleton class in self's class" do
mod = Module.new
main.extend(mod)
main_ancestors = main.singleton_class.ancestors[1..-1]
main_ancestors.first.should == mod
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
top_level = ScratchPad.recorded[2]
top_level_ancestors = top_level.singleton_class.ancestors[-main_ancestors.size..-1]
top_level_ancestors.should == main_ancestors
wrap_module = ScratchPad.recorded[1]
top_level.singleton_class.ancestors.should == [top_level.singleton_class, wrap_module, *main_ancestors]
end
describe "with top-level methods" do
before :each do
path = File.expand_path "load_wrap_method_fixture.rb", CODE_LOADING_DIR
@object.load(path, true)
end
it "allows calling top-level methods" do
ScratchPad.recorded.last.should == :load_wrap_loaded
end
it "does not pollute the receiver" do
-> { @object.send(:top_level_method) }.should raise_error(NameError)
end
end
end
describe "when passed a module for 'wrap'" do
ruby_version_is "3.1" do
it "sets the enclosing scope to the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
Object.const_defined?(:LoadSpecWrap).should be_false
mod.const_defined?(:LoadSpecWrap).should be_true
wrap_module = ScratchPad.recorded[1]
wrap_module.should == mod
end
it "makes constants and instance methods in the source file reachable with the supplied module" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
mod::LOAD_WRAP_SPECS_TOP_LEVEL_CONSTANT.should == 1
obj = Object.new
obj.extend(mod)
obj.send(:load_wrap_specs_top_level_method).should == :load_wrap_specs_top_level_method
end
it "makes instance methods in the source file private" do
path = File.expand_path "load_wrap_fixture.rb", CODE_LOADING_DIR
mod = Module.new
@object.load(path, mod)
mod.private_instance_methods.include?(:load_wrap_specs_top_level_method).should == true
end
end
end
describe "(shell expansion)" do
before :each do
@env_home = ENV["HOME"]
ENV["HOME"] = CODE_LOADING_DIR
end
after :each do
ENV["HOME"] = @env_home
end
it "expands a tilde to the HOME environment variable as the path to load" do
@object.require("~/load_fixture.rb").should be_true
ScratchPad.recorded.should == [:loaded]
end
end
end
|