2022/08/11 今回の気になった bugs.ruby のチケット
今週は **nil
を許容する提案などがありました。
[Feature #18959] Handle gracefully nil kwargs eg. **nil
- 以下のように『値が存在している時のみ』
Hash
に値を追加したいケースがある
{ some: 'value', **({ id: id } if id.present?), # id の値が存在していれば `{ id: id }` を Has に定義したい }
- しかし以下のように
**nil
は呼び出すことができないので上記のコードは意図する挙動をしない
def qwe(a: 1) end qwe(**nil) #=> fails with `no implicit conversion of nil into Hash (TypeError)` error { a:1, **nil } #=> fails with `no implicit conversion of nil into Hash (TypeError)` error
- 以下のようにして回避する事もできるが冗長である
h = { some: 'value' } h[:id] = id if id.present? h # または以下 { some: 'value', **(id.present? ? { id: id } : {}), }
*nil
は動作しており、以下のように書くことができるので**nil
も許容してほしいという提案- ちなみに
*nil
は[]
になる - Rails でよく使うらしい
- ちなみに
content_tag :div, class: [*('is-hero' if hero), *('is-search-page' if search_page)].presence
- ちなみに
*obj
や**obj
はobj.to_a
やobj.to_hash
が内部で呼び出される
class X def to_a ["default"] end def to_hash { default: 0 } end end x = X.new pp(*x) # => "default" pp(**x) # => {:default=>0}
- なので以下のように
nil.to_hash
を定義して対応する事は可能
# to_hash を定義しておく def nil.to_hash = {} def qwe(a: 1) end qwe(**nil) #=> OK { a:1, **nil } #=> OK
- ちなみに
nil.to_hash
を定義している場合に Ruby 2.6 で以下のケースで segv するらしい
h = {"y"=>"!"} "xyz".sub(/y/, h) #=> "x!z" h = nil "xyz".sub(/y/, h) #=> TypeError (no implicit conversion of nil into String) def nil.to_hash; {}; end "xyz".sub(/y/, h) #=> "xz" (segfault in 2.6!)
[Feature #18961] Introduce support for pattern matching all elements of an array
- 以下のように配列の全ての要素が特定のパータンの場合のパターンマッチを書きたいことがある
class Robot; end class User; end case [User.new, User.new] in [User, *] => u if u.all? { _1 in User } puts 'array of users!' end # => array of users! case [User.new, User.new, Robot.new] in [User, *] => u if u.all? { _1 in User } puts 'array of users!' end # => Error: guard clause does not return true (NoMatchingPatternError)
- これを以下のような構文で対応させいたいという提案
case [User.new, User.new] in [User*] puts 'array of users!' end
- これだけだと
u.all? { _1 in User }
でよさそうに見えるんですがパターンの一部だけに記述したい、みたいな要求はありそう
[Bug #18960] Module#using raises RuntimeError when called at toplevel from wrapped script
load
の第二引数にtrue
(またモジュール) を渡した時にトップレベルでusing
されているとエラーになるというバグ報告true
を渡すと無名モジュール内でload
したスクリプトが定義される- Kernel.#load (Ruby 3.1 リファレンスマニュアル)
# using.rb using Module.new
# OK load "./using.rb" # NG load "./using.rb", true # raises RuntimeError (main.using is permitted only at toplevel)
- こんなバグが
マージされた機能
{Method,UnboundMethod}#{public?,private?,protected?}
を RevertSymbol#to_proc
ではpublic
メソッドのみ呼び出されるように変更obj.map(&:hoge)
のhoge
はpublic
である必要がある- https://github.com/ruby/ruby/pull/6018
[Bug #18946] Time#to_date returns incorrect date
- 以下のように
1499-12-27
のTime
をDate
に変換すると1499-12-18
になるというバグ報告
require "time" time = Time.local(1499, 12, 27) pp time # => 1499-12-27 00:00:00 +091859 # 変換した日付は -9日されている pp time.to_date # => #<Date: 1499-12-18 ((2268919j,0s,0n),+0s,2299161j)>
- これは対象の日付が
ユリウス暦
として扱われているのが原因かも?- https://ja.wikipedia.org/wiki/%E3%82%B0%E3%83%AC%E3%82%B4%E3%83%AA%E3%82%AA%E6%9A%A6
- `ユリウス暦1582年10月4日木曜日の翌日を、曜日を連続させながら、グレゴリオ暦1582年10月15日金曜日とすることを定め、その通りに実施された。
# 1582-10-15 の場合 require "time" time = Time.local(1582, 10, 15) pp time # => 1582-10-15 00:00:00 +091859 # 変換前と変換後は同じ日付 pp time.to_date # => #<Date: 1582-10-15 ((2299161j,0s,0n),+0s,2299161j)>
# 1582-10-15 の場合 require "time" time = Time.local(1582, 10, 14) pp time # => 1582-10-14 00:00:00 +091859 # この日付だと変換後はユリウス暦の日付に置き換わっている pp time.to_date # => #<Date: 1582-10-04 ((2299160j,0s,0n),+0s,2299161j)>
1499-12-27
とはズレてる日数がちょっと違ってるのが気になる…- また
Time#to_datetime
とTime#to_date
で返ってくる日付が異なっている
require "date" p Time.local(1499, 12, 27).to_datetime # => #<DateTime: 1499-12-27T00:00:00-07:52 ((2268928j,28378s,0n),-28378s,2299161j)> p Time.local(1499, 12, 27).to_date # => #<Date: 1499-12-18 ((2268919j,0s,0n),+0s,2299161j)>
- これはバグだったので最新版で修正されている
- どちらもグレゴリオ暦を参照するようになる
- https://github.com/ruby/date/pull/73
require "date" p RUBY_VERSION # => "3.2.0" p Time.local(1499, 12, 27).to_datetime # => #<DateTime: 1499-12-18T00:00:00+09:18 ((2268918j,52861s,0n),+33539s,2299161j)> p Time.local(1499, 12, 27).to_date # => #<Date: 1499-12-18 ((2268919j,0s,0n),+0s,2299161j)>