最近のruby-core (2016年3月)

こんにちは。卜部です。

ruby-coreというRuby本体の開発の議論がされているメーリングリストがあります。

新機能やバグ報告などがだいたいここに集約されてくるので購読しておくとRubyの動きが分かります。

最近興味深かったトピックを紹介します。

[#12113] Global method inside Delegator causes NameError

スレッドのタイトルは現象としてはその通りなんだけど、本当の原因はDelegatorからプライベートなメソッドを呼ぶことがこれまでできなかったという点です。なぜならDelegator経由ではプライベートなメソッドがプライベートな感じで(レシーバーをつけないで)呼ばれたかどうかが判定できなかったから。

なんだけど最近did_you_meanの側からの要求により「プライベートなメソッドがプライベートな感じで呼ばれたかどうか」が判定可能になったんですね(#12043)。なので今やこれは実現可能なのではないかというパッチが出ている状態です。

[#12115] Add Symbol#call to allow to_proc shorthand with arguments

これと同じ要求がたくさん出ているし、実は今日会社の同僚からも聞いたので、おそらくめっちゃ欲しい人が多いと思うんですが、[1,2,3].map(&:to_s(16))とか書きたい案件ですね。しかしながら書き方が(まつもとさん的に)ぐっとこないかなにかの理由でなかなか採用されてないやつです。

なお引数が足りない場合にpartial applicationを返すことにすれば…とか考えだすと、話が大きくなって発散してしまうので、そういう方向に舵を切らないのがポイントかと。

[#12131] Should defining singleton_method_added call itself?

obj = Object.new
def obj.singleton_method_added(n)
  p n
end

で、obj.singleton_method_addedが自分自身に対して呼ばれてびっくりなんだけど、という話です。これは個人的には意外なんだけど、まあそういう解釈もありえないわけではないとのことです。つまりsingleton_method_addedはメソッド定義後に呼ばれるものだから、singleton_method_added自体の定義の後にも呼ばれても良いはずという発想ですね。そういう主張があり得るのはそうかなという感じです(が、個人の感覚としては違和感はある)。

[#10617] Change multiple assignment in conditional from parse error to warning

while (a, b = queue.pop(true) rescue nil)
   ...
end

とか、できてもいいじゃん? (なのに今できないのはおかしい)という主張です。これはまあできてもいいのかもしれないという気がしますけども難しいんだっけ。Syntax Error ということは、通そうとするとなにかの文法と衝突してしまうのかもしれませんね。

[#11210] IPAddr has no public method to get the current subnet mask

IPAddr.new でネットマスクを指定できるんですけど、その指定したネットマスクを取得する方法がいまだとinspectしてから文字列を分解するしかないのは困る、というチケットです。たしかに方法あってもいい気がしますね。

[#12136] OpenStruct.new(format: :bar).send :format # => too few arguments

ostructの最適化で内部にプライベートメソッドが増えたのですが、それに伴いOpenStructで使えるキーが減ってしまった(実装がmethod_missingを使っているのでプライベートメソッドと名前かぶるとダメ)、というバグ報告です。

これも上のDelegatorのやつと同様、昔はうつ手がなかったけど今は回避可能なのでは? と指摘されていますね。

[#12138] Support Kernel#load_with_env(filename, cbase: SomeMod, cref: someMod, binding: SomeMod) # => obj

結局GemfileとかRakefileとかあれ系全部Rubyスクリプトで、スクリプト読み込み需要は明らかなわけだから、それをもうちょっと支援するようなAPIがあってもいいのではないかという提案です。

まあ分からなくもないのだが、さりとてこの提案されてるAPIはちょっと雑すぎるかなあ。crefで意味通じる人ってほとんどおらんとおもいます…

[#12145] Aliashood between size and length is not consistent

たしか2013年くらいにMethod#original_nameというメソッドが増えていて、今だとエイリアスされてるメソッドでも元の名前がわかるようになっているのですが、実際取ってみたら結構バラバラじゃん、という指摘です。

そうなんだけど、何か困るんだろうか? というところですね。”This might be a big issue” って主張してはいますが…

[#12077] Consolidate SSLSocket interface with TCPSocket

SSLSocketTCPSocketで、定義されているメソッドが不一致だったりして、SSLを透過的に扱うことに若干の困難があるので、統一して欲しいという要求ですが、その不一致はそもそもSSLがそういうふうにできてる以上しょうがなかろう、という返信がついてますね。

[#10708] In a function call, double splat of an empty hash still calls the function with an argument

いま

def foo; end
foo(**{}) 

とかできないのが困る、なぜならmethod_missing的な任意の引数を受けて、そのまま別のメソッドに渡すようなラッパーメソッドが書けないから。という報告です。

これkwargs導入するときにmethod_missingのことは当然考慮してからデザインしたはずと記憶してますがどう実現すればいいってことになってたんでしたっけ。

[#12147] Time::local returns incorrect ending of US DST

これは結論から言うと投稿者の勘違いなのですが…

  • 2016年11月6日に米国では夏時間が切り替わった(終わった)。
  • 2:00に夏時間が終わってタイムゾーンが変わる。
  • なのにTime.localを取得するとその前の1:00の時点でもうタイムゾーンが変わってることになってる。のはおかしい!
  • しかしよく考えたら夏時間の終わりというのは時間が戻る方向に変わるので、1時間逆戻りするので、1:00という時間は2回出現するのであった。
  • なので1:00と指定するだけでは、そのどっちのインスタンスなのか指定できないから、べつにタイムゾーン変わってる方のやつが取得できても間違いというわけではなかった

夏時間はなかなか闇が深いな、という印象です。

[#2567] Net::HTTP does not handle encoding correctly

うっわ、来た。

HTTPのヘッダに”Content-Type: text/html; charset=UTF-8″とか指定されてくる場合に、net/httpでそのヘッダについてくるcharsetを無視しているのはおかしい、という主張、なんだけど…問題はそのHTTPサーバが返してくる”charset=UTF-8″とかいうのが驚くほど高確率で嘘なわけですよ。そこをどうするか。

というところで「サーバを信用すべき」派vs「信用できるか」派で膠着状態だったわけですが、今回はとりあえずforce_encodingしてみるっていうコメントが来たようですね。でもそれって以前[ruby-core:41256]で提案されてた方式よりも後退してるような…?

[#12084] Class#instance

Object#singleton_class の逆が欲しい、という提案です。しかし逆と言っても特異クラスの特異クラスの、とか連鎖してるときに逆って何が欲しいの? というのは自明ってほどじゃないのでは、とコメントされています。

[#12160] Extract XMLRPC library to bundled gem

いま標準添付ライブラリになっているXMLRPCをrakeとかみたいに標準添付gemにするのはどうだろうという提案です。誰も反対してないし、そうなるかもしれませんね。

[#12164] Binding UnboundMethod to BasicObject

いつのまにかObjectのメソッドを(継承関係を無視して)BasicObjectに移植してもエラーにならなくなってる、という指摘がありました。おそらく#11278の影響だろうとのこと。

これはこれで便利という気もしますが…でもいいのかなあ?

[#3944] Add Fiber#root? method

Fiberのrootかどうかを判定したい時があるので判定させて欲しいという要求に対して、それのユースケースは?という定番の返しがあって、こういうときに有用だよとさらに返ってきているとことです

[#12165] Hash#first, Hash#last

文字列とか配列にもあるんだからハッシュにも最初とか最後とかあってもいいじゃないかという主張です。

今だとHash#shiftもあることだし、まあ配列っぽく使えてもそんなに変じゃないかなーという気はします。が、何に使うのかはやや不透明ですね。

[#12141] send and __send__

__send__ っていう名前が気に食わないのでinvokeに変えよう(” replacing __send__ with invoke to have a better named alias”)という主張ですが、賛同者は現れていませんね。

[#12129] syntactic sugar for dynamic method dispatch object_expression:method_name_expression(1, 2)

ようするにJavaScriptぽいobj[expr](arg...)的なことがRubyでも(sendじゃなく、文法として)できるようになりたいという主張かとおもいます。

一応sendだとメソッドなので上書きされる可能性があるので、文法レベルで実装してあったほうが安定して使えるという可能性はあり、そういう意味ではありえない主張とまでは言い切れないでしょう。

[#12174] Interpolation ignores to_s (and inspect) when to_s is defined to nil.

なにかのto_sが文字列じゃない何かを返したときに”(null)”とかにすらならず、何かよくわからない感じになるのはなんででしょうという報告なのですが、これは意図的で、ようするにto_sは文字列に変換する意図で呼んでいるのに、それが文字列を返さないときに、さらに文字列に変換しようとするのは(無限ループの可能性などありえるし)不可能なので、その時点で文字列っぽく表示するのは諦めるということだそうです。

[#12176] method equality of aliased methods breakage on 2.3

メソッドにも実は==が定義されていて、それが壊れているのではないかというバグ報告です。

そんなの何に使うの、というと、テストでaliasの関係性を調べるテストを書いていて発覚したものですので、テスト方面での需要がややあるようです。

[#12134] Comparison between true and false

truefalseが比較可能になっているとたとえばソートするときに便利、という主張ですが、そこで当然「どっちが大きいのか?」という問題があり、なぜか投稿者はfalseのほうが大きいべきと主張しているので、あまり賛同が得られていないようです。

[#12095] ruby_vm_at_exit can sometime cause a crash.

ruby_vm_at_exitというのはプロセスが終わろうとしているときに呼ばれる後処理関数で、ここで落ちるというのはたとえば拡張ライブラリの中で「とうの昔に壊れていた」というやつがここに至って顕在化するパターンも多く、だいたいコア側は悪くないんじゃないかという先入観があるのですが、今回は本当にこの関数内で問題あるパターンのようですね。謙虚な心で見る必要があった…

[#11955] Expose Object that Receives logs in Logger

ログが標準出力にすでに吐かれてるとかじゃない場合に何かしたい、というニーズを満たすにはすでに標準出力に出してるかを判定する必要があるので、それを実現できる情報を外から観測可能にして欲しいという要望です。

最後のコメントが「これあと何すればマージされますか?」という質問だけど、あとはメンテナにプッシュするとかじゃないですかねえ。

[#12173] Time#till_now

用途として時間を測りたいというニーズは多々あって、それを毎回複数のTimeオブジェクトを生成して差分取るのは面倒なので、それ用のメソッドがあればいいのではないかという提案です。なんか名前で紛糾してますが…

でもそれもだけどCLOCK_MONOTONICclock_gettime(3posix)呼ぶのも重要なんじゃないかなあ

[#12104] Procs keyword arguments affect value of previous argument

procに空配列を渡してもnilに変換されてしまうというバグ報告だったのですが、これは設計どおり。配列とかそういう細かいことを気にせずなんとなく動いちゃうのがprocというもので、そういうのがいやでちゃんとちゃんとしたい人はlambdaを使いましょうという話のようです。

[#12109] Exception during class load can cause partially-loaded class

requireで読み込んだファイルの途中で例外が起きると中途半端なクラスができちゃう、という話ですが、これもそういうもの。その中途半端を避けるのであればDBと同じトランザクション分離レベルをすべてのオペレーションに実装していかないといけなくて、どう考えても現実的じゃないのですね。そういう変なことをする方が悪いってことにしないといろいろと無理があります。

[#10098] [PATCH] Timing-safe string comparison for OpenSSL::HMAC

暗号の方面でタイミング攻撃という攻撃があって、 これを防ぐような文字列比較関数が欲しいという要求です。

が、OpenSSLにすでにそういうものがありそうな気配を感じるので、今なぜかRubyから使えないようになってるけど、これをRubyから使えるようにすればいいんじゃないかという気がします。

[#12092] Allow Object#clone to yield cloned object before freezing

前回のこの番組で「ニーズがよくわからない」と書いたこの要望ですが、作者からさらに用例が提出されていますね。でもそれもまだよくわからないんだ…

特異メソッドを保持したいとかじゃなくてextendじゃいかんのかという気もしますが、逆にそれだとオブジェクトに対するextendを逐一全部管理しないといけないので、余計に難しいのかもしれません。

[#12094] parameterized property assignment: o.prop(arg) = 1

これは、o.prop(arg) = 1とか書きたいという、そのようなニーズがあることは知っているが、実装が難しいので、うまくいかないという問題です。

実装お待ちしています。

[#12020] Documenting Ruby memory model

並行並列プログラミングをやっていく上で、複数のスレッドから同じ変数を触った時にどうなるかが定義できてないと意味のある動作が記述できないし、そういうモデルを書きましょうという提案 + 実際に書いたものです。

ただメモリモデルを規定するというのは、逆にそれに縛られて自由な最適化とかがしづらくなる面もあるので、なかなか難しいところ。「やらないほうがいい」という意見もあり得るので、いろんな人がいろんな意見を出して欲しいところです。

[#12175] rb_gc_mark prevents the value from being garbage collected if called outside of a GC cycle

GCの中から呼ばれることが想定されている rb_gc_mark をGC外からミスって読んじゃうと壊れるので、GC内かどうか判定して欲しいというリクエスト。

技術的には可能ではあるんだけども、それはようするにマーク関数を再帰的に呼ぶたびにメモリ上の関係ないアドレスに逐一フラグ見に行かなきゃならんという話に他ならないわけで、そんなことすればただでさえ遅い遅いと言われてるGCにさらにペナルティになることは明らかですよね。なので個人的には乗り気ではない。

[#12124] Use Automake

いまAutomake使ってないのなんで? という疑問に対して、移植性がないからだよというあたたかいお返事がついているスレッド。

[#12172] Array#max and Array#min

Arrayに特化したメソッドを定義することで高速化できる(データ構造を前提にできるから)というのと、[a, b].max みたいのめっちゃ大量に使われるからこのパターンだけ特化命令を入れておくとさらに高速化できるぞ、という二つの提案がセットになっています。

Arrayでこれらのメソッドを定義するとEnumerable側を再定義した時にArrayに伝播しなくなるというデメリットが一応あるんですが、そうは言ってもそういうメソッドは既に他にもある(sortとか)んで、メリットのほうが明確に上回ってそうですね。

[#11997] A method to read a file with interpolations

ファイルから読み込むときも文字列リテラルと同じように#{}が使えてもいいんじゃない、それライブラリで実装するよりコアにあったほうが簡単でしょう、という提案なんだけど実はさにあらずで、#{}というのはパーサと密接に結合しているので、そこだけを取り出すのは困難(もうちょっというと状態付きlexerなのでlexerのほうの状態遷移が破綻するのが回避困難)なので、結局ライブラリで書くのと大差ない実装(一から別に書く)になってしまうので、簡単とは言いづらいのだそうです。

[#12142] Hash tables with open addressing

今月いちばん盛り上がったのはこれ。「Hash書き直した。最高2.8倍速くなった」というパッチが急に来てみんなびっくりです。

基本的な発想としてはこれまでの(教科書的な)チェイン法のハッシュではなく、オープンアドレス法を使うというもの。これによりチェイン法で必要だったポインタをたどる操作が不要になるのでオーバーヘッドがかなり削減できます。オープンアドレス法ではハッシュ値が衝突した時に後から来た方のエントリをどこか適当なところに突っ込んでおくわけですが、今回提案ではそこに線形合同法(つまりhash関数の戻り値を種とした擬似乱数列)を使っていて、HullとDobellの定理から、最悪でもどこかにスロットを発見することができることを保証しています。その発想はなかったという感じ。

ただ、実際手元にパッチ当ててみるとぐんぐん速くなるんだけど、どうもぐんぐんメモリリークしてるぽい挙動を示していて、そのあたりがツッコミ入ってる感じです。投稿者は「GCCから持ってきた」みたいなことを言ってますが、GCCと違ってRubyは長時間起動することもあるから、メモリリークへのシビアさは違いますよね…

さてそれとは別に議論になっているのがエントリ配列への添字を32bitで持つべきか64bitで持つべきかという点。理論上は64bitマシンであれば64bitで持つのが筋ではあるものの、実際に32bitの添字で足りなくなる(42億エントリくらい)には100GB程度のメインメモリが必要で、それって現実的なのかという疑問が提示されています。実のところぶっちゃけ256エントリくらいまで対応しとけば世の中の99%程度のハッシュはカバーできると思われるため、32bitでもやや持て余す感はありますが、とはいえ今実際に100GBというのは決して搭載不可能な数字ではないし、数年後確実にその桁の世界は到達するはず。今どうするのがいいのかは悩ましいです。

[#12191] Violation of ANSI aliasing rules causing problems while compiling

ANSI Cのstrict aliasing ruleに違反してる箇所があるよ、という指摘なんですが。

確かに説明とJISX3010の §6.5 あたりをよーくよーく見比べてみるとそうかなという感じです。しかし普段Rubyの実装の正当性についてJISまで読まないと判断できかねるというのは相当レアで、しかも今回は複数のマクロが展開された先でそれぞれ別のキャストが走ってる結果起きたという不幸なので、これは気づくのは厳しいなあという印象を受けます。

まあそもそもがstrict aliasing ruleはコンパイラの都合で導入されているものだと理解していますから、こういうのはコンパイラが警告してきたら粛々と対策するというのが正しい姿なのかなという気がしました。

[#12082] Tail-calling method can’t catch exception raised by tail-called method

Rubyに実は備わっている末尾呼出最適化機能で、最適化するのはいいんだけど、しすぎて例外が捕捉できなくなってしまうというバグです。パッチを読む感じだと、こういう場合は末尾呼出と見なしてはならないということのようですね。

しかし、おそらくこのバグは(致命的ぽいのに)最初から誰も気づかずにずっとあったようですね。この機能がおそらく誰にも使われてないんだろうなということ、それから、この報告者はどうやって気づいたんですかね…

[#12194] File.dirname optional parameter

いつも../../../../..とかやるの面倒(だし本質的記述ではない)、そういう機能をつけてもいいのではという提案です。ただPathnameでやりなよという返しが入ってるのは正しいし、それにさらにrequireが面倒じゃんと返っているのも感覚としては正常なので、どういう落とし所にするのがいいんでしょうね。

[#12116] Fixnum#divmod, Bignum#divmod with multiple arguments

例が秀逸で、

seconds = 289342751
minutes, seconds = seconds.divmod(60) # => [4822379, 11]
hours, minutes = minutes.divmod(60) # => [80372, 59]
days, hours = hours.divmod(24) # => [3348, 20]
years, days = days.divmod(365) # => [9, 63]

289342751.divmod(365, 24, 60, 60) # => [9, 63, 20, 59, 11]

になるよ、という、誰もが一万回は書いたことがあるユースケースを一発で解決するたいへんに優れた提案で、誰もが+1していた、のですが…

そのあとに投稿者から「実はdivmodの一般化で自然な定義はもう一種類ある」とちゃぶ台がひっくり返されていて、ええええーという感じです。みんなの+1はなんだったんだ…

[#12026] Support warning filters

いまRUBYOPT=-dすると山ほど警告出るじゃないですか。でも本当は自分の書いたコードは無警告なんだけど、意識低いライブラリとかが警告たれ流しにしてて、自分のほうは意識高いのに、他人の意識低さがフラストレーションになってしまう。それをどうにかしたいという熱いパッションですよね。それは伝わってきます。

ただ、それを実装するのにgrepでいいじゃんというのはやや安直というか、本当にそうか?というのはじっくり考える必要があるところです。あるいは実現方法に関してはライブラリに任せて、コア側からはプリミティブな機能だけを提案するといいのかもしれません。

[#12206] undef_method on prepended module undefines same-name method on prepending class

メソッドをundefしたモジュールをprependするとそのundefも優先されちゃうのはおかしいのでは、というバグ報告です。とはいえundefというのはundefっていう特殊なメソッドを定義しているような感じのものなわけでして、継承とかmixinとかが絡むとあんまり予想しないような振る舞いになるというのはこれまでもそうでしたので、prependで新たな闇が加わっただけで、まあ通常運行かなと感じてしまいます。

コメントでも指摘されている通り、remove_methodという単にメソッド定義を削除するやつもあるので、使い分けると良いでしょう。

[#12209] Array#pack(“G”) problem

GCCのみ、32bit x86のみで発生するビットの誤りというバグ。当初GCCの最適化の問題など疑いましたが、これはRubyの書き方が悪いとのこと。

背景には実はx86の浮動小数点数(x87)レジスタが64bitじゃなくて80bitあるという、今となっては歴史的事情としかいいようがない問題があります。しかしレジスタは80bitでもメモリ上は64bitなわけです。なのでレジスタにロードしたり、逆にストアしたりするときに、謎の(謎ではないが)変換が走ります。今回はエンディアンを変換した時にたまたまNaN (signaling NaN)のビットパターンになってしまったやつをレジスタにロードしてるから、そこでビットがへんになっちゃってるという話の模様です。

なおさすがにこの仕様(x87)は廃れたのでx86_64ではdeprecatedです。皆さんは普段はSSEとかそういうインストラクションセットを使っているはずかと思います。

[#12214] Inconsistent behaviour and lack of warnings/errors when referencing duplicated _variables

いまのRubyだと_というローカル変数はちょっとだけ特別扱いされていて、使っても使わなくても別に怒られたりしないということになっているのですね。なので_, _, _, _ = 1, 2, 3, 4などというふうに代入して直後に捨てるようなことをしても構わない。

構わないんだけど、それで複数回_が出現した時に、そのうちのどれが最後まで生き残るかというのが、どうもパターンによってはあやしくて、意図しないものが残ってるんではないかというのがこの報告です。

おそらく最適化か何かで代入の順序が変わっているとかかではないでしょうか。

[#12217] Introducing Enumerable#sum for precision compensated summation and revert r54237

浮動小数点数を何も考えずに足し込んでいくと、本来は回避できるはずの誤差がどんどん累積していく(という場合がある)ことが知られていて、これをちゃんと回避するための補正加算アルゴリズムが知られています。タイトルで触れられているr54237というのはこれを実装しましたというコミットでした。

しかしながらinject(:+)でこれを実装したのがよくなかった。injectはあくまで「何も考えずに足し込んでいく」っていうパターンの抽象化であって、総和そのものではないわけです。なのでそこでより「正確」な値を返すことで、逆に求めているものからずれてしまったのではないか、という考察になっています。

というわけでinjectの変更は元に戻してEnumerable#sumなるメソッドを新設しようという提案になっているわけですが、それはどうかなあ。Enumerableeach以外のメソッドの存在を仮定するのはあまり筋がよくないですよね。ここだけ例外ってのも変だし。

[#12208] Improve ri command

rubyをインストールすると一緒についてくるriというコマンドがあまり使われていないのではないか、だとしたらどう改善していけばいいかというスレッド。

たしかに自分でもri使う前にgtagsでソース見ちゃう癖がついてるので、よくないなーと思います。改善策が思い浮かぶ人はご意見いただきたいです。

[#12210] Add IdentitySet class that compares members by identity

Setというのは集合なので、同値性をどう取り扱うかに関していくらかパターンがありえます。今のSetではHashと同じ同値性を使いましょうということになっており、つまり文字列などではその内容を見ているわけですけれども、そうではなくてオブジェクトとしてのIDを使うというものも原理的にはあり得るので、そういうクラスが欲しいという提案です。

アイディア自体は悪くないと思いますが、ニーズの面でややよくわからないので、とりあえずgemとして作ってみるといいんじゃないですかねえ。需要あれば使われるだろうし、そうなってきたら本体取り込みも視野に入るのではないかという気がします。

[#12225] Remove inline assemblers and always enables USE_MACHINE_REGS

今の実装ではレジスタがある程度豊富にありそうなアーキテクチャの場合に、重要と思しき変数を強制的にレジスタに割り付けるためにGCC拡張で__asm__("r13")とかやっちゃってるのですが、その部分が書かれた時代よりも今はコンパイラのregister allocationアルゴリズムが改善されているので、外してコンパイラ任せにしてもいいのでは? という主張です。

実際に添付されているベンチマーク結果を見る感じでは、まあやってもやらなくても大差ない(つまりコンパイラも人間と同程度に賢い)ことが示されているように見えますので、人間側で複雑なことをしないというのは一つの見識かもしれません。逆に、やってもあまり効果ないなら放置でもいいのではというのもそれはそれであり得る気がします。

[#12133] Ability to exclude start when defining a range

いま、開区間を定義しようとすると、終わりが開いている半開区間は作れるけど、それ以外のパターンが作れないので、作ってほしいという要望です。けど逆にこれの便利な用途があんまり思いつかないんですよね。

Rubyの...は(もちろん)Perlから来てるし、perlop(1)によるとPerlのそれはsedから来てるらしいので、それなりに長い伝統があって、これまだ新機能入れるべきなのかなあという感じです。

[#11844] Please update unicode-licensed files (license issue)

平和裏に解決してよかった案件。

Rubyのソースコード中にはUnicode.orgで配布されているファイルのいくつかが含まれているのですが、それらのライセンスが本家の方で変わっているので、追従して欲しいというリクエストがありました。

当然なぜ?という疑問があるわけですが、それまでRubyにコピーしてあったファイルは「Unicode標準を支持するプロダクトに対して配布する」という意味の一文が含まれており、Ruby自体がUnicodeを支持するのは構わないとしても、RubyをたとえばGPLで再配布しようとしたときにUnicodeを支持することになってしまうというのは困る旨の主張でした。

その主張の真偽・是非はさておくとして、いま現在のUnicode.orgからファイルをコピーし直してくれば問題ないということだったので、これは素直にコピーし直して終了ということになりました。

[#12204] Invalid range of capital letters at Greek alphabet

('Α'..'Ω').to_aがなぜかΩで終わらない、という、あまりに不可解なバグです。これは根本の理由としてはUnicodeの中でΑとΩの間に「アサインされてないコードポイント」があるからです。このU+03A2というコードポイントはUnicodeの当該部分[PDF]では「<reserved>」と書いてある。

さらにそれはなぜかというと、このアサインされてないコードポイントに対応する小文字は実は存在するんですね。ς(U+03C2, GREEK SMALL LETTER FINAL SIGMA)というやつ。つまりギリシャ語のアルファベットにはシグマの小文字が二種類あるんだが、大文字は一種類しかない。というのを、コードポイント上にきれいにマップしようとしたらこうなるわけです。穴を開けておいたほうが対応がきれい。

それで、Unicode側はそうなっているんですが、じゃあなぜRubyはこの穴があいてるやつを単に無視するということになっていないのか。それは実は、Rubyの文字列の範囲というのは意外にも複雑な仕様になっていて、たとえば'A'..'ZZ'とかそういうパターンが書けるわけですよ。なのでZの次はAAとかそういう情報が必要。で、それをロジックでこれの次はこれ、みたいのを全部ベタ書きするのは(文字数があまりに多すぎるため)辛いにもほどがあって、なのでコードポイントに穴があいてるときはそこで終わるとみなしましょうというキメになっていたのです。実際 たとえば('あ'..'安').to_aなどとすると安までは到達せず途中で終わるのですが、それは平仮名と漢字の間に膨大な謎の文字たちが収録されているのをいちいち見たりしないようにという親切なのです。やや古いですがもう少し詳細な説明[PDF]

が、そうはいっても’Α’..’Ω’がΩまで到達しないのはありえないので、今回は穴が一個だけですぐ次があるならその穴は例外的に無視するということになりました。

[#12224] logger: Allow specifying log level in constructor

どうせloggerを使うときはログレベルも一緒に設定することが常なので、もう最初から設定できるようにすればいいのでは? という提案です。

まだ提案されてから日が浅いからなんともいえませんが、確かにログレベルは毎回設定してる気もちょっとします。

最後に

マネーフォワードでは、ruby-coreが気になって夜も眠れないエンジニアを募集しています。
ご応募お待ちしています。

【採用サイト】
マネーフォワード採用サイト
Wantedly | マネーフォワード

【プロダクト一覧】
家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』
家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 iPhone,iPad
家計簿アプリ・クラウド家計簿ソフト『マネーフォワード』 Android
クラウド型会計ソフト『MFクラウド会計』
クラウド型請求書管理ソフト『MFクラウド請求書』
クラウド型給与計算ソフト『MFクラウド給与』
経費精算システム『MFクラウド経費』
消込ソフト・システム『MFクラウド消込』
マイナンバー対応『MFクラウドマイナンバー』
創業支援トータルサービス『MFクラウド創業支援サービス』
お金に関する正しい知識やお得な情報を発信するウェブメディア『マネトク!』

Pocket