Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

[インデックス 11961] ファイルの概要

このコミットは、Go言語の標準ライブラリである net/url パッケージにおいて、ParseWithReference 関数を ParseWithFragment に名称変更するものです。この変更は、関数の目的をより正確に反映させ、URLのフラグメント(#以降の部分)の解析に特化していることを明確にするために行われました。また、この名称変更に伴い、既存のコードベースを自動的に更新するための go fix ツール用の新しいルールが追加されています。

コミット

  • コミットハッシュ: 8342793e7bc9ea38629893763eeef9a3f4fdc836
  • Author: David Symonds dsymonds@golang.org
  • Date: Thu Feb 16 15:56:03 2012 +1100

GitHub上でのコミットページへのリンク

https://github.com/golang/go/commit/8342793e7bc9ea386629893763eeef9a3f4fdc836

元コミット内容

net/url: Rename ParseWithReference to ParseWithFragment.

Updates #2946.

R=golang-dev, r, r
CC=golang-dev
https://golang.org/cl/5671061

変更の背景

この変更の主な背景は、net/url パッケージ内の ParseWithReference 関数の命名がその実際の機能と一致していなかった点にあります。URLの「参照(Reference)」という用語は、URIの一般的な概念においてより広範な意味を持つため、特定のURLの「フラグメント(Fragment)」部分(URLの # 以降の部分)を解析する機能を持つこの関数には誤解を招く可能性がありました。

Go言語のIssue #2946(net/url: API)では、net/url パッケージのAPIに関する議論が行われており、その中でこの命名の曖昧さが指摘されました。開発チームは、関数の名前を ParseWithFragment に変更することで、その役割をより明確にし、将来的な混乱を避けることを決定しました。これにより、コードの可読性と保守性が向上し、開発者が関数の意図をより正確に理解できるようになります。

また、このようなAPIの変更は、既存のGoプログラムに影響を与える可能性があります。Go言語では、後方互換性を維持しつつ、必要に応じてAPIの改善を行うために go fix ツールが提供されています。このコミットでは、ParseWithReference から ParseWithFragment への名称変更を自動的に処理するための go fix ルールも同時に導入されており、既存のコードベースの移行を容易にしています。

前提知識の解説

net/url パッケージ

net/url パッケージは、Go言語の標準ライブラリの一部であり、URL(Uniform Resource Locator)の解析、生成、および操作のための機能を提供します。このパッケージは、ウェブアプリケーションやネットワークプログラミングにおいて、URLを安全かつ効率的に扱うために不可欠です。

主な機能には以下のようなものがあります。

  • URLの解析: 文字列形式のURLを構造化された url.URL 型のオブジェクトに解析し、スキーム、ホスト、パス、クエリ、フラグメントなどの各コンポーネントにアクセスできるようにします。
  • URLの構築: 各コンポーネントからURL文字列を構築します。
  • クエリパラメータの操作: URLのクエリパラメータを簡単に操作するための機能を提供します。
  • エスケープ/アンエスケープ: URLエンコーディングとデコーディングを処理します。

URLのフラグメント(Fragment)

URLのフラグメントは、URLの末尾に #(ハッシュ記号)に続いて記述される部分です。例えば、http://example.com/path/to/page.html#section1 というURLでは、section1 がフラグメントです。

フラグメントは、通常、ウェブページ内の特定の部分(アンカー)を指し示すために使用されます。ブラウザは、フラグメントに基づいてページ内の指定された位置までスクロールしますが、フラグメントの情報は通常、HTTPリクエストとしてサーバーに送信されません。これは、フラグメントがクライアントサイドでのみ意味を持つ情報であるためです。

go fix ツール

go fix は、Go言語のコマンドラインツールの一つで、Goのバージョンアップに伴うAPIの変更や非推奨になった機能の使用箇所を、自動的に新しいAPIや推奨される書き方に修正するために使用されます。これにより、Go言語の進化に合わせて既存のコードベースを容易に更新できるようになります。

go fix は、Goのソースコードを解析し、特定のパターンに一致するコードを見つけると、それを定義された新しいパターンに置き換えます。このツールは、Go言語のバージョンアップ時に開発者の移行コストを大幅に削減するのに役立ちます。

このコミットでは、ParseWithReference から ParseWithFragment への名称変更を自動化するために、go fix の新しいルールが追加されました。これにより、開発者は手動で全ての呼び出し箇所を修正する必要がなくなり、よりスムーズな移行が可能になります。

技術的詳細

このコミットの技術的詳細は、主に以下の3つの側面に焦点を当てています。

  1. net/url パッケージ内の関数名称変更:

    • src/pkg/net/url/url.go ファイルにおいて、ParseWithReference 関数が ParseWithFragment に名称変更されました。
    • 関数のシグネチャも func ParseWithReference(rawurlref string) (url *URL, err error) から func ParseWithFragment(rawurl string) (url *URL, err error) に変更されています。引数名も rawurlref から rawurl に変更され、より簡潔になりました。
    • 関数内部のロジックも、引数名の変更に合わせて rawurlrefrawurl に、split 関数の戻り値の変数名が rawurl, frag から u, frag に変更されています。これにより、コードの意図がより明確になります。
    • エラーメッセージ内の引数も rawurlref から rawurl に変更され、一貫性が保たれています。
  2. テストコードの更新:

    • src/pkg/net/url/url_test.go ファイルにおいて、ParseWithReference を呼び出していたテスト関数やテストケースが、新しい ParseWithFragment を呼び出すように更新されました。
    • 具体的には、TestParseWithReference 関数が TestParseWithFragment に、DoTest および DoTestString の呼び出しにおける関数名引数も ParseWithReference から ParseWithFragment に変更されています。
    • resolveReferenceTests および TestResolveReferenceOpaque 内の mustParse ヘルパー関数も、ParseWithReference の代わりに ParseWithFragment を使用するように更新されています。これにより、変更されたAPIに対するテストカバレッジが維持されます。
  3. go fix ツールのための新しいルールの追加:

    • src/cmd/fix/url2.go および src/cmd/fix/url2_test.go という新しいファイルが追加されました。これらは、go fix ツールが ParseWithReference の呼び出しを ParseWithFragment に自動的に修正するためのルールを定義しています。
    • url2.go では、fix 構造体として url2Fix が定義され、url2 関数が実際の修正ロジックを実装しています。この url2 関数は、net/url パッケージをインポートしているファイルに対して、url.ParseWithReference の呼び出しを url.ParseWithFragment に置き換える処理を行います。go/ast パッケージを使用してAST(抽象構文木)を走査し、ast.SelectorExpr(セレクタ式、例: url.ParseWithReference)を特定して名前を書き換えます。
    • url2_test.go では、url2.go で定義された go fix ルールのテストケースが記述されています。これにより、go fix ツールが正しく機能することを確認できます。テストケースは、ParseWithReference を含む入力コードが、ParseWithFragment に修正された出力コードになることを検証します。

これらの変更は、APIの明確化、既存コードの自動移行支援、およびテストカバレッジの維持という点で、Go言語の設計思想と開発プロセスにおけるベストプラクティスを反映しています。

コアとなるコードの変更箇所

このコミットにおけるコアとなるコードの変更箇所は以下のファイルに集中しています。

  • doc/go1.html
  • doc/go1.tmpl
  • src/cmd/fix/url2.go (新規追加)
  • src/cmd/fix/url2_test.go (新規追加)
  • src/pkg/net/url/url.go
  • src/pkg/net/url/url_test.go

特に重要な変更は src/pkg/net/url/url.gosrc/cmd/fix/url2.go にあります。

src/pkg/net/url/url.go

--- a/src/pkg/net/url/url.go
+++ b/src/pkg/net/url/url.go
@@ -415,18 +415,18 @@ func parseAuthority(authority string) (user *Userinfo, host string, err error) {
 	return
 }
 
-// ParseWithReference is like Parse but allows a trailing #fragment.
-func ParseWithReference(rawurlref string) (url *URL, err error) {
+// ParseWithFragment is like Parse but allows a trailing #fragment.
+func ParseWithFragment(rawurl string) (url *URL, err error) {
 	// Cut off #frag
-\trawurl, frag := split(rawurlref, '#', true)\
-\tif url, err = Parse(rawurl); err != nil {\
+\tu, frag := split(rawurl, '#', true)\
+\tif url, err = Parse(u); err != nil {\
 \t\treturn nil, err
 \t}\
 \tif frag == "" {\
 \t\treturn url, nil
 \t}\
 \tif url.Fragment, err = unescape(frag, encodeFragment); err != nil {\
-\t\treturn nil, &Error{\"parse\", rawurlref, err}\
+\t\treturn nil, &Error{\"parse\", rawurl, err}\
 \t}\
 \treturn url, nil
 }

src/cmd/fix/url2.go (新規追加)

// Copyright 2011 The Go Authors.  All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

package main

import "go/ast"

func init() {
	register(url2Fix)
}

var url2Fix = fix{
	"url2",
	"2012-02-16",
	url2,
	`Rename some functions in net/url.

http://codereview.appspot.com/5671061
`,
}

func url2(f *ast.File) bool {
	if !imports(f, "net/url") {
		return false
	}

	fixed := false

	walk(f, func(n interface{}) {
		// Rename functions and methods.
		sel, ok := n.(*ast.SelectorExpr)
		if !ok {
			return
		}
		if !isTopName(sel.X, "url") {
			return
		}
		if sel.Sel.Name == "ParseWithReference" {
			sel.Sel.Name = "ParseWithFragment"
			fixed = true
		}
	})

	return fixed
}

コアとなるコードの解説

src/pkg/net/url/url.go の変更

このファイルでは、ParseWithReference 関数が ParseWithFragment に名称変更され、そのシグネチャと内部の実装が更新されています。

  • 関数名の変更: ParseWithReference から ParseWithFragment への変更は、この関数がURLのフラグメント部分(#以降)の解析に特化していることを明確にします。
  • 引数名の変更: rawurlref から rawurl への変更は、引数が生のURL文字列全体であることをより簡潔に示します。
  • 内部ロジックの調整: split 関数の戻り値の変数名が rawurl, frag から u, frag に変更されています。これは、rawurl という変数名が関数の引数として既に存在するため、シャドーイングを避けるための良いプラクティスです。Parse(rawurl) の代わりに Parse(u) を呼び出すことで、引数として渡された元の rawurl ではなく、フラグメント部分を切り離した後のURL文字列が Parse 関数に渡されることを保証します。
  • エラーメッセージの更新: エラー発生時に返される Error 構造体の rawurlref フィールドが rawurl に変更され、一貫性が保たれています。

これらの変更は、関数の意図を明確にし、コードの可読性と保守性を向上させることを目的としています。

src/cmd/fix/url2.go の新規追加

このファイルは、go fix ツールが ParseWithReference の呼び出しを自動的に ParseWithFragment に修正するためのロジックを定義しています。

  • init() 関数: register(url2Fix) を呼び出すことで、この修正ルールを go fix ツールに登録します。
  • url2Fix 変数: fix 構造体として定義され、この修正ルールの名前("url2")、適用日("2012-02-16")、実際の修正ロジックを実装する関数(url2)、および説明を提供します。
  • url2(f *ast.File) bool 関数:
    • imports(f, "net/url") で、現在のファイルが net/url パッケージをインポートしているかどうかを確認します。インポートしていない場合は、修正の必要がないため false を返します。
    • walk(f, func(n interface{}) { ... }) を使用して、ファイルのAST(抽象構文木)を走査します。ASTは、Goのソースコードを構造化されたツリー形式で表現したものです。
    • 走査中に、各ノードが *ast.SelectorExpr(セレクタ式、例: url.ParseWithReference)であるかどうかを確認します。
    • isTopName(sel.X, "url") で、セレクタ式の左側(sel.X)が url という名前(つまり、url.ParseWithReferenceurl 部分)であるかどうかを確認します。
    • sel.Sel.Name == "ParseWithReference" で、セレクタ式の右側(sel.Sel.Name)が ParseWithReference であるかどうかを確認します。
    • これらの条件がすべて満たされた場合、sel.Sel.Name = "ParseWithFragment" を実行して、関数名を ParseWithFragment に書き換えます。
    • fixed = true を設定し、ファイルが修正されたことを示します。
    • 最終的に fixed の値を返すことで、go fix ツールにファイルが変更されたかどうかを通知します。

この go fix ルールにより、開発者は手動でコードを修正する手間を省き、Go言語のAPI変更に迅速に対応できるようになります。

関連リンク

参考にした情報源リンク