ソースコードから見るVagrantのネットワーク(2)

今回は前回のnetwork_ip.rbと同じくnetwork.rbから外部モジュールとして呼び出されているscoped_hash_override.rbを見てみましょう。
https://github.com/mitchellh/vagrant/blob/8747d938aa37e02abc20c870bb9b866a5726bc6b/lib/vagrant/util/scoped_hash_override.rb

このなかでは1つだけメソッドが定義されています。

scoped_hash_override(origianl,scope)

このメソッドはハッシュを操作するメソッドで、ソースコードには以下の例が記載されています。 ハッシュoriginalからscopeで指定した文字列に一致した要素を抜き出し新たなハッシュを作り出すようです。

    # This allows for hash options to be overridden by a scope key
    # prefix. An example speaks best here. Imagine the following hash:
    #
    #     original = {
    #       :id => "foo",
    #       :mitchellh__id => "bar",
    #       :mitchellh__other => "foo"
    #     }
    #
    #     scoped = scoped_hash_override(original, "mitchellh")
    #
    #     scoped == {
    #       :id => "bar",
    #       :other => "foo"
    #     }
    #

それではソースコードを見ていきましょう。
まず引数のscopeをto_sメソッドで文字列に変換し、ハッシュorigianlをコピーしてresultに格納します。次以降で説明する処理でハッシュoriginalの要素に行った処理をここでコピーしたハッシュresultに作用させていきます。

scope = scope.to_s
result = original.dup

次に元のハッシュoriginalの各要素に対して繰り返し処理をしていきます。

original.each do |key, value|
  parts = key.to_s.split("__", 2)

  # If we don't have the proper parts, then bail
  next if parts.length != 2

  # If this is our scope, then override
  if parts[0] == scope
    result[parts[1].to_sym] = value
  end
end

まずkeyをto_sメソッドで文字列に変換した上でsplitメソッドで配列にして返します。 splitメソッドsplit(pattern,[limit])とptternとlimitを引数にとり、patternを区切り文字で文字列を分割し、limitで指定した数字に配列の要素数を押さえます。ここではsplit("__",2)なので文字列「__」を区切り文字、要素を2つまでに押さえます。
http://ref.xaio.jp/ruby/classes/string/split

ソースコードのハッシュoriginalの例では以下のように処理されます。

①:id                 ->:id
②:mitchellh__id      ->:mitchellh, :id
③:mitchellh__other   ->:mitchellh, :other

次の制御構造のnextでif以下の条件に合致した場合は繰り返し処理を飛ばします。

  next if parts.length != 2

ここではparts.length != 2という条件なので、keyを分割(split)して作成した配列partsの要素が2以外であれば以降の処理はされずに次のkeyの処理を行います。前述のハッシュ関数の例だと①は要素が1つなので処理が飛ばされ②の処理に移ります。 ②は要素が2つなので次の処理に進みます。
次の処理では配列partsの1つ目の要素がscopeかどうかがifの条件式となっています。

  if parts[0] == scope

例ではmitchellhなので②はこの条件式に合致します。その場合は次の処理がされます。

    result[parts[1].to_sym] = value

配列の2番目の要素をシンボルにしてハッシュresultにハッシュoriginalのvalueを入れます。②ではresult[:id] = "bar"となります。このとき:idは①と同じなので、id => "foo"id => "bar"に上書きされます。
③ではresult[:other] = "foo"なので:otherがハッシュ内で重複しないので単純に追加されます。

最後にscoped_hash_overrideメソッドはハッシュresultを返り値として返します。
ハッシュresultは以下になりソースコードのハッシュの比較結果はfalseになってしまいます。。。scoped == {〜となっていてハッシュを比較しているのか、「=」を1つの間違いかなのかはわからなかったです。

    #     result = {
    #       :id => "bar",
    #       :mitchellh__id => "bar",
    #       :mitchellh__other => "foo",
    #       :other => "foo"
    #     }

testコードをみるとこの動きで正しそうでした。 https://github.com/mitchellh/vagrant/blob/8747d938aa37e02abc20c870bb9b866a5726bc6b/test/unit/vagrant/util/scoped_hash_override_test.rb