structx 0.1.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.
- data/.gitignore +19 -0
- data/.simplecov +8 -0
- data/.travis.yml +8 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +22 -0
- data/README.md +61 -0
- data/Rakefile +18 -0
- data/lib/structx.rb +169 -0
- data/lib/structx/version.rb +4 -0
- data/structx.gemspec +29 -0
- data/test/compatibility-test.rb +32 -0
- data/test/ruby/1.9/envutil.rb +212 -0
- data/test/ruby/1.9/test_struct.rb +252 -0
- data/test/ruby/2.0/envutil.rb +362 -0
- data/test/ruby/2.0/test_struct.rb +284 -0
- data/test/run.sh +12 -0
- data/test/spec_structx.rb +193 -0
- metadata +166 -0
data/.gitignore
ADDED
data/.simplecov
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2013 Keita Yamaguchi
|
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,61 @@
|
|
1
|
+
# StructX
|
2
|
+
|
3
|
+
StructX is an extension of Ruby standard Struct. The diffences are that 1) the constructor handles hash table as key-value pairs, 2) you can specify members as statements, and 3) you can set default values of member. StructX's API is compatible with Struct.
|
4
|
+
|
5
|
+
[](http://badge.fury.io/rb/structx) [](https://travis-ci.org/keita/structx) [](https://coveralls.io/r/keita/structx) [](https://codeclimate.com/github/keita/structx)
|
6
|
+
|
7
|
+
## Installation
|
8
|
+
|
9
|
+
$ gem install structx
|
10
|
+
|
11
|
+
## Usage
|
12
|
+
|
13
|
+
### Constructor with hash table
|
14
|
+
|
15
|
+
```ruby
|
16
|
+
StructX.new(:x, :y, :z).new(x: 1, y: 2, z: 3) #=> #<struct x=1, y=10, z=100>
|
17
|
+
```
|
18
|
+
|
19
|
+
### Member sentences
|
20
|
+
|
21
|
+
```ruby
|
22
|
+
class A < StructX
|
23
|
+
member :x
|
24
|
+
member :y
|
25
|
+
member :z
|
26
|
+
end
|
27
|
+
A.new(1, 2, 3) #=> #<struct A x=1, y=2, z=3>
|
28
|
+
```
|
29
|
+
|
30
|
+
### Default values
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
class B < StructX
|
34
|
+
member :x
|
35
|
+
member :y, default: 10
|
36
|
+
member :z, default: 100
|
37
|
+
end
|
38
|
+
B.new(1) # => #<struct B x=1, y=10, z=100>
|
39
|
+
```
|
40
|
+
|
41
|
+
## Documentation
|
42
|
+
|
43
|
+
- [API Documentation](http://rubydoc.info/gems/structx)
|
44
|
+
|
45
|
+
## License
|
46
|
+
|
47
|
+
StructX is free software distributed under MIT license.
|
48
|
+
The following files are copied from ruby's test case, so you should keep its lisense.
|
49
|
+
|
50
|
+
- test/ruby/1.9/test_struct.rb
|
51
|
+
- test/ruby/1.9/envutil.rb
|
52
|
+
- test/ruby/2.0/test_struct.rb
|
53
|
+
- test/ruby/2.0/envutil.rb
|
54
|
+
|
55
|
+
## Contributing
|
56
|
+
|
57
|
+
1. Fork it
|
58
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
59
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
60
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
61
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
desc 'Test specs'
|
4
|
+
task 'test' do
|
5
|
+
sh "test/run.sh"
|
6
|
+
end
|
7
|
+
|
8
|
+
desc 'Generate API document'
|
9
|
+
task 'html' do
|
10
|
+
sh "bundle exec yard doc -o html --hide-void-return --no-api"
|
11
|
+
end
|
12
|
+
|
13
|
+
desc 'Show undocumented function list'
|
14
|
+
task 'html:undoc' do
|
15
|
+
sh "bundle exec yard stats --list-undoc --no-api --compact"
|
16
|
+
end
|
17
|
+
|
18
|
+
task :default => :test
|
data/lib/structx.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
require "forwardablex"
|
2
|
+
require "structx/version"
|
3
|
+
|
4
|
+
# StructX is an extension of Ruby standard Struct. The diffences are that 1) the
|
5
|
+
# constructor handles hash table as key-value pairs, 2) you can specify members
|
6
|
+
# as statements, and 3) you can set default values of member. StructX's API is
|
7
|
+
# compatible with Struct.
|
8
|
+
#
|
9
|
+
# @example Constructor with hash table
|
10
|
+
# StructX.new(:x, :y, :z).new(x: 1, y: 2, z: 3) #=> #<struct x=1, y=10, z=100>
|
11
|
+
# @example Member sentences
|
12
|
+
# class A < StructX
|
13
|
+
# member :x
|
14
|
+
# member :y
|
15
|
+
# member :z
|
16
|
+
# end
|
17
|
+
# A.new(1, 2, 3) #=> #<struct A x=1, y=2, z=3>
|
18
|
+
# @example Default values
|
19
|
+
# class B < StructX
|
20
|
+
# member :x
|
21
|
+
# member :y, default: 10
|
22
|
+
# member :z, default: 100
|
23
|
+
# end
|
24
|
+
# B.new(1) # => #<struct B x=1, y=10, z=100>
|
25
|
+
class StructX
|
26
|
+
include Enumerable
|
27
|
+
|
28
|
+
class << self
|
29
|
+
alias :orig_new :new
|
30
|
+
private :orig_new
|
31
|
+
|
32
|
+
# Same as Struct[].
|
33
|
+
alias :[] :new
|
34
|
+
|
35
|
+
# Create a instance or sublcass. If this class has members, create an
|
36
|
+
# instance. The case handles hash table as key-value pairs. If this class
|
37
|
+
# has no members, create a subclass.
|
38
|
+
#
|
39
|
+
# @param args [Array or Hash]
|
40
|
+
# Same as Struct if args is Array. Consider args as key-value pairs if it is Hash.
|
41
|
+
def new(*args)
|
42
|
+
# create an instance
|
43
|
+
return orig_new(*args) if @member
|
44
|
+
|
45
|
+
# create subclass
|
46
|
+
Class.new(StructX).tap do |subclass|
|
47
|
+
# class name
|
48
|
+
if args.first.kind_of?(String)
|
49
|
+
const_set(args.first, subclass)
|
50
|
+
args = args.drop(1)
|
51
|
+
end
|
52
|
+
|
53
|
+
# set members
|
54
|
+
args.each {|m| subclass.member(*m)}
|
55
|
+
|
56
|
+
# this is according to MRI, why yield?
|
57
|
+
yield if block_given?
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# Same as Struct#members.
|
62
|
+
def members
|
63
|
+
(@member ||= {}).keys
|
64
|
+
end
|
65
|
+
|
66
|
+
# Add member into structure.
|
67
|
+
#
|
68
|
+
# @param name [Symbol]
|
69
|
+
# member name
|
70
|
+
# @param data [Hash]
|
71
|
+
# member options
|
72
|
+
def member(name, data={})
|
73
|
+
(@member ||= {})[name] = Hash.new.merge(data)
|
74
|
+
|
75
|
+
# define member's value reader
|
76
|
+
define_method(name) do
|
77
|
+
@value[name]
|
78
|
+
end
|
79
|
+
|
80
|
+
# define member's value writer
|
81
|
+
define_method("%s=" % name) do |val|
|
82
|
+
@value[name] = val
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# Return default values.
|
87
|
+
#
|
88
|
+
# @return [Hash{Symbol=>Object}]
|
89
|
+
# default values
|
90
|
+
def default_values
|
91
|
+
@member.inject({}) do |tbl, (key, val)|
|
92
|
+
tbl.tap {|x| x[key] = val[:default] if val.has_key?(:default)}
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
private
|
97
|
+
|
98
|
+
def inherited(subclass)
|
99
|
+
@member.each {|key, data| subclass.member(key, data)} if @member
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
# almost methods are forwarded to value table
|
104
|
+
forward :class, :members
|
105
|
+
forward :@value, :each, :each_pair
|
106
|
+
forward! :@value, :values, :length, :size, :hash
|
107
|
+
forward! lambda{|x| @value.values}, :each, :values_at
|
108
|
+
|
109
|
+
alias :to_a :values
|
110
|
+
|
111
|
+
# See Struct.new.
|
112
|
+
def initialize(*values)
|
113
|
+
if values.first.kind_of?(Hash) and values.size == 1
|
114
|
+
@value = __build__(values.first)
|
115
|
+
else
|
116
|
+
raise ArgumentError.new("struct size differs #{values} #{members} ") if values.size > members.size
|
117
|
+
@value = __build__(members.zip(values))
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Same as Struct#[].
|
122
|
+
def [](idx)
|
123
|
+
case idx
|
124
|
+
when Integer
|
125
|
+
size > idx && -size <= idx ? values[idx] : (raise IndexError.new(idx))
|
126
|
+
when Symbol, String
|
127
|
+
members.include?(idx.to_sym) ? @value[idx.to_sym] : (raise NameError.new(idx.to_s))
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Same as Struct#[]=.
|
132
|
+
def []=(idx, val)
|
133
|
+
case idx
|
134
|
+
when Integer
|
135
|
+
size > idx && -size <= idx ? @value[members[idx]] = val : (raise IndexError.new(idx))
|
136
|
+
when Symbol, String
|
137
|
+
members.include?(idx.to_sym) ? @value[idx.to_sym] = val : (raise NameError.new(idx.to_s))
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
# Same as Struct#inspect.
|
142
|
+
def inspect
|
143
|
+
name = self.class.inspect[0] == "#" ? "" : " " + self.class.inspect
|
144
|
+
values = @value.map do |key, val|
|
145
|
+
k = (key.to_s[0] == "@" ? ":" : "") + key.to_s
|
146
|
+
v = self == val ? "#<struct %s:...>" % val : val.inspect
|
147
|
+
"%s=%s" % [k, v]
|
148
|
+
end
|
149
|
+
"#<struct%s %s>" % [name, values.join(", ")]
|
150
|
+
end
|
151
|
+
|
152
|
+
# Same as Struct#eql?.
|
153
|
+
def eql?(other)
|
154
|
+
self.class == other.class and @value == other.to_h
|
155
|
+
end
|
156
|
+
alias :"==" :eql?
|
157
|
+
|
158
|
+
# Same as Struct#to_h. This method is available in Ruby 1.9 too.
|
159
|
+
def to_h
|
160
|
+
@value
|
161
|
+
end
|
162
|
+
|
163
|
+
private
|
164
|
+
|
165
|
+
def __build__(data)
|
166
|
+
tbl = data.inject({}) {|tbl, (m, val)| tbl.tap {|x| x[m] = val if val}}
|
167
|
+
self.class.default_values.merge(tbl)
|
168
|
+
end
|
169
|
+
end
|
data/structx.gemspec
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# -*- ruby -*-
|
2
|
+
# coding: utf-8
|
3
|
+
lib = File.expand_path('../lib', __FILE__)
|
4
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
+
require 'structx/version'
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "structx"
|
9
|
+
spec.version = StructX::VERSION
|
10
|
+
spec.authors = ["Keita Yamaguchi"]
|
11
|
+
spec.email = ["keita.yamaguchi@gmail.com"]
|
12
|
+
spec.description = "sturctx is a Ruby library that extends standard Struct"
|
13
|
+
spec.summary = "sturctx is a Ruby library that extends standard Struct"
|
14
|
+
spec.homepage = "https://github.com/keita/structx"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files`.split($/)
|
18
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
19
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_dependency "forwardablex"
|
23
|
+
|
24
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
25
|
+
spec.add_development_dependency "rake"
|
26
|
+
spec.add_development_dependency "bacon"
|
27
|
+
spec.add_development_dependency "yard"
|
28
|
+
spec.add_development_dependency "ruby-version"
|
29
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "structx"
|
2
|
+
require "ruby-version"
|
3
|
+
|
4
|
+
def patch(code)
|
5
|
+
## Struct -> StructX
|
6
|
+
code = code.gsub("Struct", "StructX")
|
7
|
+
## clear require_relative
|
8
|
+
code = code.gsub(/^require_relative.*$/, "")
|
9
|
+
## modify error message for test_struct_subclass
|
10
|
+
# StructX can handle security error but the message is different
|
11
|
+
code = code.gsub("Insecure: can't modify \#\{st}::S", "Insecure: can't modify hash")
|
12
|
+
end
|
13
|
+
|
14
|
+
def load_test(target)
|
15
|
+
require_relative "../test/ruby/#{target}/envutil"
|
16
|
+
path = File.join(File.dirname(__FILE__), "ruby", target, "test_struct.rb")
|
17
|
+
eval patch(File.read(path))
|
18
|
+
end
|
19
|
+
|
20
|
+
if Ruby::Engine::NAME == "ruby"
|
21
|
+
if Ruby::Version >= "1.9" and Ruby::Version < "2.0"
|
22
|
+
load_test("1.9")
|
23
|
+
end
|
24
|
+
|
25
|
+
if Ruby::Version >= "2.0"
|
26
|
+
load_test("2.0")
|
27
|
+
end
|
28
|
+
else
|
29
|
+
puts "We cannot run compatibility test with jruby and rbx."
|
30
|
+
puts "Related to Struct, these VMs are not compatible with MRI."
|
31
|
+
end
|
32
|
+
|
@@ -0,0 +1,212 @@
|
|
1
|
+
require "open3"
|
2
|
+
require "timeout"
|
3
|
+
|
4
|
+
module EnvUtil
|
5
|
+
def rubybin
|
6
|
+
unless ENV["RUBYOPT"]
|
7
|
+
|
8
|
+
end
|
9
|
+
if ruby = ENV["RUBY"]
|
10
|
+
return ruby
|
11
|
+
end
|
12
|
+
ruby = "ruby"
|
13
|
+
rubyexe = ruby+".exe"
|
14
|
+
3.times do
|
15
|
+
if File.exist? ruby and File.executable? ruby and !File.directory? ruby
|
16
|
+
return File.expand_path(ruby)
|
17
|
+
end
|
18
|
+
if File.exist? rubyexe and File.executable? rubyexe
|
19
|
+
return File.expand_path(rubyexe)
|
20
|
+
end
|
21
|
+
ruby = File.join("..", ruby)
|
22
|
+
end
|
23
|
+
if defined?(RbConfig.ruby)
|
24
|
+
RbConfig.ruby
|
25
|
+
else
|
26
|
+
"ruby"
|
27
|
+
end
|
28
|
+
end
|
29
|
+
module_function :rubybin
|
30
|
+
|
31
|
+
LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
|
32
|
+
|
33
|
+
def invoke_ruby(args, stdin_data="", capture_stdout=false, capture_stderr=false, opt={})
|
34
|
+
in_c, in_p = IO.pipe
|
35
|
+
out_p, out_c = IO.pipe if capture_stdout
|
36
|
+
err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
|
37
|
+
opt = opt.dup
|
38
|
+
opt[:in] = in_c
|
39
|
+
opt[:out] = out_c if capture_stdout
|
40
|
+
opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr
|
41
|
+
if enc = opt.delete(:encoding)
|
42
|
+
out_p.set_encoding(enc) if out_p
|
43
|
+
err_p.set_encoding(enc) if err_p
|
44
|
+
end
|
45
|
+
timeout = opt.delete(:timeout) || 10
|
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
|
+
raise Timeout::Error
|
69
|
+
end
|
70
|
+
out_p.close if capture_stdout
|
71
|
+
err_p.close if capture_stderr && capture_stderr != :merge_to_stdout
|
72
|
+
Process.wait pid
|
73
|
+
status = $?
|
74
|
+
return stdout, stderr, status
|
75
|
+
end
|
76
|
+
ensure
|
77
|
+
[in_c, in_p, out_c, out_p, err_c, err_p].each do |io|
|
78
|
+
io.close if io && !io.closed?
|
79
|
+
end
|
80
|
+
[th_stdout, th_stderr].each do |th|
|
81
|
+
(th.kill; th.join) if th
|
82
|
+
end
|
83
|
+
end
|
84
|
+
module_function :invoke_ruby
|
85
|
+
|
86
|
+
alias rubyexec invoke_ruby
|
87
|
+
class << self
|
88
|
+
alias rubyexec invoke_ruby
|
89
|
+
end
|
90
|
+
|
91
|
+
def verbose_warning
|
92
|
+
class << (stderr = "")
|
93
|
+
alias write <<
|
94
|
+
end
|
95
|
+
stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
|
96
|
+
yield stderr
|
97
|
+
ensure
|
98
|
+
stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
|
99
|
+
return stderr
|
100
|
+
end
|
101
|
+
module_function :verbose_warning
|
102
|
+
|
103
|
+
def suppress_warning
|
104
|
+
verbose, $VERBOSE = $VERBOSE, nil
|
105
|
+
yield
|
106
|
+
ensure
|
107
|
+
$VERBOSE = verbose
|
108
|
+
end
|
109
|
+
module_function :suppress_warning
|
110
|
+
|
111
|
+
def under_gc_stress
|
112
|
+
stress, GC.stress = GC.stress, true
|
113
|
+
yield
|
114
|
+
ensure
|
115
|
+
GC.stress = stress
|
116
|
+
end
|
117
|
+
module_function :under_gc_stress
|
118
|
+
end
|
119
|
+
|
120
|
+
module Test
|
121
|
+
module Unit
|
122
|
+
module Assertions
|
123
|
+
public
|
124
|
+
def assert_normal_exit(testsrc, message = '', opt = {})
|
125
|
+
if opt.include?(:child_env)
|
126
|
+
opt = opt.dup
|
127
|
+
child_env = [opt.delete(:child_env)] || []
|
128
|
+
else
|
129
|
+
child_env = []
|
130
|
+
end
|
131
|
+
out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, opt)
|
132
|
+
pid = status.pid
|
133
|
+
faildesc = proc do
|
134
|
+
signo = status.termsig
|
135
|
+
signame = Signal.list.invert[signo]
|
136
|
+
sigdesc = "signal #{signo}"
|
137
|
+
if signame
|
138
|
+
sigdesc = "SIG#{signame} (#{sigdesc})"
|
139
|
+
end
|
140
|
+
if status.coredump?
|
141
|
+
sigdesc << " (core dumped)"
|
142
|
+
end
|
143
|
+
full_message = ''
|
144
|
+
if !message.empty?
|
145
|
+
full_message << message << "\n"
|
146
|
+
end
|
147
|
+
full_message << "pid #{pid} killed by #{sigdesc}"
|
148
|
+
if !out.empty?
|
149
|
+
out << "\n" if /\n\z/ !~ out
|
150
|
+
full_message << "\n#{out.gsub(/^/, '| ')}"
|
151
|
+
end
|
152
|
+
full_message
|
153
|
+
end
|
154
|
+
assert !status.signaled?, faildesc
|
155
|
+
end
|
156
|
+
|
157
|
+
def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, opt={})
|
158
|
+
stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, opt)
|
159
|
+
if block_given?
|
160
|
+
yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp })
|
161
|
+
else
|
162
|
+
if test_stdout.is_a?(Regexp)
|
163
|
+
assert_match(test_stdout, stdout, message)
|
164
|
+
else
|
165
|
+
assert_equal(test_stdout, stdout.lines.map {|l| l.chomp }, message)
|
166
|
+
end
|
167
|
+
if test_stderr.is_a?(Regexp)
|
168
|
+
assert_match(test_stderr, stderr, message)
|
169
|
+
else
|
170
|
+
assert_equal(test_stderr, stderr.lines.map {|l| l.chomp }, message)
|
171
|
+
end
|
172
|
+
status
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
def assert_ruby_status(args, test_stdin="", message=nil, opt={})
|
177
|
+
_, _, status = EnvUtil.invoke_ruby(args, test_stdin, false, false, opt)
|
178
|
+
m = message ? "#{message} (#{status.inspect})" : "ruby exit status is not success: #{status.inspect}"
|
179
|
+
assert(status.success?, m)
|
180
|
+
end
|
181
|
+
|
182
|
+
def assert_warn(msg)
|
183
|
+
stderr = EnvUtil.verbose_warning { yield }
|
184
|
+
assert(msg === stderr, "warning message #{stderr.inspect} is expected to match #{msg.inspect}")
|
185
|
+
end
|
186
|
+
|
187
|
+
|
188
|
+
def assert_is_minus_zero(f)
|
189
|
+
assert(1.0/f == -Float::INFINITY, "#{f} is not -0.0")
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
begin
|
196
|
+
require 'rbconfig'
|
197
|
+
rescue LoadError
|
198
|
+
else
|
199
|
+
module RbConfig
|
200
|
+
@ruby = EnvUtil.rubybin
|
201
|
+
class << self
|
202
|
+
undef ruby if method_defined?(:ruby)
|
203
|
+
attr_reader :ruby
|
204
|
+
end
|
205
|
+
dir = File.dirname(ruby)
|
206
|
+
name = File.basename(ruby, CONFIG['EXEEXT'])
|
207
|
+
CONFIG['bindir'] = dir
|
208
|
+
CONFIG['ruby_install_name'] = name
|
209
|
+
CONFIG['RUBY_INSTALL_NAME'] = name
|
210
|
+
Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap)
|
211
|
+
end
|
212
|
+
end
|