Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

URI.joinが直感に反するのはなぜですか?

ここHoneybadgerでマイルストーンに到達しました。販売ページは、メインのRailsアプリの一部ではなくなりました。それは何年もの間私のウィッシュリストに載っていますが、必ずしも最優先事項ではありません。

この移行の一環として、URI.joinを使用していることに気付きました。 特定のリダイレクトリンクを構築します。しかし、私はすぐに問題に遭遇しました。 URI.join 期待どおりに動作していませんでした。

たくさんのパスフラグメントを取り、次のようにそれらをつなぎ合わせると期待していました:

# This is what I was expecting. It didn't happen.
URI.join("https://www.honeybadger.io", "plans", "change")
=> "https://www.honeybadger.io/plans/change"

joinとは 方法ははるかに奇妙です。パスフラグメントの1つを削除し、最後の「変更」のみを使用しました。

# This is what happened.
URI.join("https://www.honeybadger.io", "plans", "change")
=> "https://www.honeybadger.io/change"

では、なぜこのように機能するのでしょうか?

誤解

URI.joinを期待していたことがわかりました Array#joinの特殊バージョンと同様に動作します 、URLフラグメントを取得し、それらを組み合わせてURL全体を作成します。

それはそれがすることではありません。大きな驚き。

joinを見てみましょう メソッドのコードは、すべての引数を繰り返し処理し、mergeを呼び出すだけであることがわかります。 それぞれの。

# File uri/rfc2396_parser.rb, line 236
def join(*uris)
  uris[0] = convert_to_uri(uris[0])
  uris.inject :merge
end

マージメソッドは2つのことを行います:

  1. 「ページ」のような文字列を相対URIオブジェクトに変換します。
  2. 相対URIをベースURIに解決しようとします。これは、RFC2396のセクション5.2で指定されている方法とまったく同じように行われます。

かっこいいですが、前に述べた予期しない動作をどのように説明しますか?

URI.join("https://www.honeybadger.io", "plans", "change")
=> "https://www.honeybadger.io/change"

それをステップスルーしましょう。上記のコードは次と同等です:

URI.parse("https://www.honeybadger.io/plans").merge("change")

上記のコードは、相対URI「change」を絶対URI「https://www.honeybadger.io/plans」に対して解決しようとします。

これを行うには、RFC2396のセクション5.2.6に従い、次のように述べています。

a)ベースURIのパスコンポーネントの最後のセグメントを除くすべてがバッファにコピーされます。つまり、最後の(右端の)スラッシュ文字(存在する場合)の後の文字はすべて除外されます。

b)参照のパスコンポーネントがバッファ文字列に追加されます。

一緒に遊んでみましょう:

  1. 絶対URLの最後のセグメント以外のすべてをコピーします。 "https://www.honeybadger.io/"が表示されます
  2. 相対パスを追加すると、"https://www.honeybadger.io/change"になります。

世界は再び理にかなっています!

結論

URI.join さまざまなパスフラグメントからURLを構築するために使用できますが、これは実際には設計されたものではありません。これは、もう少し複雑なことを行うように設計されています。RFCで指定されている標準に従ってURIを再帰的にマージします。

私の個人的なプロジェクト(新しい販売ページへのリダイレクトで使用するURLを作成する)については、代わりにArray#joinを使用しました。 :)

2016年8月12日編集: この記事を公開した後、File.joinを使用することを提案するツイートをいくつか受け取りました。 この目的のために。これには、二重スラッシュを回避できるという利点があります。 /my//path ただし、パス区切り文字がスラッシュではないWindowsなどのOSでは機能しなくなります。


  1. なぜクラスを作成するのですか?

    前回の記事に続いて、なぜnilを使用するのか、私たちが当たり前と思っている他のことについてこの質問をするのは良い考えだと思いました。 いいね… 醜いコードの巨大なブロブを1つだけ持つのではなく、なぜクラスを使用するのですか? 基本的なレベルでは、クラスを使用してコードとデータを論理ユニットに編成します。 しかし、それだけではありません。 クラスを使用すると、抽象化を作成できます 。 抽象化とは何ですか? 毎日、1分ごとに抽象化を使用します。 キーボード 私はこれを入力しています: ケーブル チェリーMXブラックスイッチ すべてをまとめるプラスチックケース 電気信号をコンピュータ

  2. Windows 10 がダメな理由

    Windows 10 オペレーティング システムは世界的に有名であり、定期的な更新により独自性と信頼性を高めています。すべてのアプリとウィジェットは完璧ではありませんが、それでもかなり便利です。ただし、その設定と機能は改善される可能性があります。 Microsoft は、世界中で約 13 億人の Windows 10 ユーザーのユーザー ベースを楽しんでいます。多くの人が Windows 10 は最悪だと考えています。それは、ポップアップするさまざまな問題のためです。たとえば、ファイル エクスプローラーの破損、VMWare との互換性の問題、データの削除などの問題に直面する可能性があります。ま