2022/02/03 今回の気になった bugs.ruby のチケット
今週は String 周りでメソッドを追加するチケットの話などがありました。
[Feature #18564] Add Exception#detailed_message
- [Feature #18438] Add
Exception#additional_messageto 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#byteindexString#byterindexMatchData#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