Ruby 3.1: コードを単純化するために &method(:name) を使用すると、不可解にも失敗します

概要

ルビー3.1.2 クブントゥ 22.04

URI からベース ドメイン名 (サブドメインを除く) を抽出する方法:

def host_name(a)
  URI(a).host.sub(/\Awww\./, '')
end

使用:

uri_array = ['https://www.example.org', 'http://www.example.net/posts?a=1', 'www.example.com']
uri_array.map!(&method(:host_name))

期待される出力: =>

['example.org', 'example.net', 'example.com']

代わりに次のものが生成されます。

(irb):14:in `host_name': undefined method `sub' for nil:NilClass (NoMethodError)

結果の配列は次のように変更されます。

[
    [0] "example.org",
    [1] "example.net",
    [2] "www.example.com"
]

配列の 3 番目の要素で失敗する理由。

解決策

ここでの問題は、&method の使用ではなく、URI に渡される URI にあります。解析される URI にスキーム (http、https など) が含まれていない場合、URI はホスト プロパティを抽出できません。

irb(main):001> require 'uri'
=> true
irb(main):002> uri = URI('www.example.com')
=> #<URI::Generic www.example.com>
irb(main):003> uri.host
=> nil
irb(main):004> uri.path
=> "www.example.com"
irb(main):005> uri.host.sub(/\Awww\./, '')
(irb):5:in `<main>': undefined method `sub' for nil (NoMethodError)

uri.host.sub(/\Awww\./, '')
        ^^^^
        from <internal:kernel>:187:in `loop'
        from /Users/jason/.gem/ruby/3.3.0/gems/irb-1.12.0/exe/irb:9:in `<top (required)>'
        from /Users/jason/.gem/ruby/3.3.0/bin/irb:25:in `load'
        from /Users/jason/.gem/ruby/3.3.0/bin/irb:25:in `<main>'
irb(main):006>

ただし、この状況では、代わりにアドレス指定可能な gem、特に Addressable::URI.heuristic_parse を使用できます。

irb(main):001> require 'addressable'
=> true
irb(main):002> uri = Addressable::URI.heuristic_parse('www.example.com')
=> #<Addressable::URI:0x2ee0 URI:http://www.example.com>
irb(main):003> uri.host
=> "www.example.com"
irb(main):004>