2022/02/03 今回の気になった bugs.ruby のチケット
今週は String
周りでメソッドを追加するチケットの話などがありました。
[Feature #18564] Add Exception#detailed_message
- [Feature #18438] Add
Exception#additional_message
to show additional error information で議論した結果をまとめたチケット - エラー出力の内容を
Exception#message
ではなくてException#detailed_message
を使用するようになる- これによりエラー出力の内容を
Exception#detailed_message
で制御できるようになる
- これによりエラー出力の内容を
class MyClass < StandardError def message = "my error!" def detailed_message(highlight: false, **opt) super + "\nThis is\nan additional\nmessage" end end raise MyClass
$ ./ruby test.rb test.rb:8:in `<main>': my error! (MyClass) This is an additional message
Exception#detailed_message(highlight: false)
は内部でException#message
を呼び出しhighlight: true
だとエスケープシーケンスでハイライトされる
e = RuntimeError.new("my error!") p e.detailed_message #=> "my error! (RuntimeError)" p e.detailed_message(highlight: true) #=> "\e[1mmy error! (\e[1;4mRuntimeError\e[m\e[1m)\e[m"
[Feature #13110] Byte-based operations for String
String
にバイトベースの操作をするメソッドを追加するチケット
s = "あああいいいあああ" p s.byteindex(/ああ/, 4) #=> 18 x, y = Regexp.last_match.byteoffset(0) #=> [18, 24] s.bytesplice(x...y, "おおお") p s #=> "あああいいいおおおあ"
- ユースケースとしてはバイトベースで操作する場合に一旦
force_encoding(Encoding::ASCII_8BIT)
で変換する必要があるのでそれをなくしたいらしい - 既存のメソッドを比較したベンチマークは以下の通り
lexington:ruby$ cat bench.rb require "benchmark" s = File.read("README.ja.md") * 10 Benchmark.bmbm do |x| x.report("index") do pos = 0 n = 0 loop { break unless s.index(/\p{Han}/, pos) n += 1 _, pos = Regexp.last_match.offset(0) } end x.report("byteindex") do pos = 0 n = 0 loop { break unless s.byteindex(/\p{Han}/, pos) n += 1 _, pos = Regexp.last_match.byteoffset(0) } end end lexington:ruby$ ./ruby bench.rb Rehearsal --------------------------------------------- index 1.060000 0.010000 1.070000 ( 1.116932) byteindex 0.000000 0.010000 0.010000 ( 0.004501) ------------------------------------ total: 1.080000sec user system total real index 1.050000 0.000000 1.050000 ( 1.080099) byteindex 0.000000 0.000000 0.000000 ( 0.003814)
- 5年前のチケットだが最近
String#byteindex
String#byterindex
MatchData#byteoffset
が実装された PR が投げられていた
[Feature #18563] Add "graphemes" and "each_grapheme aliases
String#each_grapheme_cluster
メソッドのエイリアスとして#graphemes
と#each_grapheme
を追加するチケット他の言語でも
graphemes
という名前になっている事が多いらしい- JavaScript/TypeScript grapheme-splitter library: splitGraphemes
- PHP: grapheme_extract
- Zig ziglyph library: GraphemeIterator
- Golang uniseg library: NewGraphemes
- Matlab: splitGraphemes
- Python grapheme library: grapheme
- Elixir: graphemes
- Crystal uni_text_seg library: graphemes
- Nim nim-graphemes library: graphemes
- Rust unicode-segmentation library: graphemes
以下、matz のコメント
https://bugs.ruby-lang.org/issues/13780#note-10
grapheme sounds like an element in the grapheme cluster. How about each_grapheme_cluster? If everyone gets used to the grapheme as an alias of grapheme cluster, we'd love to add an alias each_grapheme.
Matz.
[Bug #11064] #singleton_methods for objects with special singleton_class returns an empty array
- 以下のように
nil
に特異メソッドを追加するとnil.singleton_methods
には追加されてないように見えるというバグ報告
# nil に特異メソッドを追加する def nil.bla 42 end # 以下は動作してるが nil.bla #=> 42 nil.singleton_method(:bla) #=> #<Method: NilClass#bla> # 以下は動作していない nil.singleton_methods #=> []
- これは
nil
の#singleton_class
がNilClass
を返しているためnil
には特異クラスは存在しておらずNilClass
がその役割を果たしている
# NilClass を返す p nil.singleton_class # => NilClass # なので nil の特異メソッドは NilClass のインスタンスメソッドとして定義される def nil.bla end p NilClass.instance_methods.include? :bla # => true
- これに対しては matz からは以下のような提案がされている
- 現状のままにする
-
nil.singleton_methods
がNilClass
のメソッドを返すようにする - https://bugs.ruby-lang.org/issues/11064#note-1