Gumby.Object.psm1
function Dispose($Object) { if ($Object -ne $null -and $Object -is [System.IDisposable]) { $Object.Dispose() } } function DeepCopy($Original) { if ($Original -is [array]) { $copy = [Collections.ArrayList]::new() foreach ($element in $Original) { $copy.Add((DeepCopy $element)) | Out-Null } return $copy.ToArray() } elseif ($Original -is [hashtable]) { $copy = @{} foreach ($key in $Original.Keys) { $copy[$key] = DeepCopy $Original[$key] } return $copy } else { return $Original } } <# .SYNOPSIS Merges two objects. .PARAMETER Target The first of the two objects to merge. Becomes the result of the merge. .PARAMETER Source The second of the two objects to merge. .DESCRIPTION In the context of the this function, "merging" is a process that applies to arrays and hash tables. Merging two arrays results in an array that contains the elements from both input arrays, e.g. $a = 1, 3, 5 MergeObjects ([ref] $a) (2, 4, 6) results in $a being (1, 2, 3, 4, 5, 6). Merging two hash tables results in a hash table that contains the keys from both input hash tables, e.g. $a = @{ Name = "Anton" } MergeObjects ([ref] $a) @{ Age = 27 } results in $a being @{ Name = "Anton"; Age = 27 }. This function merges arrays and hash tables recursively, e.g. $a = @{ Name = "Seattle"; ZipCodes = 98101, 98103 } MergeObject ([ref] $a) @{ Population = 608660; ZipCodes = 98102, 98104 } results in $a being @{ Name = "Seattle"; Population = 608660; ZipCodes = 98101, 98102, 98103, 98104 }. Refer to the unit tests for more examples of this process. The merge alters the Target object and, by incorporating object references from the Source object into the Target object, enables potentially unexpected changes to the Source object through the resulting Target object. To prevent either, make a deep copy of the argument you wish to preserve. Currently, a key in a source hash table overwrites the same key in a target hash table. Target array elements at a given index precede source array elements at a given index. In the future, additional parameters to this function could govern different behaviors (e.g. a 'CollisionHandling' parameter with values 'TargetOverSource', 'SourceOverTarget' and 'ThrowOnCollision'; and an 'ArrayComposition' parameter with values 'TargetThenSource', 'SourceThenTarget', 'InterleaveTargetFirst', 'InterleaveSourceFirst' ...). #> function MergeObjects(<# Objects... #>) { function Mergeable($a, $b) { return ($a.GetType() -eq $b.GetType()) -and ($a -is [array] -or $a -is [hashtable]) } function MergeTwoObjects ([ref] $Target, $Source) { if (Mergeable $Target.value $Source) { if ($Target.value -is [array]) { $temp = [Collections.ArrayList]::new() $i = 0 for(; ($i -lt $Target.value.Count) -and ($i -lt $Source.Count); ++$i) { if (Mergeable $Target.value[$i] $Source[$i]) { $refable = $Target.value[$i] MergeTwoObjects ([ref]$refable) $Source[$i] $temp.Add($refable) | Out-Null } else { $temp.Add($Target.value[$i]) | Out-Null $temp.Add($Source[$i]) | Out-Null } } # in case the target array is longer than the source array for (; $i -lt $Target.value.Count; ++$i) { $temp.Add($Target.value[$i]) | Out-Null } # in case the source array is longer than the target array for (; $i -lt $Source.Count; ++$i) { $temp.Add($Source[$i]) | Out-Null } $Target.value = $temp.ToArray() } elseif ($Target.value -is [hashtable]) { foreach ($key in $Source.Keys) { if (!$Target.value.ContainsKey($key)) { $Target.value[$key] = $Source[$key] } else { $refable = $Target.value[$key] MergeTwoObjects ([ref]$refable) $Source[$key] $Target.value[$key] = $refable } } } } else { $Target.value = $Source } } $refable = $args[0] for ($i = 1; $i -lt $args.Count; ++$i) { MergeTwoObjects ([ref]$refable) $args[$i] } return $refable } <# .SYNOPSIS Integrates an array of names and an array of values into a hash table. .PARAMETER Names Array of names. The items therein become the hash table keys. .PARAMETER Values Array of values. The items therein become the hash table values. .OUTPUTS Hash table. #> function Zip($Names, $Values) { if ($Names.Length -ne $Values.Length) { throw "Number of names and values does not line up." } $hash = @{} for ($i = 0; $i -lt $Names.Length; $i++) { $hash.Add($Names[$i], $Values[$i]) } return $hash } |