💎

Ruby 3.2 - OptionParser / Timeout

2022/12/23に公開

Ruby 3.2 アドベントカレンダーの23日目の記事です。

https://qiita.com/advent-calendar/2022/ruby32


default gem のバージョンアップで面白いのがあるかなーと眺めてみた。

OptionParser

OptionParser#raise_unknown

Mode for accepting all unknown options · Issue #38 · ruby/optparse

raise_unknown に偽を指定すると未知のオプションが指定されてもエラーにならないらしい。

--hoge オプションが有効なプログラムを作って、

require 'optparse'
opts = OptionParser.new do |opts|
  opts.on('--hoge'){puts 'hoge option'}
end
opts.parse!(ARGV)

これに --fuga を与えると落ちる。

% ruby hoge.rb --hoge --fuga abc
hoge option
hoge.rb:7:in `<main>': invalid option: --fuga (OptionParser::InvalidOption)

raise_unknown に偽を指定すると落ちない。それはオプションではない普通の引数として扱われるぽい。

require 'optparse'

opts = OptionParser.new do |opts|
  opts.on('--hoge'){puts 'hoge option'}
end
opts.raise_unknown = false
opts.parse!(ARGV)
pp ARGV
% ruby hoge.rb --hoge --fuga abc
hoge option
["--fuga", "abc"]

ただし、普通は通常の引数の後ろにオプションがあってもオプションとして解釈されるんだけど、

% ruby hoge.rb abc --hoge
hoge option
["abc"]

未知のオプションがあった場合はそれ以降に正しいオプションがあってもオプションとはみなされないぽい。

% ruby hoge.rb --fuga --hoge abc
["--fuga", "--hoge", "abc"]

そこで引数の評価を打ち切るって感じなのかな。

Timeout

Timeout.timeout が一つのスレッドで動く

以前は Timeout.timeout は実行されるたびにスレッドがひとつ生成されたので、わりと負荷が高い処理だった。

timeout gem 0.3.1 では、ひとつのスレッドを使いまわすようになったらしい。

こんなスクリプトを実行してみると、

require 'timeout'

def hoge(c)
 if c > 0
   Timeout.timeout(10){hoge(c-1)}
 else
   system("ps -o nlwp -p #$$")
 end
end
hoge(100)

Ruby 3.1 (timeout gem 0.2.0):

% ruby timeout-test.rb
NLWP
 101

Ruby 3.2 (timeout gem 0.3.1):

% ruby timeout-test.rb
NLWP
   2

timeout gem 0.3.1 ではスレッドを消費してないことがわかる。

Discussion