faster_pathname 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +17 -0
- data/.travis.yml +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +35 -0
- data/Rakefile +14 -0
- data/faster_pathname.gemspec +23 -0
- data/lib/faster_pathname.rb +8 -0
- data/lib/faster_pathname/version.rb +3 -0
- data/lib/ruby/pathname.rb +18 -0
- data/lib/ruby/pathname_windows.rb +19 -0
- data/test/envutil.rb +396 -0
- data/test/envutil_19.rb +212 -0
- data/test/test_pathname.rb +1302 -0
- data/test/test_pathname_19.rb +1295 -0
- metadata +92 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 0ccbc8073d0305e0b0884acb20129df0f8e26269
|
4
|
+
data.tar.gz: 85a9c53a151c5700e0f05e16f819dfc244e98119
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 6a15c9cfae6cc12c8055b7483edd0dd6275b4ed4d4412d9703c1ff6a3af72220fd8fff51fc54afadf19077eb56dc22150cc47dc21b666202a3e0b9ceac57859b
|
7
|
+
data.tar.gz: 17a611ee4b55a2aae84e7fab98beb3bed399ede70d5b20d29c33c282e36bec28f5b5e4a1b045defcb97e556be5f8c72435bf8280287efe53b714f470d66290bc
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Chris Heald
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# FasterPathname
|
2
|
+
|
3
|
+

|
4
|
+
|
5
|
+
Pathname is slow. This makes Sprockets slow. This gem patches some of the slowest methods in
|
6
|
+
Pathname to make Sprockets fast.
|
7
|
+
|
8
|
+
See [this issue](https://github.com/sstephenson/sprockets/issues/506) for an overview of the issue.
|
9
|
+
|
10
|
+
## Installation
|
11
|
+
|
12
|
+
Add this line to your application's Gemfile:
|
13
|
+
|
14
|
+
gem 'faster_pathname'
|
15
|
+
|
16
|
+
And then execute:
|
17
|
+
|
18
|
+
$ bundle
|
19
|
+
|
20
|
+
Or install it yourself as:
|
21
|
+
|
22
|
+
$ gem install faster_pathname
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
1. Install gem
|
27
|
+
2. Enjoy Sprockets being 25% faster
|
28
|
+
|
29
|
+
## Contributing
|
30
|
+
|
31
|
+
1. Fork it
|
32
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
33
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
34
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
35
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
require 'rake/testtask'
|
3
|
+
|
4
|
+
Rake::TestTask.new do |t|
|
5
|
+
t.libs << "test"
|
6
|
+
if RUBY_VERSION =~ /^1\.9/
|
7
|
+
t.test_files = FileList['test/test_pathname_19.rb']
|
8
|
+
else
|
9
|
+
t.test_files = FileList['test/test_pathname.rb']
|
10
|
+
end
|
11
|
+
t.verbose = true
|
12
|
+
end
|
13
|
+
|
14
|
+
task :default => :test
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'faster_pathname/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "faster_pathname"
|
8
|
+
spec.version = FasterPathname::VERSION
|
9
|
+
spec.authors = ["Chris Heald"]
|
10
|
+
spec.email = ["cheald@gmail.com"]
|
11
|
+
spec.summary = %q{Patches some parts of the Pathname Ruby stdlib class for improved performance}
|
12
|
+
spec.description = %q{Patches some parts of the Pathname Ruby stdlib class for improved performance}
|
13
|
+
spec.homepage = ""
|
14
|
+
spec.license = "MIT"
|
15
|
+
|
16
|
+
spec.files = `git ls-files`.split($/)
|
17
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
18
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
19
|
+
spec.require_paths = ["lib"]
|
20
|
+
|
21
|
+
spec.add_development_dependency "bundler"
|
22
|
+
spec.add_development_dependency "rake"
|
23
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
class Pathname
|
2
|
+
def relative?
|
3
|
+
@path[0] != File::SEPARATOR
|
4
|
+
end
|
5
|
+
|
6
|
+
def join(*args)
|
7
|
+
last = args.last
|
8
|
+
if last.to_s[0] == File::SEPARATOR
|
9
|
+
if last.is_a? Pathname
|
10
|
+
last
|
11
|
+
else
|
12
|
+
Pathname.new last
|
13
|
+
end
|
14
|
+
else
|
15
|
+
Pathname.new(File.join @path, *args.map(&:to_s))
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Pathname
|
2
|
+
def relative?
|
3
|
+
@path[0] != File::SEPARATOR && @path[0] != File::ALT_SEPARATOR
|
4
|
+
end
|
5
|
+
|
6
|
+
def join(*args)
|
7
|
+
last = args.last
|
8
|
+
first_char = last.to_s[0]
|
9
|
+
if first_char == File::SEPARATOR || first_char == File::ALT_SEPARATOR
|
10
|
+
if last.is_a? Pathname
|
11
|
+
last
|
12
|
+
else
|
13
|
+
Pathname.new last
|
14
|
+
end
|
15
|
+
else
|
16
|
+
Pathname.new(File.join @path, *args.map(&:to_s))
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/test/envutil.rb
ADDED
@@ -0,0 +1,396 @@
|
|
1
|
+
# -*- coding: us-ascii -*-
|
2
|
+
require "open3"
|
3
|
+
require "timeout"
|
4
|
+
|
5
|
+
module EnvUtil
|
6
|
+
def rubybin
|
7
|
+
unless ENV["RUBYOPT"]
|
8
|
+
|
9
|
+
end
|
10
|
+
if ruby = ENV["RUBY"]
|
11
|
+
return ruby
|
12
|
+
end
|
13
|
+
ruby = "ruby"
|
14
|
+
rubyexe = ruby+".exe"
|
15
|
+
3.times do
|
16
|
+
if File.exist? ruby and File.executable? ruby and !File.directory? ruby
|
17
|
+
return File.expand_path(ruby)
|
18
|
+
end
|
19
|
+
if File.exist? rubyexe and File.executable? rubyexe
|
20
|
+
return File.expand_path(rubyexe)
|
21
|
+
end
|
22
|
+
ruby = File.join("..", ruby)
|
23
|
+
end
|
24
|
+
if defined?(RbConfig.ruby)
|
25
|
+
RbConfig.ruby
|
26
|
+
else
|
27
|
+
"ruby"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
module_function :rubybin
|
31
|
+
|
32
|
+
LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
|
33
|
+
|
34
|
+
def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false,
|
35
|
+
encoding: nil, timeout: 10, reprieve: 1, **opt)
|
36
|
+
in_c, in_p = IO.pipe
|
37
|
+
out_p, out_c = IO.pipe if capture_stdout
|
38
|
+
err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
|
39
|
+
opt[:in] = in_c
|
40
|
+
opt[:out] = out_c if capture_stdout
|
41
|
+
opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr
|
42
|
+
if encoding
|
43
|
+
out_p.set_encoding(encoding) if out_p
|
44
|
+
err_p.set_encoding(encoding) if err_p
|
45
|
+
end
|
46
|
+
c = "C"
|
47
|
+
child_env = {}
|
48
|
+
LANG_ENVS.each {|lc| child_env[lc] = c}
|
49
|
+
if Array === args and Hash === args.first
|
50
|
+
child_env.update(args.shift)
|
51
|
+
end
|
52
|
+
args = [args] if args.kind_of?(String)
|
53
|
+
pid = spawn(child_env, EnvUtil.rubybin, *args, **opt)
|
54
|
+
in_c.close
|
55
|
+
out_c.close if capture_stdout
|
56
|
+
err_c.close if capture_stderr && capture_stderr != :merge_to_stdout
|
57
|
+
if block_given?
|
58
|
+
return yield in_p, out_p, err_p, pid
|
59
|
+
else
|
60
|
+
th_stdout = Thread.new { out_p.read } if capture_stdout
|
61
|
+
th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout
|
62
|
+
in_p.write stdin_data.to_str
|
63
|
+
in_p.close
|
64
|
+
if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
|
65
|
+
stdout = th_stdout.value if capture_stdout
|
66
|
+
stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
|
67
|
+
else
|
68
|
+
signal = /mswin|mingw/ =~ RUBY_PLATFORM ? :KILL : :TERM
|
69
|
+
begin
|
70
|
+
Process.kill signal, pid
|
71
|
+
rescue Errno::ESRCH
|
72
|
+
break
|
73
|
+
else
|
74
|
+
end until signal == :KILL or (sleep reprieve; signal = :KILL; false)
|
75
|
+
raise Timeout::Error
|
76
|
+
end
|
77
|
+
out_p.close if capture_stdout
|
78
|
+
err_p.close if capture_stderr && capture_stderr != :merge_to_stdout
|
79
|
+
Process.wait pid
|
80
|
+
status = $?
|
81
|
+
return stdout, stderr, status
|
82
|
+
end
|
83
|
+
ensure
|
84
|
+
[th_stdout, th_stderr].each do |th|
|
85
|
+
th.kill if th
|
86
|
+
end
|
87
|
+
[in_c, in_p, out_c, out_p, err_c, err_p].each do |io|
|
88
|
+
io.close if io && !io.closed?
|
89
|
+
end
|
90
|
+
[th_stdout, th_stderr].each do |th|
|
91
|
+
th.join if th
|
92
|
+
end
|
93
|
+
end
|
94
|
+
module_function :invoke_ruby
|
95
|
+
|
96
|
+
alias rubyexec invoke_ruby
|
97
|
+
class << self
|
98
|
+
alias rubyexec invoke_ruby
|
99
|
+
end
|
100
|
+
|
101
|
+
def verbose_warning
|
102
|
+
class << (stderr = "")
|
103
|
+
alias write <<
|
104
|
+
end
|
105
|
+
stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
|
106
|
+
yield stderr
|
107
|
+
return $stderr
|
108
|
+
ensure
|
109
|
+
stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
|
110
|
+
end
|
111
|
+
module_function :verbose_warning
|
112
|
+
|
113
|
+
def suppress_warning
|
114
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
115
|
+
yield
|
116
|
+
ensure
|
117
|
+
$VERBOSE = verbose
|
118
|
+
end
|
119
|
+
module_function :suppress_warning
|
120
|
+
|
121
|
+
def under_gc_stress
|
122
|
+
stress, GC.stress = GC.stress, true
|
123
|
+
yield
|
124
|
+
ensure
|
125
|
+
GC.stress = stress
|
126
|
+
end
|
127
|
+
module_function :under_gc_stress
|
128
|
+
|
129
|
+
def with_default_external(enc)
|
130
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
131
|
+
origenc, Encoding.default_external = Encoding.default_external, enc
|
132
|
+
$VERBOSE = verbose
|
133
|
+
yield
|
134
|
+
ensure
|
135
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
136
|
+
Encoding.default_external = origenc
|
137
|
+
$VERBOSE = verbose
|
138
|
+
end
|
139
|
+
module_function :with_default_external
|
140
|
+
|
141
|
+
def with_default_internal(enc)
|
142
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
143
|
+
origenc, Encoding.default_internal = Encoding.default_internal, enc
|
144
|
+
$VERBOSE = verbose
|
145
|
+
yield
|
146
|
+
ensure
|
147
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
148
|
+
Encoding.default_internal = origenc
|
149
|
+
$VERBOSE = verbose
|
150
|
+
end
|
151
|
+
module_function :with_default_internal
|
152
|
+
end
|
153
|
+
|
154
|
+
module Test
|
155
|
+
module Unit
|
156
|
+
module Assertions
|
157
|
+
public
|
158
|
+
def assert_valid_syntax(code, fname = caller_locations(1, 1)[0], mesg = fname.to_s)
|
159
|
+
code = code.dup.force_encoding("ascii-8bit")
|
160
|
+
code.sub!(/\A(?:\xef\xbb\xbf)?(\s*\#.*$)*(\n)?/n) {
|
161
|
+
"#$&#{"\n" if $1 && !$2}BEGIN{throw tag, :ok}\n"
|
162
|
+
}
|
163
|
+
code.force_encoding("us-ascii")
|
164
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
165
|
+
yield if defined?(yield)
|
166
|
+
case
|
167
|
+
when Array === fname
|
168
|
+
fname, line = *fname
|
169
|
+
when defined?(fname.path) && defined?(fname.lineno)
|
170
|
+
fname, line = fname.path, fname.lineno
|
171
|
+
else
|
172
|
+
line = 0
|
173
|
+
end
|
174
|
+
assert_nothing_raised(SyntaxError, mesg) do
|
175
|
+
assert_equal(:ok, catch {|tag| eval(code, binding, fname, line)}, mesg)
|
176
|
+
end
|
177
|
+
ensure
|
178
|
+
$VERBOSE = verbose
|
179
|
+
end
|
180
|
+
|
181
|
+
def assert_syntax_error(code, error, fname = caller_locations(1, 1)[0], mesg = fname.to_s)
|
182
|
+
code = code.dup.force_encoding("ascii-8bit")
|
183
|
+
code.sub!(/\A(?:\xef\xbb\xbf)?(\s*\#.*$)*(\n)?/n) {
|
184
|
+
"#$&#{"\n" if $1 && !$2}BEGIN{throw tag, :ng}\n"
|
185
|
+
}
|
186
|
+
code.force_encoding("us-ascii")
|
187
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
188
|
+
yield if defined?(yield)
|
189
|
+
case
|
190
|
+
when Array === fname
|
191
|
+
fname, line = *fname
|
192
|
+
when defined?(fname.path) && defined?(fname.lineno)
|
193
|
+
fname, line = fname.path, fname.lineno
|
194
|
+
else
|
195
|
+
line = 0
|
196
|
+
end
|
197
|
+
e = assert_raise(SyntaxError, mesg) do
|
198
|
+
catch {|tag| eval(code, binding, fname, line)}
|
199
|
+
end
|
200
|
+
assert_match(error, e.message, mesg)
|
201
|
+
ensure
|
202
|
+
$VERBOSE = verbose
|
203
|
+
end
|
204
|
+
|
205
|
+
def assert_normal_exit(testsrc, message = '', child_env: nil, **opt)
|
206
|
+
assert_valid_syntax(testsrc, caller_locations(1, 1)[0])
|
207
|
+
if child_env
|
208
|
+
child_env = [child_env]
|
209
|
+
else
|
210
|
+
child_env = []
|
211
|
+
end
|
212
|
+
out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, opt)
|
213
|
+
assert !status.signaled?, FailDesc[status, message, out]
|
214
|
+
end
|
215
|
+
|
216
|
+
FailDesc = proc do |status, message = "", out = ""|
|
217
|
+
pid = status.pid
|
218
|
+
faildesc = proc do
|
219
|
+
signo = status.termsig
|
220
|
+
signame = Signal.list.invert[signo]
|
221
|
+
sigdesc = "signal #{signo}"
|
222
|
+
if signame
|
223
|
+
sigdesc = "SIG#{signame} (#{sigdesc})"
|
224
|
+
end
|
225
|
+
if status.coredump?
|
226
|
+
sigdesc << " (core dumped)"
|
227
|
+
end
|
228
|
+
full_message = ''
|
229
|
+
if message and !message.empty?
|
230
|
+
full_message << message << "\n"
|
231
|
+
end
|
232
|
+
full_message << "pid #{pid} killed by #{sigdesc}"
|
233
|
+
if out and !out.empty?
|
234
|
+
full_message << "\n#{out.gsub(/^/, '| ')}"
|
235
|
+
full_message << "\n" if /\n\z/ !~ full_message
|
236
|
+
end
|
237
|
+
full_message
|
238
|
+
end
|
239
|
+
faildesc
|
240
|
+
end
|
241
|
+
|
242
|
+
def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, **opt)
|
243
|
+
stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, opt)
|
244
|
+
if block_given?
|
245
|
+
raise "test_stdout ignored, use block only or without block" if test_stdout != []
|
246
|
+
raise "test_stderr ignored, use block only or without block" if test_stderr != []
|
247
|
+
yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp }, status)
|
248
|
+
else
|
249
|
+
errs = []
|
250
|
+
[[test_stdout, stdout], [test_stderr, stderr]].each do |exp, act|
|
251
|
+
begin
|
252
|
+
if exp.is_a?(Regexp)
|
253
|
+
assert_match(exp, act, message)
|
254
|
+
else
|
255
|
+
assert_equal(exp, act.lines.map {|l| l.chomp }, message)
|
256
|
+
end
|
257
|
+
rescue MiniTest::Assertion => e
|
258
|
+
errs << e.message
|
259
|
+
message = nil
|
260
|
+
end
|
261
|
+
end
|
262
|
+
raise MiniTest::Assertion, errs.join("\n---\n") unless errs.empty?
|
263
|
+
status
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
def assert_ruby_status(args, test_stdin="", message=nil, **opt)
|
268
|
+
out, _, status = EnvUtil.invoke_ruby(args, test_stdin, true, :merge_to_stdout, opt)
|
269
|
+
message ||= "ruby exit status is not success:"
|
270
|
+
assert(status.success?, FailDesc[status, message, out])
|
271
|
+
end
|
272
|
+
|
273
|
+
ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV")
|
274
|
+
|
275
|
+
def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt)
|
276
|
+
unless file and line
|
277
|
+
loc, = caller_locations(1,1)
|
278
|
+
file ||= loc.path
|
279
|
+
line ||= loc.lineno
|
280
|
+
end
|
281
|
+
src = <<eom
|
282
|
+
require 'test/unit';include Test::Unit::Assertions;begin;#{src}
|
283
|
+
ensure
|
284
|
+
puts [Marshal.dump($!)].pack('m'), "assertions=\#{self._assertions}"
|
285
|
+
end
|
286
|
+
class Test::Unit::Runner
|
287
|
+
@@stop_auto_run = true
|
288
|
+
end
|
289
|
+
eom
|
290
|
+
args = args.dup
|
291
|
+
$:.each{|l| args.unshift "-I#{l}" }
|
292
|
+
stdout, stderr, status = EnvUtil.invoke_ruby(args, src, true, true, opt)
|
293
|
+
abort = status.coredump? || (status.signaled? && ABORT_SIGNALS.include?(status.termsig))
|
294
|
+
assert(!abort, FailDesc[status, stderr])
|
295
|
+
self._assertions += stdout[/^assertions=(\d+)/, 1].to_i
|
296
|
+
res = Marshal.load(stdout.unpack("m")[0])
|
297
|
+
if res
|
298
|
+
res.backtrace.each do |l|
|
299
|
+
l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"}
|
300
|
+
end
|
301
|
+
raise res
|
302
|
+
end
|
303
|
+
|
304
|
+
# really is it succeed?
|
305
|
+
unless ignore_stderr
|
306
|
+
# the body of assert_separately must not output anything to detect errror
|
307
|
+
assert_equal("", stderr, "assert_separately failed with error message")
|
308
|
+
end
|
309
|
+
assert_equal(0, status, "assert_separately failed: '#{stderr}'")
|
310
|
+
end
|
311
|
+
|
312
|
+
def assert_warning(pat, message = nil)
|
313
|
+
stderr = EnvUtil.verbose_warning { yield }
|
314
|
+
message = ' "' + message + '"' if message
|
315
|
+
msg = proc {"warning message #{stderr.inspect} is expected to match #{pat.inspect}#{message}"}
|
316
|
+
assert(pat === stderr, msg)
|
317
|
+
end
|
318
|
+
|
319
|
+
def assert_warn(*args)
|
320
|
+
assert_warning(*args) {$VERBOSE = false; yield}
|
321
|
+
end
|
322
|
+
|
323
|
+
def assert_no_memory_leak(args, prepare, code, message=nil, limit: 1.5)
|
324
|
+
token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m"
|
325
|
+
token_dump = token.dump
|
326
|
+
token_re = Regexp.quote(token)
|
327
|
+
args = [
|
328
|
+
"--disable=gems",
|
329
|
+
"-r", File.expand_path("../memory_status", __FILE__),
|
330
|
+
*args,
|
331
|
+
"-v", "-",
|
332
|
+
]
|
333
|
+
cmd = [
|
334
|
+
'END {STDERR.puts '"#{token_dump}"'"FINAL=#{Memory::Status.new.size}"}',
|
335
|
+
prepare,
|
336
|
+
'STDERR.puts('"#{token_dump}"'"START=#{$initial_size = Memory::Status.new.size}")',
|
337
|
+
code,
|
338
|
+
].join("\n")
|
339
|
+
_, err, status = EnvUtil.invoke_ruby(args, cmd, true, true)
|
340
|
+
before = err.sub!(/^#{token_re}START=(\d+)\n/, '') && $1.to_i
|
341
|
+
after = err.sub!(/^#{token_re}FINAL=(\d+)\n/, '') && $1.to_i
|
342
|
+
assert_equal([true, ""], [status.success?, err], message)
|
343
|
+
assert_operator(after.fdiv(before), :<, limit, message)
|
344
|
+
end
|
345
|
+
|
346
|
+
def assert_is_minus_zero(f)
|
347
|
+
assert(1.0/f == -Float::INFINITY, "#{f} is not -0.0")
|
348
|
+
end
|
349
|
+
|
350
|
+
def assert_file
|
351
|
+
AssertFile
|
352
|
+
end
|
353
|
+
|
354
|
+
class << (AssertFile = Struct.new(:message).new)
|
355
|
+
include Assertions
|
356
|
+
def assert_file_predicate(predicate, *args)
|
357
|
+
if /\Anot_/ =~ predicate
|
358
|
+
predicate = $'
|
359
|
+
neg = " not"
|
360
|
+
end
|
361
|
+
result = File.__send__(predicate, *args)
|
362
|
+
result = !result if neg
|
363
|
+
mesg = "Expected file " << args.shift.inspect
|
364
|
+
mesg << mu_pp(args) unless args.empty?
|
365
|
+
mesg << "#{neg} to be #{predicate}"
|
366
|
+
mesg << " #{message}" if message
|
367
|
+
assert(result, mesg)
|
368
|
+
end
|
369
|
+
alias method_missing assert_file_predicate
|
370
|
+
|
371
|
+
def for(message)
|
372
|
+
clone.tap {|a| a.message = message}
|
373
|
+
end
|
374
|
+
end
|
375
|
+
end
|
376
|
+
end
|
377
|
+
end
|
378
|
+
|
379
|
+
begin
|
380
|
+
require 'rbconfig'
|
381
|
+
rescue LoadError
|
382
|
+
else
|
383
|
+
module RbConfig
|
384
|
+
@ruby = EnvUtil.rubybin
|
385
|
+
class << self
|
386
|
+
undef ruby if method_defined?(:ruby)
|
387
|
+
attr_reader :ruby
|
388
|
+
end
|
389
|
+
dir = File.dirname(ruby)
|
390
|
+
name = File.basename(ruby, CONFIG['EXEEXT'])
|
391
|
+
CONFIG['bindir'] = dir
|
392
|
+
CONFIG['ruby_install_name'] = name
|
393
|
+
CONFIG['RUBY_INSTALL_NAME'] = name
|
394
|
+
Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap)
|
395
|
+
end
|
396
|
+
end
|