2020/11/19 今週の気になった bugs.ruby のチケット

内容は適当です。
今週と言っても今週みかけたチケットなだけでチケット自体は昔からあるやつもあります。
あくまでも『わたしが気になったチケット』で全ての bugs.ruby のチケットを載せているわけではありません。

[Feature #17330] Object#non

  • Object#non を追加する提案
  • Object#non の実装は以下の通り
class Object
  # ブロックの戻り値が偽ならレシーバを返し、そうでないなら nil を返す
  def non
    self unless yield(self)
  end
end

# 0 じゃない場合はレシーバを返す
p 1.non { _1.zero? }   # => 1
p 0.non { _1.zero? }   # => nil

# 空じゃない場合はレシーバを返す
p [1, 2, 3].non { _1.empty? }  # => [1, 2, 3]
p [].non { _1.empty? }         # => nil
limit = calculate.some.limit
# limit が 0 の場合は DEFAULT_LIMIT を返し、そうでない場合は limit を返す
limit.zero? ? DEFAULT_LIMIT : limit

# もしくは nonzero? メソッドを使う
# これは 0 であれば nil を返し、そうでなければレシーバを返す
calculate.some.limit.nonzero? || DEFAULT_LIMIT
# #non を使うとこんな感じ
calculate.some.limit.non(&:zero?) || DEFAULT_LIMIT
# ^ Note here, how, unlike `nonzero?`, we see predicate-y ?, but it is INSIDE the `non()` and less confusing
# params[:name] があり空でない場合は name に代入する
name = params[:name] if params[:name] && !params[:name].empty?
# ActiveSupport だと presence が使える
name = params[:name].presence
# #non を使うとこんな感じ
name = params[:name]&.non(&:empty?)
  • 最近ほしいと思った書き方
# ARGV が空の場合はデフォルト値を設定する
argv = ARGV.non(&:empty?) || ["--hoge"]
  • かなり便利そうなので標準にほしい…

[Feature #17333] Enumerable#many?

  • Enumerable#many? を追加する提案
  • ActiveSupport には同名のメソッドが定義されていて『条件にマッチする要素が 2個以上の場合』に true を返す
[1, 2, 3].many?(&:odd?)
# は以下と同じ意味
[1, 2, 3].count(&:odd?) > 1
  • ActiveSupport で定義されているもののユースケースがパッと思いつかなかった
  • 欲しい人はコメントしてアピールするといいと思います!

[Bug #17332] No error when using endless method definitions with self. setters

  • Ruby 3.0 preview1 では = がついてる endless method は定義できない
p RUBY_DESCRIPTION   # => "ruby 3.0.0preview1 (2020-09-25 master 0096d2b895) [x86_64-linux]"

# error: setter method cannot be defined in an endless method definition
def value=() = 42
  • しかし、preview1 ではクラスメソッドで = がついてるメソッドが定義できてしまうというバグ報告
p RUBY_DESCRIPTION   # => "ruby 3.0.0preview1 (2020-09-25 master 0096d2b895) [x86_64-linux]"

# OK
def value=() = 42
  • この挙動は開発版の Ruby ではすでに修正済みとなっている
p RUBY_DESCRIPTION   # => "ruby 3.0.0dev (2020-11-11T09:11:09Z master fa3670e6e4) [x86_64-linux]"

# error: setter method cannot be defined in an endless method definition
def self.value=() = 42

[Bug #11213] defined?(super) ignores respond_to_missing?

  • defined?(super) した時に #respond_to_missing? が反映されない?というバグ報告
    • 5年前のチケット
class C0
  def method_missing(*args)
    [:method_missing, *args]
  end

  def respond_to_missing?(*args)
    true
  end
end

class C1 < C0
  def foo
    # suepr を呼び出すことはできるが
    p super
    # => [:method_missing, :foo]

    # respond_to_missing? は呼ばれずに defined? は nil を返す
    p defined?(super)
    # => nil
  end
end

c1 = C1.new
c1.foo

[Feature #17328] Extend un.rb to be usable by everyone

  • Rubyun というライブラリがあって、これは以下のように Unix の基本コマンドを実行できる
$ ruby -run -e cp -- [-prv] SOURCE DEST
$ ruby -run -e ln -- [-sfv] TARGET LINK_NAME
$ ruby -run -e mv -- [-v] SOURCE DEST
$ ruby -run -e rm -- [-frv] FILE
$ ruby -run -e mkdir -- [-pv] DIRS
$ ruby -run -e rmdir -- [-v] DIRS
$ ruby -run -e install -- [-pv -m mode] SOURCE DEST
$ ruby -run -e chmod -- [-v] OCTAL-MODE FILE
$ ruby -run -e touch -- [-v] FILE
$ ruby -run -e wait_writable -- [OPTION] FILE
$ ruby -run -e mkmf -- [OPTION] EXTNAME [OPTION]
$ ruby -run -e httpd -- [OPTION] [DocumentRoot]
$ ruby -run -e help [COMMAND]
  • これは -runrequre "un" して -ecp メソッドを呼び出している、というような挙動になる
  • この require "un" した時に暗黙的に run.rb も読み込もうという提案になる
  • 例えば以下のように rub.rb を定義しておくと
def greet
  puts 'Hello!'
end
  • ruby -run -e greet のようにメソッドを呼び出すことができる
  • 便利そうだが、これは ruby run.rb -e greet すればいいだけなのでこの提案は Reject されている