From 33663e2c50eb8496b81750976b3480c14783470d Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 22 Dec 2022 19:48:22 +0900 Subject: [PATCH 01/18] Add `helper.bump` --- rakelib/version.rake | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/rakelib/version.rake b/rakelib/version.rake index f3557a7..eb430b0 100644 --- a/rakelib/version.rake +++ b/rakelib/version.rake @@ -24,20 +24,24 @@ class << (helper = Bundler::GemHelper.instance) update_version commit_bump end + + def bump(major, minor = 0, teeny = 0, pre: nil) + self.version = [major, minor, teeny, pre].compact.join(".") + end end major, minor, teeny = helper.gemspec.version.segments -task "bump:teeny" do - helper.version = Gem::Version.new("#{major}.#{minor}.#{teeny+1}") +task "bump:teeny", [:pre] do |t, pre: nil| + helper.bump(major, minor, teeny+1, pre: pre) end -task "bump:minor" do - helper.version = Gem::Version.new("#{major}.#{minor+1}.0") +task "bump:minor", [:pre] do |t, pre: nil| + helper.bump(major, minor+1, pre: pre) end -task "bump:major" do - helper.version = Gem::Version.new("#{major+1}.0.0") +task "bump:major", [:pre] do |t, pre: nil| + helper.bump(major+1, pre: pre) end task "bump" => "bump:teeny" From ab0022bd23d77e515390cbb2c165f7647400be46 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 29 Sep 2021 11:47:47 +0900 Subject: [PATCH 02/18] Cron test --- .github/workflows/test.yml | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 00610d3..db5d08f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,6 +1,11 @@ name: test -on: [push, pull_request] +on: + push: + pull_request: + workflow_dispatch: + schedule: + - cron: '3 11 * * 4' jobs: ruby-versions: From 697ea7bf8e343704e735fb2d1f7787d96b843469 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 22 Dec 2022 19:55:51 +0900 Subject: [PATCH 03/18] Add .rdoc_options --- .rdoc_options | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 .rdoc_options diff --git a/.rdoc_options b/.rdoc_options new file mode 100644 index 0000000..79a8fce --- /dev/null +++ b/.rdoc_options @@ -0,0 +1,4 @@ +--- +page_dir: doc +main_page: README.md +title: Documentation for OptionParser From 73661899ad17e1061c7fc0f88cc4ac4e66a3c9a9 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Thu, 22 Dec 2022 19:57:30 +0900 Subject: [PATCH 04/18] bump up to 0.4.0.pre.1 --- lib/optparse.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/optparse.rb b/lib/optparse.rb index 53a4387..26683ef 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -425,7 +425,7 @@ # If you have any questions, file a ticket at http://bugs.ruby-lang.org. # class OptionParser - OptionParser::Version = "0.3.1" + OptionParser::Version = "0.4.0.pre.1" # :stopdoc: NoArgument = [NO_ARGUMENT = :NONE, nil].freeze From 3e63d878f895a299a6ddeee5f8c615b69edf401c Mon Sep 17 00:00:00 2001 From: Junichi Ito Date: Tue, 29 Nov 2022 08:07:47 +0900 Subject: [PATCH 05/18] Add symbolize_names to getopts --- lib/optparse.rb | 21 +++++++++++++++------ test/optparse/test_getopts.rb | 16 ++++++++++++++++ 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/lib/optparse.rb b/lib/optparse.rb index 26683ef..7e0479b 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -1775,7 +1775,16 @@ def parse!(argv = default_argv, into: nil) # # params["bar"] = "x" # --bar x # # params["zot"] = "z" # --zot Z # - def getopts(*args) + # Option +symbolize_names+ (boolean) specifies whether returned Hash keys should be Symbols; defaults to +false+ (use Strings). + # + # params = ARGV.getopts("ab:", "foo", "bar:", "zot:Z;zot option", symbolize_names: true) + # # params[:a] = true # -a + # # params[:b] = "1" # -b1 + # # params[:foo] = "1" # --foo + # # params[:bar] = "x" # --bar x + # # params[:zot] = "z" # --zot Z + # + def getopts(*args, symbolize_names: false) argv = Array === args.first ? args.shift : default_argv single_options, *long_options = *args @@ -1804,14 +1813,14 @@ def getopts(*args) end parse_in_order(argv, result.method(:[]=)) - result + symbolize_names ? result.transform_keys(&:to_sym) : result end # # See #getopts. # - def self.getopts(*args) - new.getopts(*args) + def self.getopts(*args, symbolize_names: false) + new.getopts(*args, symbolize_names: symbolize_names) end # @@ -2289,8 +2298,8 @@ def parse!() options.parse!(self) end # rescue OptionParser::ParseError # end # - def getopts(*args) - options.getopts(self, *args) + def getopts(*args, symbolize_names: false) + options.getopts(self, *args, symbolize_names: symbolize_names) end # diff --git a/test/optparse/test_getopts.rb b/test/optparse/test_getopts.rb index 7d9160f..4a0ae28 100644 --- a/test/optparse/test_getopts.rb +++ b/test/optparse/test_getopts.rb @@ -11,23 +11,39 @@ def test_short_noarg o = @opt.getopts(%w[-a], "ab") assert_equal(true, o['a']) assert_equal(false, o['b']) + + o = @opt.getopts(%w[-a], "ab", symbolize_names: true) + assert_equal(true, o[:a]) + assert_equal(false, o[:b]) end def test_short_arg o = @opt.getopts(%w[-a1], "a:b:") assert_equal("1", o['a']) assert_equal(nil, o['b']) + + o = @opt.getopts(%w[-a1], "a:b:", symbolize_names: true) + assert_equal("1", o[:a]) + assert_equal(nil, o[:b]) end def test_long_noarg o = @opt.getopts(%w[--foo], "", "foo", "bar") assert_equal(true, o['foo']) assert_equal(false, o['bar']) + + o = @opt.getopts(%w[--foo], "", "foo", "bar", symbolize_names: true) + assert_equal(true, o[:foo]) + assert_equal(false, o[:bar]) end def test_long_arg o = @opt.getopts(%w[--bar ZOT], "", "foo:FOO", "bar:BAR") assert_equal("FOO", o['foo']) assert_equal("ZOT", o['bar']) + + o = @opt.getopts(%w[--bar ZOT], "", "foo:FOO", "bar:BAR", symbolize_names: true) + assert_equal("FOO", o[:foo]) + assert_equal("ZOT", o[:bar]) end end From 366a6a6b569037420013e83ada92012d0c6a2f76 Mon Sep 17 00:00:00 2001 From: Keishi Tanaka Date: Sat, 21 Jan 2023 14:09:00 +0900 Subject: [PATCH 06/18] Migrate set-output to $GITHUB_OUTPUT (#50) https://github.blog/changelog/2022-10-11-github-actions-deprecating-save-state-and-set-output-commands/ --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index db5d08f..655a58c 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -46,7 +46,7 @@ jobs: rake build ls -l pkg/*.gem shasum -a 256 pkg/*.gem - echo "::set-output name=pkg::${GITHUB_REPOSITORY#*/}-${RUNNING_OS%-*}" + echo "pkg=${GITHUB_REPOSITORY#*/}-${RUNNING_OS%-*}" >> $GITHUB_OUTPUT env: RUNNING_OS: ${{matrix.os}} shell: bash From 45fade52f519f656f62eb601899e3e96d3f69fca Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 18 Feb 2023 16:25:25 +0900 Subject: [PATCH 07/18] Use ruby/actions/.github/workflows/ruby_versions.yml@master --- .github/workflows/test.yml | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 655a58c..49735cc 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -9,14 +9,10 @@ on: jobs: ruby-versions: - runs-on: ubuntu-latest - outputs: - versions: ${{ steps.versions.outputs.value }} - steps: - - id: versions - run: | - versions=$(curl -s 'https://cache.ruby-lang.org/pub/misc/ci_versions/all.json' | jq -c '. + ["2.5"]') - echo "value=${versions}" >> $GITHUB_OUTPUT + uses: ruby/actions/.github/workflows/ruby_versions.yml@master + with: + min_version: 2.5 + test: needs: ruby-versions name: build (${{ matrix.ruby }} / ${{ matrix.os }}) From 426726fa170ab5a1ddba4f2ef04ae6864ed2a625 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 18 Feb 2023 16:25:39 +0900 Subject: [PATCH 08/18] Try with Windows --- .github/workflows/test.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 49735cc..d330f14 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -19,7 +19,10 @@ jobs: strategy: matrix: ruby: ${{ fromJson(needs.ruby-versions.outputs.versions) }} - os: [ ubuntu-latest, macos-latest ] + os: [ ubuntu-latest, macos-latest, windows-latest ] + exclude: + - { os: windows-latest, ruby: truffleruby-head } + - { os: windows-latest, ruby: truffleruby } runs-on: ${{ matrix.os }} steps: - name: git config From fd6621a23da2e8d3d1a3ab75003dbfeb0e42e2ab Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 18 Feb 2023 16:31:55 +0900 Subject: [PATCH 09/18] Exclude JRuby from Windows --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index d330f14..e6958c9 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -23,6 +23,8 @@ jobs: exclude: - { os: windows-latest, ruby: truffleruby-head } - { os: windows-latest, ruby: truffleruby } + - { os: windows-latest, ruby: jruby-head } + - { os: windows-latest, ruby: jruby } runs-on: ${{ matrix.os }} steps: - name: git config From b67cc2407e6f9b5b4c9bc0751e21fa4969da0ceb Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Sat, 18 Feb 2023 16:37:54 +0900 Subject: [PATCH 10/18] Skip build and upload package with Windows --- .github/workflows/test.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index e6958c9..58ebde3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -51,8 +51,10 @@ jobs: env: RUNNING_OS: ${{matrix.os}} shell: bash + if: ${{ matrix.os != 'windows-latest' }} - name: Upload package uses: actions/upload-artifact@v3 with: path: pkg/*.gem name: ${{steps.build.outputs.pkg}} + if: ${{ matrix.os != 'windows-latest' }} From 5bf4fa8a72a00d0891106af21655800db1d2ceff Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Fri, 24 Mar 2023 13:01:25 +0900 Subject: [PATCH 11/18] Update test libraries from https://github.com/ruby/ruby/commit/b4e438d8aabaf4bba2b27f374c787543fae07c58 --- test/lib/core_assertions.rb | 152 +++++++++++++++++++++--------------- test/lib/envutil.rb | 25 ++++-- 2 files changed, 109 insertions(+), 68 deletions(-) diff --git a/test/lib/core_assertions.rb b/test/lib/core_assertions.rb index bac3856..1fdc0a3 100644 --- a/test/lib/core_assertions.rb +++ b/test/lib/core_assertions.rb @@ -3,6 +3,10 @@ module Test module Unit module Assertions + def assert_raises(*exp, &b) + raise NoMethodError, "use assert_raise", caller + end + def _assertions= n # :nodoc: @_assertions = n end @@ -16,9 +20,16 @@ def _assertions # :nodoc: def message msg = nil, ending = nil, &default proc { - msg = msg.call.chomp(".") if Proc === msg - custom_message = "#{msg}.\n" unless msg.nil? or msg.to_s.empty? - "#{custom_message}#{default.call}#{ending || "."}" + ending ||= (ending_pattern = /(? e - bt = e.backtrace - as = e.instance_of?(Test::Unit::AssertionFailedError) - if as - ans = /\A#{Regexp.quote(__FILE__)}:#{line}:in /o - bt.reject! {|ln| ans =~ ln} - end - if ((args.empty? && !as) || - args.any? {|a| a.instance_of?(Module) ? e.is_a?(a) : e.class == a }) - msg = message(msg) { - "Exception raised:\n<#{mu_pp(e)}>\n" + - "Backtrace:\n" + - e.backtrace.map{|frame| " #{frame}"}.join("\n") - } - raise Test::Unit::AssertionFailedError, msg.call, bt - else - raise - end + rescue *(args.empty? ? Exception : args) => e + msg = message(msg) { + "Exception raised:\n<#{mu_pp(e)}>\n""Backtrace:\n" << + Test.filter_backtrace(e.backtrace).map{|frame| " #{frame}"}.join("\n") + } + raise Test::Unit::AssertionFailedError, msg.call, e.backtrace end end @@ -244,13 +244,17 @@ def assert_ruby_status(args, test_stdin="", message=nil, **opt) ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV TERM") - def separated_runner(out = nil) + def separated_runner(token, out = nil) include(*Test::Unit::TestCase.ancestors.select {|c| !c.is_a?(Class) }) out = out ? IO.new(out, 'w') : STDOUT at_exit { - out.puts [Marshal.dump($!)].pack('m'), "assertions=#{self._assertions}" + out.puts "#{token}", [Marshal.dump($!)].pack('m'), "#{token}", "#{token}assertions=#{self._assertions}" } - Test::Unit::Runner.class_variable_set(:@@stop_auto_run, true) if defined?(Test::Unit::Runner) + if defined?(Test::Unit::Runner) + Test::Unit::Runner.class_variable_set(:@@stop_auto_run, true) + elsif defined?(Test::Unit::AutoRunner) + Test::Unit::AutoRunner.need_auto_run = false + end end def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt) @@ -260,22 +264,24 @@ def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **o line ||= loc.lineno end capture_stdout = true - unless /mswin|mingw/ =~ RUBY_PLATFORM + unless /mswin|mingw/ =~ RbConfig::CONFIG['host_os'] capture_stdout = false opt[:out] = Test::Unit::Runner.output if defined?(Test::Unit::Runner) res_p, res_c = IO.pipe opt[:ios] = [res_c] end + token_dump, token_re = new_test_token src = <\n\K.*\n(?=#{token_re}<\/error>$)/m].unpack1("m")) rescue => marshal_error ignore_stderr = nil res = nil @@ -463,7 +469,7 @@ def assert_raise_with_message(exception, expected, msg = nil, &block) ex end - MINI_DIR = File.join(File.dirname(File.expand_path(__FILE__)), "minitest") #:nodoc: + TEST_DIR = File.join(__dir__, "test/unit") #:nodoc: # :call-seq: # assert(test, [failure_message]) @@ -483,7 +489,7 @@ def assert(test, *msgs) when nil msgs.shift else - bt = caller.reject { |s| s.start_with?(MINI_DIR) } + bt = caller.reject { |s| s.start_with?(TEST_DIR) } raise ArgumentError, "assertion message must be String or Proc, but #{msg.class} was given.", bt end unless msgs.empty? super @@ -506,7 +512,7 @@ def assert_respond_to(obj, (meth, *priv), msg = nil) return assert obj.respond_to?(meth, *priv), msg end #get rid of overcounting - if caller_locations(1, 1)[0].path.start_with?(MINI_DIR) + if caller_locations(1, 1)[0].path.start_with?(TEST_DIR) return if obj.respond_to?(meth) end super(obj, meth, msg) @@ -529,17 +535,17 @@ def assert_not_respond_to(obj, (meth, *priv), msg = nil) return assert !obj.respond_to?(meth, *priv), msg end #get rid of overcounting - if caller_locations(1, 1)[0].path.start_with?(MINI_DIR) + if caller_locations(1, 1)[0].path.start_with?(TEST_DIR) return unless obj.respond_to?(meth) end refute_respond_to(obj, meth, msg) end - # pattern_list is an array which contains regexp and :*. + # pattern_list is an array which contains regexp, string and :*. # :* means any sequence. # # pattern_list is anchored. - # Use [:*, regexp, :*] for non-anchored match. + # Use [:*, regexp/string, :*] for non-anchored match. def assert_pattern_list(pattern_list, actual, message=nil) rest = actual anchored = true @@ -548,11 +554,13 @@ def assert_pattern_list(pattern_list, actual, message=nil) anchored = false else if anchored - match = /\A#{pattern}/.match(rest) + match = rest.rindex(pattern, 0) else - match = pattern.match(rest) + match = rest.index(pattern) end - unless match + if match + post_match = $~ ? $~.post_match : rest[match+pattern.size..-1] + else msg = message(msg) { expect_msg = "Expected #{mu_pp pattern}\n" if /\n[^\n]/ =~ rest @@ -569,7 +577,7 @@ def assert_pattern_list(pattern_list, actual, message=nil) } assert false, msg end - rest = match.post_match + rest = post_match anchored = true end } @@ -596,14 +604,14 @@ def assert_warn(*args) def assert_deprecated_warning(mesg = /deprecated/) assert_warning(mesg) do - Warning[:deprecated] = true + Warning[:deprecated] = true if Warning.respond_to?(:[]=) yield end end def assert_deprecated_warn(mesg = /deprecated/) assert_warn(mesg) do - Warning[:deprecated] = true + Warning[:deprecated] = true if Warning.respond_to?(:[]=) yield end end @@ -641,7 +649,7 @@ def initialize def for(key) @count += 1 - yield + yield key rescue Exception => e @failures[key] = [@count, e] end @@ -695,7 +703,7 @@ def assert_join_threads(threads, message = nil) msg = "exceptions on #{errs.length} threads:\n" + errs.map {|t, err| "#{t.inspect}:\n" + - RUBY_VERSION >= "2.5.0" ? err.full_message(highlight: false, order: :top) : err.message + (err.respond_to?(:full_message) ? err.full_message(highlight: false, order: :top) : err.message) }.join("\n---\n") if message msg = "#{message}\n#{msg}" @@ -730,21 +738,36 @@ def assert_all_assertions_foreach(msg = nil, *keys, &block) end alias all_assertions_foreach assert_all_assertions_foreach - def message(msg = nil, *args, &default) # :nodoc: - if Proc === msg - super(nil, *args) do - ary = [msg.call, (default.call if default)].compact.reject(&:empty?) - if 1 < ary.length - ary[0...-1] = ary[0...-1].map {|str| str.sub(/(?(n) {n}) + first = seq.first + *arg = pre.call(first) + times = (0..(rehearsal || (2 * first))).map do + st = Process.clock_gettime(Process::CLOCK_MONOTONIC) + yield(*arg) + t = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - st) + assert_operator 0, :<=, t + t.nonzero? + end + times.compact! + tmin, tmax = times.minmax + tmax *= tmax / tmin + tmax = 10**Math.log10(tmax).ceil + + seq.each do |i| + next if i == first + t = tmax * i.fdiv(first) + *arg = pre.call(i) + message = "[#{i}]: in #{t}s" + Timeout.timeout(t, Timeout::Error, message) do + st = Process.clock_gettime(Process::CLOCK_MONOTONIC) + yield(*arg) + assert_operator (Process.clock_gettime(Process::CLOCK_MONOTONIC) - st), :<=, t, message end - else - super end end @@ -763,6 +786,11 @@ def diff(exp, act) end q.output end + + def new_test_token + token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m" + return token.dump, Regexp.quote(token) + end end end end diff --git a/test/lib/envutil.rb b/test/lib/envutil.rb index 0391b90..728ca70 100644 --- a/test/lib/envutil.rb +++ b/test/lib/envutil.rb @@ -152,7 +152,12 @@ def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = if RUBYLIB and lib = child_env["RUBYLIB"] child_env["RUBYLIB"] = [lib, RUBYLIB].join(File::PATH_SEPARATOR) end - child_env['ASAN_OPTIONS'] = ENV['ASAN_OPTIONS'] if ENV['ASAN_OPTIONS'] + + # remain env + %w(ASAN_OPTIONS RUBY_ON_BUG).each{|name| + child_env[name] = ENV[name] if ENV[name] + } + args = [args] if args.kind_of?(String) pid = spawn(child_env, *precommand, rubybin, *args, opt) in_c.close @@ -292,16 +297,24 @@ def self.diagnostic_reports(signame, pid, now) cmd = @ruby_install_name if "ruby-runner#{RbConfig::CONFIG["EXEEXT"]}" == cmd path = DIAGNOSTIC_REPORTS_PATH timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT - pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.crash" + pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.{crash,ips}" first = true 30.times do first ? (first = false) : sleep(0.1) Dir.glob(pat) do |name| log = File.read(name) rescue next - if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log - File.unlink(name) - File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil - return log + case name + when /\.crash\z/ + if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log + File.unlink(name) + File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil + return log + end + when /\.ips\z/ + if /^ *"pid" *: *#{pid},/ =~ log + File.unlink(name) + return log + end end end end From fb91d97c109269aee4fb0f7ecc1b3826dad118d8 Mon Sep 17 00:00:00 2001 From: Jeremy Evans Date: Tue, 4 Apr 2023 13:58:59 -0700 Subject: [PATCH 12/18] Document requires needed for Date/DateTime/Time/URI/Shellwords support Fixes [Bug #19566] --- lib/optparse.rb | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/optparse.rb b/lib/optparse.rb index 7e0479b..28b64af 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -152,14 +152,14 @@ # OptionParser supports the ability to coerce command line arguments # into objects for us. # -# OptionParser comes with a few ready-to-use kinds of type +# OptionParser comes with a few ready-to-use kinds of type # coercion. They are: # -# - Date -- Anything accepted by +Date.parse+ -# - DateTime -- Anything accepted by +DateTime.parse+ -# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+ -# - URI -- Anything accepted by +URI.parse+ -# - Shellwords -- Anything accepted by +Shellwords.shellwords+ +# - Date -- Anything accepted by +Date.parse+ (need to require +optparse/date+) +# - DateTime -- Anything accepted by +DateTime.parse+ (need to require +optparse/date+) +# - Time -- Anything accepted by +Time.httpdate+ or +Time.parse+ (need to require +optparse/time+) +# - URI -- Anything accepted by +URI.parse+ (need to require +optparse/uri+) +# - Shellwords -- Anything accepted by +Shellwords.shellwords+ (need to require +optparse/shellwords+) # - String -- Any non-empty string # - Integer -- Any integer. Will convert octal. (e.g. 124, -3, 040) # - Float -- Any float. (e.g. 10, 3.14, -100E+13) From 3cde2178d3d1bd1c7bf9c7e2af930e89e0bad6e5 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Wed, 12 Jul 2023 01:07:11 +0900 Subject: [PATCH 13/18] Upload according to build results --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 58ebde3..f115db3 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -57,4 +57,4 @@ jobs: with: path: pkg/*.gem name: ${{steps.build.outputs.pkg}} - if: ${{ matrix.os != 'windows-latest' }} + if: ${{ steps.build.outcome == 'success' }} From e8bee0be8f52f5a3e08d0db09a13798701670391 Mon Sep 17 00:00:00 2001 From: Nobuyoshi Nakada Date: Sun, 30 Jul 2023 11:24:59 +0900 Subject: [PATCH 14/18] [DOC] Mark up constant and method names as code --- doc/optparse/argument_converters.rdoc | 70 +++++++++++++-------------- doc/optparse/option_params.rdoc | 4 +- doc/optparse/tutorial.rdoc | 66 ++++++++++++------------- lib/optparse.rb | 2 +- 4 files changed, 71 insertions(+), 71 deletions(-) diff --git a/doc/optparse/argument_converters.rdoc b/doc/optparse/argument_converters.rdoc index ac659da..4b4b30e 100644 --- a/doc/optparse/argument_converters.rdoc +++ b/doc/optparse/argument_converters.rdoc @@ -1,7 +1,7 @@ == Argument Converters An option can specify that its argument is to be converted -from the default \String to an instance of another class. +from the default +String+ to an instance of another class. === Contents @@ -27,13 +27,13 @@ from the default \String to an instance of another class. === Built-In Argument Converters -\OptionParser has a number of built-in argument converters, ++OptionParser+ has a number of built-in argument converters, which are demonstrated below. -==== \Date +==== +Date+ File +date.rb+ -defines an option whose argument is to be converted to a \Date object. +defines an option whose argument is to be converted to a +Date+ object. The argument is converted by method Date#parse. :include: ruby/date.rb @@ -47,10 +47,10 @@ Executions: $ ruby date.rb --date "3rd Feb 2001" [#, Date] -==== \DateTime +==== +DateTime+ File +datetime.rb+ -defines an option whose argument is to be converted to a \DateTime object. +defines an option whose argument is to be converted to a +DateTime+ object. The argument is converted by method DateTime#parse. :include: ruby/datetime.rb @@ -64,10 +64,10 @@ Executions: $ ruby datetime.rb --datetime "3rd Feb 2001 04:05:06 PM" [#, DateTime] -==== \Time +==== +Time+ File +time.rb+ -defines an option whose argument is to be converted to a \Time object. +defines an option whose argument is to be converted to a +Time+ object. The argument is converted by method Time#httpdate or Time#parse. :include: ruby/time.rb @@ -79,10 +79,10 @@ Executions: $ ruby time.rb --time 2010-10-31 [2010-10-31 00:00:00 -0500, Time] -==== \URI +==== +URI+ File +uri.rb+ -defines an option whose argument is to be converted to a \URI object. +defines an option whose argument is to be converted to a +URI+ object. The argument is converted by method URI#parse. :include: ruby/uri.rb @@ -96,10 +96,10 @@ Executions: $ ruby uri.rb --uri file://~/var [#, URI::File] -==== \Shellwords +==== +Shellwords+ File +shellwords.rb+ -defines an option whose argument is to be converted to an \Array object by method +defines an option whose argument is to be converted to an +Array+ object by method Shellwords#shellwords. :include: ruby/shellwords.rb @@ -111,10 +111,10 @@ Executions: $ ruby shellwords.rb --shellwords "here are 'two words'" [["here", "are", "two words"], Array] -==== \Integer +==== +Integer+ File +integer.rb+ -defines an option whose argument is to be converted to an \Integer object. +defines an option whose argument is to be converted to an +Integer+ object. The argument is converted by method Kernel#Integer. :include: ruby/integer.rb @@ -132,10 +132,10 @@ Executions: $ ruby integer.rb --integer 0b100 [4, Integer] -==== \Float +==== +Float+ File +float.rb+ -defines an option whose argument is to be converted to a \Float object. +defines an option whose argument is to be converted to a +Float+ object. The argument is converted by method Kernel#Float. :include: ruby/float.rb @@ -151,11 +151,11 @@ Executions: $ ruby float.rb --float 1.234E-2 [0.01234, Float] -==== \Numeric +==== +Numeric+ File +numeric.rb+ defines an option whose argument is to be converted to an instance -of \Rational, \Float, or \Integer. +of +Rational+, +Float+, or +Integer+. The argument is converted by method Kernel#Rational, Kernel#Float, or Kernel#Integer. @@ -170,10 +170,10 @@ Executions: $ ruby numeric.rb --numeric 3 [3, Integer] -==== \DecimalInteger +==== +DecimalInteger+ File +decimal_integer.rb+ -defines an option whose argument is to be converted to an \Integer object. +defines an option whose argument is to be converted to an +Integer+ object. The argument is converted by method Kernel#Integer. :include: ruby/decimal_integer.rb @@ -192,10 +192,10 @@ Executions: $ ruby decimal_integer.rb --decimal_integer -0100 [-100, Integer] -==== \OctalInteger +==== +OctalInteger+ File +octal_integer.rb+ -defines an option whose argument is to be converted to an \Integer object. +defines an option whose argument is to be converted to an +Integer+ object. The argument is converted by method Kernel#Integer. :include: ruby/octal_integer.rb @@ -212,10 +212,10 @@ Executions: $ ruby octal_integer.rb --octal_integer 0100 [64, Integer] -==== \DecimalNumeric +==== +DecimalNumeric+ File +decimal_numeric.rb+ -defines an option whose argument is to be converted to an \Integer object. +defines an option whose argument is to be converted to an +Integer+ object. The argument is converted by method Kernel#Integer :include: ruby/decimal_numeric.rb @@ -232,7 +232,7 @@ Executions: $ ruby decimal_numeric.rb --decimal_numeric 0100 [64, Integer] -==== \TrueClass +==== +TrueClass+ File +true_class.rb+ defines an option whose argument is to be converted to +true+ or +false+. @@ -259,7 +259,7 @@ Executions: $ ruby true_class.rb --true_class nil [false, FalseClass] -==== \FalseClass +==== +FalseClass+ File +false_class.rb+ defines an option whose argument is to be converted to +true+ or +false+. @@ -286,10 +286,10 @@ Executions: $ ruby false_class.rb --false_class + [true, TrueClass] -==== \Object +==== +Object+ File +object.rb+ -defines an option whose argument is not to be converted from \String. +defines an option whose argument is not to be converted from +String+. :include: ruby/object.rb @@ -300,10 +300,10 @@ Executions: $ ruby object.rb --object nil ["nil", String] -==== \String +==== +String+ File +string.rb+ -defines an option whose argument is not to be converted from \String. +defines an option whose argument is not to be converted from +String+. :include: ruby/string.rb @@ -314,10 +314,10 @@ Executions: $ ruby string.rb --string nil ["nil", String] -==== \Array +==== +Array+ File +array.rb+ -defines an option whose argument is to be converted from \String +defines an option whose argument is to be converted from +String+ to an array of strings, based on comma-separated substrings. :include: ruby/array.rb @@ -331,10 +331,10 @@ Executions: $ ruby array.rb --array "foo, bar, baz" [["foo", " bar", " baz"], Array] -==== \Regexp +==== +Regexp+ File +regexp.rb+ -defines an option whose argument is to be converted to a \Regexp object. +defines an option whose argument is to be converted to a +Regexp+ object. :include: ruby/regexp.rb @@ -352,7 +352,7 @@ To create a custom converter, call OptionParser#accept with: - A block that accepts the argument and returns the converted value. This custom converter accepts any argument and converts it, -if possible, to a \Complex object. +if possible, to a +Complex+ object. :include: ruby/custom_converter.rb diff --git a/doc/optparse/option_params.rdoc b/doc/optparse/option_params.rdoc index ace2c42..55f9b53 100644 --- a/doc/optparse/option_params.rdoc +++ b/doc/optparse/option_params.rdoc @@ -1,6 +1,6 @@ == Parameters for New Options -Option-creating methods in \OptionParser +Option-creating methods in +OptionParser+ accept arguments that determine the behavior of a new option: - OptionParser#on @@ -405,7 +405,7 @@ Executions: === Argument Converters An option can specify that its argument is to be converted -from the default \String to an instance of another class. +from the default +String+ to an instance of another class. There are a number of built-in converters. You can also define custom converters. diff --git a/doc/optparse/tutorial.rdoc b/doc/optparse/tutorial.rdoc index b950898..b5d9bf9 100644 --- a/doc/optparse/tutorial.rdoc +++ b/doc/optparse/tutorial.rdoc @@ -1,10 +1,10 @@ == Tutorial -=== Why \OptionParser? +=== Why +OptionParser+? When a Ruby program executes, it captures its command-line arguments and options into variable ARGV. -This simple program just prints its \ARGV: +This simple program just prints its +ARGV+: :include: ruby/argv.rb @@ -18,7 +18,7 @@ the command-line options. OptionParser offers methods for parsing and handling those options. -With \OptionParser, you can define options so that for each option: +With +OptionParser+, you can define options so that for each option: - The code that defines the option and code that handles that option are in the same place. @@ -66,10 +66,10 @@ The class also has method #help, which displays automatically-generated help tex === To Begin With -To use \OptionParser: +To use +OptionParser+: -1. Require the \OptionParser code. -2. Create an \OptionParser object. +1. Require the +OptionParser+ code. +2. Create an +OptionParser+ object. 3. Define one or more options. 4. Parse the command line. @@ -92,9 +92,9 @@ the block defined for the option is called with the argument value. An invalid option raises an exception. Method #parse!, which is used most often in this tutorial, -removes from \ARGV the options and arguments it finds, +removes from +ARGV+ the options and arguments it finds, leaving other non-option arguments for the program to handle on its own. -The method returns the possibly-reduced \ARGV array. +The method returns the possibly-reduced +ARGV+ array. Executions: @@ -115,7 +115,7 @@ Executions: === Defining Options -A common way to define an option in \OptionParser +A common way to define an option in +OptionParser+ is with instance method OptionParser#on. The method may be called with any number of arguments @@ -522,11 +522,11 @@ Executions: === Argument Converters An option can specify that its argument is to be converted -from the default \String to an instance of another class. +from the default +String+ to an instance of another class. There are a number of built-in converters. Example: File +date.rb+ -defines an option whose argument is to be converted to a \Date object. +defines an option whose argument is to be converted to a +Date+ object. The argument is converted by method Date#parse. :include: ruby/date.rb @@ -546,7 +546,7 @@ for both built-in and custom converters. === Help -\OptionParser makes automatically generated help text available. ++OptionParser+ makes automatically generated help text available. The help text consists of: @@ -614,16 +614,16 @@ Execution: === Top List and Base List -An \OptionParser object maintains a stack of \OptionParser::List objects, +An +OptionParser+ object maintains a stack of +OptionParser::List+ objects, each of which has a collection of zero or more options. It is unlikely that you'll need to add or take away from that stack. The stack includes: -- The top list, given by \OptionParser#top. -- The base list, given by \OptionParser#base. +- The top list, given by +OptionParser#top+. +- The base list, given by +OptionParser#base+. -When \OptionParser builds its help text, the options in the top list +When +OptionParser+ builds its help text, the options in the top list precede those in the base list. === Defining Options @@ -632,31 +632,31 @@ Option-defining methods allow you to create an option, and also append/prepend i to the top list or append it to the base list. Each of these next three methods accepts a sequence of parameter arguments and a block, -creates an option object using method \Option#make_switch (see below), +creates an option object using method +Option#make_switch+ (see below), and returns the created option: -- \Method \OptionParser#define appends the created option to the top list. +- \Method +OptionParser#define+ appends the created option to the top list. -- \Method \OptionParser#define_head prepends the created option to the top list. +- \Method +OptionParser#define_head+ prepends the created option to the top list. -- \Method \OptionParser#define_tail appends the created option to the base list. +- \Method +OptionParser#define_tail+ appends the created option to the base list. These next three methods are identical to the three above, except for their return values: -- \Method \OptionParser#on is identical to method \OptionParser#define, +- \Method +OptionParser#on+ is identical to method +OptionParser#define+, except that it returns the parser object +self+. -- \Method \OptionParser#on_head is identical to method \OptionParser#define_head, +- \Method +OptionParser#on_head+ is identical to method +OptionParser#define_head+, except that it returns the parser object +self+. -- \Method \OptionParser#on_tail is identical to method \OptionParser#define_tail, +- \Method +OptionParser#on_tail+ is identical to method +OptionParser#define_tail+, except that it returns the parser object +self+. Though you may never need to call it directly, here's the core method for defining an option: -- \Method \OptionParser#make_switch accepts an array of parameters and a block. +- \Method +OptionParser#make_switch+ accepts an array of parameters and a block. See {Parameters for New Options}[optparse/option_params.rdoc]. This method is unlike others here in that it: - Accepts an array of parameters; @@ -668,7 +668,7 @@ here's the core method for defining an option: === Parsing -\OptionParser has six instance methods for parsing. ++OptionParser+ has six instance methods for parsing. Three have names ending with a "bang" (!): @@ -699,9 +699,9 @@ Each of these methods: (see {Keyword Argument into}[#label-Keyword+Argument+into]). - Returns +argv+, possibly with some elements removed. -==== \Method parse! +==== \Method +parse!+ -\Method parse!: +\Method +parse!+: - Accepts an optional array of string arguments +argv+; if not given, +argv+ defaults to the value of OptionParser#default_argv, @@ -756,9 +756,9 @@ Processing ended by non-option found when +POSIXLY_CORRECT+ is defined: ["--xxx", true] Returned: ["input_file.txt", "output_file.txt", "-yyy", "FOO"] (Array) -==== \Method parse +==== \Method +parse+ -\Method parse: +\Method +parse+: - Accepts an array of string arguments _or_ zero or more string arguments. @@ -810,25 +810,25 @@ Processing ended by non-option found when +POSIXLY_CORRECT+ is defined: ["--xxx", true] Returned: ["input_file.txt", "output_file.txt", "-yyy", "FOO"] (Array) -==== \Method order! +==== \Method +order!+ Calling method OptionParser#order! gives exactly the same result as calling method OptionParser#parse! with environment variable +POSIXLY_CORRECT+ defined. -==== \Method order +==== \Method +order+ Calling method OptionParser#order gives exactly the same result as calling method OptionParser#parse with environment variable +POSIXLY_CORRECT+ defined. -==== \Method permute! +==== \Method +permute!+ Calling method OptionParser#permute! gives exactly the same result as calling method OptionParser#parse! with environment variable +POSIXLY_CORRECT+ _not_ defined. -==== \Method permute +==== \Method +permute+ Calling method OptionParser#permute gives exactly the same result as calling method OptionParser#parse with environment variable diff --git a/lib/optparse.rb b/lib/optparse.rb index 28b64af..0998251 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -48,7 +48,7 @@ # # == OptionParser # -# === New to \OptionParser? +# === New to +OptionParser+? # # See the {Tutorial}[optparse/tutorial.rdoc]. # From 2940dbb65a7df013995934a93e6906109adda766 Mon Sep 17 00:00:00 2001 From: BurdetteLamar Date: Sun, 30 Jul 2023 16:35:00 +0100 Subject: [PATCH 15/18] [DOC] Corrections to tutorial --- doc/optparse/tutorial.rdoc | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/doc/optparse/tutorial.rdoc b/doc/optparse/tutorial.rdoc index b5d9bf9..b104379 100644 --- a/doc/optparse/tutorial.rdoc +++ b/doc/optparse/tutorial.rdoc @@ -55,7 +55,7 @@ The class also has method #help, which displays automatically-generated help tex - {Argument Converters}[#label-Argument+Converters] - {Help}[#label-Help] - {Top List and Base List}[#label-Top+List+and+Base+List] -- {Defining Options}[#label-Defining+Options] +- {Methods for Defining Options}[#label-Methods+for+Defining+Options] - {Parsing}[#label-Parsing] - {Method parse!}[#label-Method+parse-21] - {Method parse}[#label-Method+parse] @@ -614,49 +614,49 @@ Execution: === Top List and Base List -An +OptionParser+ object maintains a stack of +OptionParser::List+ objects, +An +OptionParser+ object maintains a stack of OptionParser::List objects, each of which has a collection of zero or more options. It is unlikely that you'll need to add or take away from that stack. The stack includes: -- The top list, given by +OptionParser#top+. -- The base list, given by +OptionParser#base+. +- The top list, given by OptionParser#top. +- The base list, given by OptionParser#base. When +OptionParser+ builds its help text, the options in the top list precede those in the base list. -=== Defining Options +=== Methods for Defining Options Option-defining methods allow you to create an option, and also append/prepend it to the top list or append it to the base list. Each of these next three methods accepts a sequence of parameter arguments and a block, -creates an option object using method +Option#make_switch+ (see below), +creates an option object using method OptionParser#make_switch (see below), and returns the created option: -- \Method +OptionParser#define+ appends the created option to the top list. +- \Method OptionParser#define appends the created option to the top list. -- \Method +OptionParser#define_head+ prepends the created option to the top list. +- \Method OptionParser#define_head prepends the created option to the top list. -- \Method +OptionParser#define_tail+ appends the created option to the base list. +- \Method OptionParser#define_tail appends the created option to the base list. These next three methods are identical to the three above, except for their return values: -- \Method +OptionParser#on+ is identical to method +OptionParser#define+, +- \Method OptionParser#on is identical to method OptionParser#define, except that it returns the parser object +self+. -- \Method +OptionParser#on_head+ is identical to method +OptionParser#define_head+, +- \Method OptionParser#on_head is identical to method OptionParser#define_head, except that it returns the parser object +self+. -- \Method +OptionParser#on_tail+ is identical to method +OptionParser#define_tail+, +- \Method OptionParser#on_tail is identical to method OptionParser#define_tail, except that it returns the parser object +self+. Though you may never need to call it directly, here's the core method for defining an option: -- \Method +OptionParser#make_switch+ accepts an array of parameters and a block. +- \Method OptionParser#make_switch accepts an array of parameters and a block. See {Parameters for New Options}[optparse/option_params.rdoc]. This method is unlike others here in that it: - Accepts an array of parameters; From a291ef5c26445d423bf0223b0cb64340df18f0cb Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Sep 2023 03:20:53 +0000 Subject: [PATCH 16/18] Bump actions/checkout from 3 to 4 Bumps [actions/checkout](https://github.com/actions/checkout) from 3 to 4. - [Release notes](https://github.com/actions/checkout/releases) - [Changelog](https://github.com/actions/checkout/blob/main/CHANGELOG.md) - [Commits](https://github.com/actions/checkout/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/checkout dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index f115db3..0c2decb 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -32,7 +32,7 @@ jobs: git config --global core.autocrlf false git config --global core.eol lf git config --global advice.detachedHead 0 - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Ruby uses: ruby/setup-ruby@v1 with: From 38848ce4b31977d4a892c2a5573b304c77208283 Mon Sep 17 00:00:00 2001 From: Hiroshi SHIBATA Date: Thu, 5 Oct 2023 16:17:40 +0900 Subject: [PATCH 17/18] Use test-unit-ruby-core gem --- Gemfile | 1 + Rakefile | 6 - test/lib/core_assertions.rb | 796 ------------------------------------ test/lib/envutil.rb | 380 ----------------- test/lib/find_executable.rb | 22 - test/lib/helper.rb | 2 +- 6 files changed, 2 insertions(+), 1205 deletions(-) delete mode 100644 test/lib/core_assertions.rb delete mode 100644 test/lib/envutil.rb delete mode 100644 test/lib/find_executable.rb diff --git a/Gemfile b/Gemfile index eb86192..86af132 100644 --- a/Gemfile +++ b/Gemfile @@ -2,3 +2,4 @@ source "https://rubygems.org" gem "rake" gem "test-unit" +gem "test-unit-ruby-core" diff --git a/Rakefile b/Rakefile index 29d9a18..8482e91 100644 --- a/Rakefile +++ b/Rakefile @@ -7,12 +7,6 @@ Rake::TestTask.new(:test) do |t| t.test_files = FileList["test/**/test_*.rb"] end -task :sync_tool, [:from] do |t, from: "../ruby"| - cp "#{from}/tool/lib/core_assertions.rb", "./test/lib" - cp "#{from}/tool/lib/envutil.rb", "./test/lib" - cp "#{from}/tool/lib/find_executable.rb", "./test/lib" -end - task :default => :test task :rdoc do diff --git a/test/lib/core_assertions.rb b/test/lib/core_assertions.rb deleted file mode 100644 index 1fdc0a3..0000000 --- a/test/lib/core_assertions.rb +++ /dev/null @@ -1,796 +0,0 @@ -# frozen_string_literal: true - -module Test - module Unit - module Assertions - def assert_raises(*exp, &b) - raise NoMethodError, "use assert_raise", caller - end - - def _assertions= n # :nodoc: - @_assertions = n - end - - def _assertions # :nodoc: - @_assertions ||= 0 - end - - ## - # Returns a proc that will output +msg+ along with the default message. - - def message msg = nil, ending = nil, &default - proc { - ending ||= (ending_pattern = /(? 0 and b > 0 - assert_operator(a.fdiv(b), :<, limit, message(message) {"#{n}: #{b} => #{a}"}) - end - rescue LoadError - pend - end - - # :call-seq: - # assert_nothing_raised( *args, &block ) - # - #If any exceptions are given as arguments, the assertion will - #fail if one of those exceptions are raised. Otherwise, the test fails - #if any exceptions are raised. - # - #The final argument may be a failure message. - # - # assert_nothing_raised RuntimeError do - # raise Exception #Assertion passes, Exception is not a RuntimeError - # end - # - # assert_nothing_raised do - # raise Exception #Assertion fails - # end - def assert_nothing_raised(*args) - self._assertions += 1 - if Module === args.last - msg = nil - else - msg = args.pop - end - begin - yield - rescue Test::Unit::PendedError, *(Test::Unit::AssertionFailedError if args.empty?) - raise - rescue *(args.empty? ? Exception : args) => e - msg = message(msg) { - "Exception raised:\n<#{mu_pp(e)}>\n""Backtrace:\n" << - Test.filter_backtrace(e.backtrace).map{|frame| " #{frame}"}.join("\n") - } - raise Test::Unit::AssertionFailedError, msg.call, e.backtrace - end - end - - def prepare_syntax_check(code, fname = nil, mesg = nil, verbose: nil) - fname ||= caller_locations(2, 1)[0] - mesg ||= fname.to_s - verbose, $VERBOSE = $VERBOSE, verbose - case - when Array === fname - fname, line = *fname - when defined?(fname.path) && defined?(fname.lineno) - fname, line = fname.path, fname.lineno - else - line = 1 - end - yield(code, fname, line, message(mesg) { - if code.end_with?("\n") - "```\n#{code}```\n" - else - "```\n#{code}\n```\n""no-newline" - end - }) - ensure - $VERBOSE = verbose - end - - def assert_valid_syntax(code, *args, **opt) - prepare_syntax_check(code, *args, **opt) do |src, fname, line, mesg| - yield if defined?(yield) - assert_nothing_raised(SyntaxError, mesg) do - assert_equal(:ok, syntax_check(src, fname, line), mesg) - end - end - end - - def assert_normal_exit(testsrc, message = '', child_env: nil, **opt) - assert_valid_syntax(testsrc, caller_locations(1, 1)[0]) - if child_env - child_env = [child_env] - else - child_env = [] - end - out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, **opt) - assert !status.signaled?, FailDesc[status, message, out] - end - - def assert_ruby_status(args, test_stdin="", message=nil, **opt) - out, _, status = EnvUtil.invoke_ruby(args, test_stdin, true, :merge_to_stdout, **opt) - desc = FailDesc[status, message, out] - assert(!status.signaled?, desc) - message ||= "ruby exit status is not success:" - assert(status.success?, desc) - end - - ABORT_SIGNALS = Signal.list.values_at(*%w"ILL ABRT BUS SEGV TERM") - - def separated_runner(token, out = nil) - include(*Test::Unit::TestCase.ancestors.select {|c| !c.is_a?(Class) }) - out = out ? IO.new(out, 'w') : STDOUT - at_exit { - out.puts "#{token}", [Marshal.dump($!)].pack('m'), "#{token}", "#{token}assertions=#{self._assertions}" - } - if defined?(Test::Unit::Runner) - Test::Unit::Runner.class_variable_set(:@@stop_auto_run, true) - elsif defined?(Test::Unit::AutoRunner) - Test::Unit::AutoRunner.need_auto_run = false - end - end - - def assert_separately(args, file = nil, line = nil, src, ignore_stderr: nil, **opt) - unless file and line - loc, = caller_locations(1,1) - file ||= loc.path - line ||= loc.lineno - end - capture_stdout = true - unless /mswin|mingw/ =~ RbConfig::CONFIG['host_os'] - capture_stdout = false - opt[:out] = Test::Unit::Runner.output if defined?(Test::Unit::Runner) - res_p, res_c = IO.pipe - opt[:ios] = [res_c] - end - token_dump, token_re = new_test_token - src = <\n\K.*\n(?=#{token_re}<\/error>$)/m].unpack1("m")) - rescue => marshal_error - ignore_stderr = nil - res = nil - end - if res and !(SystemExit === res) - if bt = res.backtrace - bt.each do |l| - l.sub!(/\A-:(\d+)/){"#{file}:#{line + $1.to_i}"} - end - bt.concat(caller) - else - res.set_backtrace(caller) - end - raise res - end - - # really is it succeed? - unless ignore_stderr - # the body of assert_separately must not output anything to detect error - assert(stderr.empty?, FailDesc[status, "assert_separately failed with error message", stderr]) - end - assert(status.success?, FailDesc[status, "assert_separately failed", stderr]) - raise marshal_error if marshal_error - end - - # Run Ractor-related test without influencing the main test suite - def assert_ractor(src, args: [], require: nil, require_relative: nil, file: nil, line: nil, ignore_stderr: nil, **opt) - return unless defined?(Ractor) - - require = "require #{require.inspect}" if require - if require_relative - dir = File.dirname(caller_locations[0,1][0].absolute_path) - full_path = File.expand_path(require_relative, dir) - require = "#{require}; require #{full_path.inspect}" - end - - assert_separately(args, file, line, <<~RUBY, ignore_stderr: ignore_stderr, **opt) - #{require} - previous_verbose = $VERBOSE - $VERBOSE = nil - Ractor.new {} # trigger initial warning - $VERBOSE = previous_verbose - #{src} - RUBY - end - - # :call-seq: - # assert_throw( tag, failure_message = nil, &block ) - # - #Fails unless the given block throws +tag+, returns the caught - #value otherwise. - # - #An optional failure message may be provided as the final argument. - # - # tag = Object.new - # assert_throw(tag, "#{tag} was not thrown!") do - # throw tag - # end - def assert_throw(tag, msg = nil) - ret = catch(tag) do - begin - yield(tag) - rescue UncaughtThrowError => e - thrown = e.tag - end - msg = message(msg) { - "Expected #{mu_pp(tag)} to have been thrown"\ - "#{%Q[, not #{thrown}] if thrown}" - } - assert(false, msg) - end - assert(true) - ret - end - - # :call-seq: - # assert_raise( *args, &block ) - # - #Tests if the given block raises an exception. Acceptable exception - #types may be given as optional arguments. If the last argument is a - #String, it will be used as the error message. - # - # assert_raise do #Fails, no Exceptions are raised - # end - # - # assert_raise NameError do - # puts x #Raises NameError, so assertion succeeds - # end - def assert_raise(*exp, &b) - case exp.last - when String, Proc - msg = exp.pop - end - - begin - yield - rescue Test::Unit::PendedError => e - return e if exp.include? Test::Unit::PendedError - raise e - rescue Exception => e - expected = exp.any? { |ex| - if ex.instance_of? Module then - e.kind_of? ex - else - e.instance_of? ex - end - } - - assert expected, proc { - flunk(message(msg) {"#{mu_pp(exp)} exception expected, not #{mu_pp(e)}"}) - } - - return e - ensure - unless e - exp = exp.first if exp.size == 1 - - flunk(message(msg) {"#{mu_pp(exp)} expected but nothing was raised"}) - end - end - end - - # :call-seq: - # assert_raise_with_message(exception, expected, msg = nil, &block) - # - #Tests if the given block raises an exception with the expected - #message. - # - # assert_raise_with_message(RuntimeError, "foo") do - # nil #Fails, no Exceptions are raised - # end - # - # assert_raise_with_message(RuntimeError, "foo") do - # raise ArgumentError, "foo" #Fails, different Exception is raised - # end - # - # assert_raise_with_message(RuntimeError, "foo") do - # raise "bar" #Fails, RuntimeError is raised but the message differs - # end - # - # assert_raise_with_message(RuntimeError, "foo") do - # raise "foo" #Raises RuntimeError with the message, so assertion succeeds - # end - def assert_raise_with_message(exception, expected, msg = nil, &block) - case expected - when String - assert = :assert_equal - when Regexp - assert = :assert_match - else - raise TypeError, "Expected #{expected.inspect} to be a kind of String or Regexp, not #{expected.class}" - end - - ex = m = nil - EnvUtil.with_default_internal(expected.encoding) do - ex = assert_raise(exception, msg || proc {"Exception(#{exception}) with message matches to #{expected.inspect}"}) do - yield - end - m = ex.message - end - msg = message(msg, "") {"Expected Exception(#{exception}) was raised, but the message doesn't match"} - - if assert == :assert_equal - assert_equal(expected, m, msg) - else - msg = message(msg) { "Expected #{mu_pp expected} to match #{mu_pp m}" } - assert expected =~ m, msg - block.binding.eval("proc{|_|$~=_}").call($~) - end - ex - end - - TEST_DIR = File.join(__dir__, "test/unit") #:nodoc: - - # :call-seq: - # assert(test, [failure_message]) - # - #Tests if +test+ is true. - # - #+msg+ may be a String or a Proc. If +msg+ is a String, it will be used - #as the failure message. Otherwise, the result of calling +msg+ will be - #used as the message if the assertion fails. - # - #If no +msg+ is given, a default message will be used. - # - # assert(false, "This was expected to be true") - def assert(test, *msgs) - case msg = msgs.first - when String, Proc - when nil - msgs.shift - else - bt = caller.reject { |s| s.start_with?(TEST_DIR) } - raise ArgumentError, "assertion message must be String or Proc, but #{msg.class} was given.", bt - end unless msgs.empty? - super - end - - # :call-seq: - # assert_respond_to( object, method, failure_message = nil ) - # - #Tests if the given Object responds to +method+. - # - #An optional failure message may be provided as the final argument. - # - # assert_respond_to("hello", :reverse) #Succeeds - # assert_respond_to("hello", :does_not_exist) #Fails - def assert_respond_to(obj, (meth, *priv), msg = nil) - unless priv.empty? - msg = message(msg) { - "Expected #{mu_pp(obj)} (#{obj.class}) to respond to ##{meth}#{" privately" if priv[0]}" - } - return assert obj.respond_to?(meth, *priv), msg - end - #get rid of overcounting - if caller_locations(1, 1)[0].path.start_with?(TEST_DIR) - return if obj.respond_to?(meth) - end - super(obj, meth, msg) - end - - # :call-seq: - # assert_not_respond_to( object, method, failure_message = nil ) - # - #Tests if the given Object does not respond to +method+. - # - #An optional failure message may be provided as the final argument. - # - # assert_not_respond_to("hello", :reverse) #Fails - # assert_not_respond_to("hello", :does_not_exist) #Succeeds - def assert_not_respond_to(obj, (meth, *priv), msg = nil) - unless priv.empty? - msg = message(msg) { - "Expected #{mu_pp(obj)} (#{obj.class}) to not respond to ##{meth}#{" privately" if priv[0]}" - } - return assert !obj.respond_to?(meth, *priv), msg - end - #get rid of overcounting - if caller_locations(1, 1)[0].path.start_with?(TEST_DIR) - return unless obj.respond_to?(meth) - end - refute_respond_to(obj, meth, msg) - end - - # pattern_list is an array which contains regexp, string and :*. - # :* means any sequence. - # - # pattern_list is anchored. - # Use [:*, regexp/string, :*] for non-anchored match. - def assert_pattern_list(pattern_list, actual, message=nil) - rest = actual - anchored = true - pattern_list.each_with_index {|pattern, i| - if pattern == :* - anchored = false - else - if anchored - match = rest.rindex(pattern, 0) - else - match = rest.index(pattern) - end - if match - post_match = $~ ? $~.post_match : rest[match+pattern.size..-1] - else - msg = message(msg) { - expect_msg = "Expected #{mu_pp pattern}\n" - if /\n[^\n]/ =~ rest - actual_mesg = +"to match\n" - rest.scan(/.*\n+/) { - actual_mesg << ' ' << $&.inspect << "+\n" - } - actual_mesg.sub!(/\+\n\z/, '') - else - actual_mesg = "to match " + mu_pp(rest) - end - actual_mesg << "\nafter #{i} patterns with #{actual.length - rest.length} characters" - expect_msg + actual_mesg - } - assert false, msg - end - rest = post_match - anchored = true - end - } - if anchored - assert_equal("", rest) - end - end - - def assert_warning(pat, msg = nil) - result = nil - stderr = EnvUtil.with_default_internal(pat.encoding) { - EnvUtil.verbose_warning { - result = yield - } - } - msg = message(msg) {diff pat, stderr} - assert(pat === stderr, msg) - result - end - - def assert_warn(*args) - assert_warning(*args) {$VERBOSE = false; yield} - end - - def assert_deprecated_warning(mesg = /deprecated/) - assert_warning(mesg) do - Warning[:deprecated] = true if Warning.respond_to?(:[]=) - yield - end - end - - def assert_deprecated_warn(mesg = /deprecated/) - assert_warn(mesg) do - Warning[:deprecated] = true if Warning.respond_to?(:[]=) - yield - end - end - - class << (AssertFile = Struct.new(:failure_message).new) - include Assertions - include CoreAssertions - def assert_file_predicate(predicate, *args) - if /\Anot_/ =~ predicate - predicate = $' - neg = " not" - end - result = File.__send__(predicate, *args) - result = !result if neg - mesg = "Expected file ".dup << args.shift.inspect - mesg << "#{neg} to be #{predicate}" - mesg << mu_pp(args).sub(/\A\[(.*)\]\z/m, '(\1)') unless args.empty? - mesg << " #{failure_message}" if failure_message - assert(result, mesg) - end - alias method_missing assert_file_predicate - - def for(message) - clone.tap {|a| a.failure_message = message} - end - end - - class AllFailures - attr_reader :failures - - def initialize - @count = 0 - @failures = {} - end - - def for(key) - @count += 1 - yield key - rescue Exception => e - @failures[key] = [@count, e] - end - - def foreach(*keys) - keys.each do |key| - @count += 1 - begin - yield key - rescue Exception => e - @failures[key] = [@count, e] - end - end - end - - def message - i = 0 - total = @count.to_s - fmt = "%#{total.size}d" - @failures.map {|k, (n, v)| - v = v.message - "\n#{i+=1}. [#{fmt%n}/#{total}] Assertion for #{k.inspect}\n#{v.b.gsub(/^/, ' | ').force_encoding(v.encoding)}" - }.join("\n") - end - - def pass? - @failures.empty? - end - end - - # threads should respond to shift method. - # Array can be used. - def assert_join_threads(threads, message = nil) - errs = [] - values = [] - while th = threads.shift - begin - values << th.value - rescue Exception - errs << [th, $!] - th = nil - end - end - values - ensure - if th&.alive? - th.raise(Timeout::Error.new) - th.join rescue errs << [th, $!] - end - if !errs.empty? - msg = "exceptions on #{errs.length} threads:\n" + - errs.map {|t, err| - "#{t.inspect}:\n" + - (err.respond_to?(:full_message) ? err.full_message(highlight: false, order: :top) : err.message) - }.join("\n---\n") - if message - msg = "#{message}\n#{msg}" - end - raise Test::Unit::AssertionFailedError, msg - end - end - - def assert_all?(obj, m = nil, &blk) - failed = [] - obj.each do |*a, &b| - unless blk.call(*a, &b) - failed << (a.size > 1 ? a : a[0]) - end - end - assert(failed.empty?, message(m) {failed.pretty_inspect}) - end - - def assert_all_assertions(msg = nil) - all = AllFailures.new - yield all - ensure - assert(all.pass?, message(msg) {all.message.chomp(".")}) - end - alias all_assertions assert_all_assertions - - def assert_all_assertions_foreach(msg = nil, *keys, &block) - all = AllFailures.new - all.foreach(*keys, &block) - ensure - assert(all.pass?, message(msg) {all.message.chomp(".")}) - end - alias all_assertions_foreach assert_all_assertions_foreach - - # Expect +seq+ to respond to +first+ and +each+ methods, e.g., - # Array, Range, Enumerator::ArithmeticSequence and other - # Enumerable-s, and each elements should be size factors. - # - # :yield: each elements of +seq+. - def assert_linear_performance(seq, rehearsal: nil, pre: ->(n) {n}) - first = seq.first - *arg = pre.call(first) - times = (0..(rehearsal || (2 * first))).map do - st = Process.clock_gettime(Process::CLOCK_MONOTONIC) - yield(*arg) - t = (Process.clock_gettime(Process::CLOCK_MONOTONIC) - st) - assert_operator 0, :<=, t - t.nonzero? - end - times.compact! - tmin, tmax = times.minmax - tmax *= tmax / tmin - tmax = 10**Math.log10(tmax).ceil - - seq.each do |i| - next if i == first - t = tmax * i.fdiv(first) - *arg = pre.call(i) - message = "[#{i}]: in #{t}s" - Timeout.timeout(t, Timeout::Error, message) do - st = Process.clock_gettime(Process::CLOCK_MONOTONIC) - yield(*arg) - assert_operator (Process.clock_gettime(Process::CLOCK_MONOTONIC) - st), :<=, t, message - end - end - end - - def diff(exp, act) - require 'pp' - q = PP.new(+"") - q.guard_inspect_key do - q.group(2, "expected: ") do - q.pp exp - end - q.text q.newline - q.group(2, "actual: ") do - q.pp act - end - q.flush - end - q.output - end - - def new_test_token - token = "\e[7;1m#{$$.to_s}:#{Time.now.strftime('%s.%L')}:#{rand(0x10000).to_s(16)}:\e[m" - return token.dump, Regexp.quote(token) - end - end - end -end diff --git a/test/lib/envutil.rb b/test/lib/envutil.rb deleted file mode 100644 index 728ca70..0000000 --- a/test/lib/envutil.rb +++ /dev/null @@ -1,380 +0,0 @@ -# -*- coding: us-ascii -*- -# frozen_string_literal: true -require "open3" -require "timeout" -require_relative "find_executable" -begin - require 'rbconfig' -rescue LoadError -end -begin - require "rbconfig/sizeof" -rescue LoadError -end - -module EnvUtil - def rubybin - if ruby = ENV["RUBY"] - return ruby - end - ruby = "ruby" - exeext = RbConfig::CONFIG["EXEEXT"] - rubyexe = (ruby + exeext if exeext and !exeext.empty?) - 3.times do - if File.exist? ruby and File.executable? ruby and !File.directory? ruby - return File.expand_path(ruby) - end - if rubyexe and File.exist? rubyexe and File.executable? rubyexe - return File.expand_path(rubyexe) - end - ruby = File.join("..", ruby) - end - if defined?(RbConfig.ruby) - RbConfig.ruby - else - "ruby" - end - end - module_function :rubybin - - LANG_ENVS = %w"LANG LC_ALL LC_CTYPE" - - DEFAULT_SIGNALS = Signal.list - DEFAULT_SIGNALS.delete("TERM") if /mswin|mingw/ =~ RUBY_PLATFORM - - RUBYLIB = ENV["RUBYLIB"] - - class << self - attr_accessor :timeout_scale - attr_reader :original_internal_encoding, :original_external_encoding, - :original_verbose, :original_warning - - def capture_global_values - @original_internal_encoding = Encoding.default_internal - @original_external_encoding = Encoding.default_external - @original_verbose = $VERBOSE - @original_warning = defined?(Warning.[]) ? %i[deprecated experimental].to_h {|i| [i, Warning[i]]} : nil - end - end - - def apply_timeout_scale(t) - if scale = EnvUtil.timeout_scale - t * scale - else - t - end - end - module_function :apply_timeout_scale - - def timeout(sec, klass = nil, message = nil, &blk) - return yield(sec) if sec == nil or sec.zero? - sec = apply_timeout_scale(sec) - Timeout.timeout(sec, klass, message, &blk) - end - module_function :timeout - - def terminate(pid, signal = :TERM, pgroup = nil, reprieve = 1) - reprieve = apply_timeout_scale(reprieve) if reprieve - - signals = Array(signal).select do |sig| - DEFAULT_SIGNALS[sig.to_s] or - DEFAULT_SIGNALS[Signal.signame(sig)] rescue false - end - signals |= [:ABRT, :KILL] - case pgroup - when 0, true - pgroup = -pid - when nil, false - pgroup = pid - end - - lldb = true if /darwin/ =~ RUBY_PLATFORM - - while signal = signals.shift - - if lldb and [:ABRT, :KILL].include?(signal) - lldb = false - # sudo -n: --non-interactive - # lldb -p: attach - # -o: run command - system(*%W[sudo -n lldb -p #{pid} --batch -o bt\ all -o call\ rb_vmdebug_stack_dump_all_threads() -o quit]) - true - end - - begin - Process.kill signal, pgroup - rescue Errno::EINVAL - next - rescue Errno::ESRCH - break - end - if signals.empty? or !reprieve - Process.wait(pid) - else - begin - Timeout.timeout(reprieve) {Process.wait(pid)} - rescue Timeout::Error - else - break - end - end - end - $? - end - module_function :terminate - - def invoke_ruby(args, stdin_data = "", capture_stdout = false, capture_stderr = false, - encoding: nil, timeout: 10, reprieve: 1, timeout_error: Timeout::Error, - stdout_filter: nil, stderr_filter: nil, ios: nil, - signal: :TERM, - rubybin: EnvUtil.rubybin, precommand: nil, - **opt) - timeout = apply_timeout_scale(timeout) - - in_c, in_p = IO.pipe - out_p, out_c = IO.pipe if capture_stdout - err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout - opt[:in] = in_c - opt[:out] = out_c if capture_stdout - opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr - if encoding - out_p.set_encoding(encoding) if out_p - err_p.set_encoding(encoding) if err_p - end - ios.each {|i, o = i|opt[i] = o} if ios - - c = "C" - child_env = {} - LANG_ENVS.each {|lc| child_env[lc] = c} - if Array === args and Hash === args.first - child_env.update(args.shift) - end - if RUBYLIB and lib = child_env["RUBYLIB"] - child_env["RUBYLIB"] = [lib, RUBYLIB].join(File::PATH_SEPARATOR) - end - - # remain env - %w(ASAN_OPTIONS RUBY_ON_BUG).each{|name| - child_env[name] = ENV[name] if ENV[name] - } - - args = [args] if args.kind_of?(String) - pid = spawn(child_env, *precommand, rubybin, *args, opt) - in_c.close - out_c&.close - out_c = nil - err_c&.close - err_c = nil - if block_given? - return yield in_p, out_p, err_p, pid - else - th_stdout = Thread.new { out_p.read } if capture_stdout - th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout - in_p.write stdin_data.to_str unless stdin_data.empty? - in_p.close - if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout)) - timeout_error = nil - else - status = terminate(pid, signal, opt[:pgroup], reprieve) - terminated = Time.now - end - stdout = th_stdout.value if capture_stdout - stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout - out_p.close if capture_stdout - err_p.close if capture_stderr && capture_stderr != :merge_to_stdout - status ||= Process.wait2(pid)[1] - stdout = stdout_filter.call(stdout) if stdout_filter - stderr = stderr_filter.call(stderr) if stderr_filter - if timeout_error - bt = caller_locations - msg = "execution of #{bt.shift.label} expired timeout (#{timeout} sec)" - msg = failure_description(status, terminated, msg, [stdout, stderr].join("\n")) - raise timeout_error, msg, bt.map(&:to_s) - end - return stdout, stderr, status - end - ensure - [th_stdout, th_stderr].each do |th| - th.kill if th - end - [in_c, in_p, out_c, out_p, err_c, err_p].each do |io| - io&.close - end - [th_stdout, th_stderr].each do |th| - th.join if th - end - end - module_function :invoke_ruby - - def verbose_warning - class << (stderr = "".dup) - alias write concat - def flush; end - end - stderr, $stderr = $stderr, stderr - $VERBOSE = true - yield stderr - return $stderr - ensure - stderr, $stderr = $stderr, stderr - $VERBOSE = EnvUtil.original_verbose - EnvUtil.original_warning&.each {|i, v| Warning[i] = v} - end - module_function :verbose_warning - - def default_warning - $VERBOSE = false - yield - ensure - $VERBOSE = EnvUtil.original_verbose - end - module_function :default_warning - - def suppress_warning - $VERBOSE = nil - yield - ensure - $VERBOSE = EnvUtil.original_verbose - end - module_function :suppress_warning - - def under_gc_stress(stress = true) - stress, GC.stress = GC.stress, stress - yield - ensure - GC.stress = stress - end - module_function :under_gc_stress - - def with_default_external(enc) - suppress_warning { Encoding.default_external = enc } - yield - ensure - suppress_warning { Encoding.default_external = EnvUtil.original_external_encoding } - end - module_function :with_default_external - - def with_default_internal(enc) - suppress_warning { Encoding.default_internal = enc } - yield - ensure - suppress_warning { Encoding.default_internal = EnvUtil.original_internal_encoding } - end - module_function :with_default_internal - - def labeled_module(name, &block) - Module.new do - singleton_class.class_eval { - define_method(:to_s) {name} - alias inspect to_s - alias name to_s - } - class_eval(&block) if block - end - end - module_function :labeled_module - - def labeled_class(name, superclass = Object, &block) - Class.new(superclass) do - singleton_class.class_eval { - define_method(:to_s) {name} - alias inspect to_s - alias name to_s - } - class_eval(&block) if block - end - end - module_function :labeled_class - - if /darwin/ =~ RUBY_PLATFORM - DIAGNOSTIC_REPORTS_PATH = File.expand_path("~/Library/Logs/DiagnosticReports") - DIAGNOSTIC_REPORTS_TIMEFORMAT = '%Y-%m-%d-%H%M%S' - @ruby_install_name = RbConfig::CONFIG['RUBY_INSTALL_NAME'] - - def self.diagnostic_reports(signame, pid, now) - return unless %w[ABRT QUIT SEGV ILL TRAP].include?(signame) - cmd = File.basename(rubybin) - cmd = @ruby_install_name if "ruby-runner#{RbConfig::CONFIG["EXEEXT"]}" == cmd - path = DIAGNOSTIC_REPORTS_PATH - timeformat = DIAGNOSTIC_REPORTS_TIMEFORMAT - pat = "#{path}/#{cmd}_#{now.strftime(timeformat)}[-_]*.{crash,ips}" - first = true - 30.times do - first ? (first = false) : sleep(0.1) - Dir.glob(pat) do |name| - log = File.read(name) rescue next - case name - when /\.crash\z/ - if /\AProcess:\s+#{cmd} \[#{pid}\]$/ =~ log - File.unlink(name) - File.unlink("#{path}/.#{File.basename(name)}.plist") rescue nil - return log - end - when /\.ips\z/ - if /^ *"pid" *: *#{pid},/ =~ log - File.unlink(name) - return log - end - end - end - end - nil - end - else - def self.diagnostic_reports(signame, pid, now) - end - end - - def self.failure_description(status, now, message = "", out = "") - pid = status.pid - if signo = status.termsig - signame = Signal.signame(signo) - sigdesc = "signal #{signo}" - end - log = diagnostic_reports(signame, pid, now) - if signame - sigdesc = "SIG#{signame} (#{sigdesc})" - end - if status.coredump? - sigdesc = "#{sigdesc} (core dumped)" - end - full_message = ''.dup - message = message.call if Proc === message - if message and !message.empty? - full_message << message << "\n" - end - full_message << "pid #{pid}" - full_message << " exit #{status.exitstatus}" if status.exited? - full_message << " killed by #{sigdesc}" if sigdesc - if out and !out.empty? - full_message << "\n" << out.b.gsub(/^/, '| ') - full_message.sub!(/(? Date: Tue, 7 Nov 2023 10:40:38 +0900 Subject: [PATCH 18/18] Bump up 0.4.0 --- lib/optparse.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/optparse.rb b/lib/optparse.rb index 0998251..832b928 100644 --- a/lib/optparse.rb +++ b/lib/optparse.rb @@ -425,7 +425,7 @@ # If you have any questions, file a ticket at http://bugs.ruby-lang.org. # class OptionParser - OptionParser::Version = "0.4.0.pre.1" + OptionParser::Version = "0.4.0" # :stopdoc: NoArgument = [NO_ARGUMENT = :NONE, nil].freeze