# encoding: ascii # api: powershell # title: lost operators # description: Adds imitations of some operators such as ternary operator, -all, -any and etc. # version: 0.1 # type: script # author: poshman # license: CC0 # function: Invoke-LostOperator # x-poshcode-id: 6492 # x-archived: 2016-09-04T23:41:46 # x-published: 2016-08-29T07:34:00 # # # Script is not mine, see # Post on Twitter https://mobile.twitter.com/gregzakharov/status/769974270046904320 Set-Alias ~! Invoke-LostOperator function Invoke-LostOperator { <# .SYNOPSIS Compensates lack of some operators. .DESCRIPTION This function has alias "~!". It seems the best way to warn user about that an operator does not really exist. .EXAMPLE PS C:\> ~! @(1, 2, 3, 4, 5) -any '($x % 2) -eq 0' True .EXAMPLE PS C:\> ~! @(2, 4, 6, 8, 10) -all '($x % 2) -eq 0' False .EXAMPLE PS C:\> ~! @('this', 'is', 'array', 1, 2, 3) -first '$x.GetTtpe().Name -eq "Int32"' 1 .EXAMPLE PS C:\> ~! @('this', 'is', 'array', 1, 2, 3) -last '$x.GetType().Name -eq "String"' array .EXAMPLE PS C:\> ~! 7 -shl 3 56 .EXAMPLE PS C:\> ~! 7 -shr 1 3 .EXAMPLE PS C:\> ~! @('this', 'is', 'array', 1, 2, 3) -skip 3 1 2 3 .EXAMPLE PS C:\> ~! @('this', 'is', 'array', 1, 2, 3) -take 3 this is array .EXAMPLE PS C:\> $x = 10 # do something with this variable PS C:\> ~! ($x -gt 30) ? { $x + 5 } : { $x - 3 } .NOTES Operators -shl and -shr are not required for usage on PowerShell -ge 3. Alternative way to simulate a shift method on PowerShell -eq 2: PS C:\> $(cmd /c set /a 7 ^<^< 3);'' 56 PS C:\> $(cmd /c set /a 7 ^>^> 1);'' 3 To get all PowerShell -eq 2 operators: if ($PSVersionTable.PSVersion.Major -eq 2) { [PSObject].Assembly.GetType( 'System.Management.Automation.OperatorTokenReader' ).GetFields([Reflection.BindingFlags]40) | Where-Object { $_.Name -match 'operators\Z' } | Sort-Object Name | ForEach-Object { Write-Host "$($_.Name.Replace( 'Operators', '' )): " -ForegroundColor Green -NoNewLine Write-Host ( $_.GetValue($null) -join ', ' ) -ForegroundColor Yellow } } #> begin { if ($PSVersionTable.PSVersion.Major -eq 2) { @( [Reflection.Emit.DynamicMethod], [Reflection.Emit.OpCodes] ) | ForEach-Object { $keys = ($ta = [PSObject].Assembly.GetType( 'System.Management.Automation.TypeAccelerators' ))::Get.Keys $collect = @() }{ if ($keys -notcontains $_.Name) { $ta::Add($_.Name, $_) } $collect += $_.Name } function private:Set-Shift { param( [Parameter(Position=0)] [ValidateNotNullOrEmpty()] [ValidateSet('Left', 'Right')] [String]$Direction = 'Left', [Parameter(Position=1)] [ValidateNotNull()] [Object]$Type = [Int32] ) @( 'Ldarg_0' 'Ldarg_1' 'Ldc_I4_S, 31' 'And' $(if ($Direction -eq 'Right') { 'Shr' } else { 'Shl' }) 'Ret' ) | ForEach-Object { $def = New-Object DynamicMethod( $Direction, $Type, @($Type, $Type) ) $il = $def.GetILGenerator() }{ if ($_ -notmatch ',') { $il.Emit([OpCodes]::$_) } else { $il.Emit( [OpCodes]::(($$ = $_.Split(','))[0]), ($$[1].Trim() -as $Type) )} } $def.CreateDelegate(( Invoke-Expression "[Func[$($Type.Name), $($Type.Name), $($Type.Name)]]" )) } } function private:Invoke-Eval { param( [Parameter(Mandatory=$true)] [Object]$Object ) if ($Object -ne $null) { if ($Object -is 'ScriptBlock') { return &$Object } return $Object } return $null } function private:Invoke-Linq { param( [Parameter(Mandatory=$true, Position=0)] [ValidateNotNullOrEmpty()] [String]$Method, [Parameter(Mandatory=$true, Position=1)] [ValidateNotNull()] [Object[]]$Collection, [Parameter(Mandatory=$true, Position=2)] [ValidateNotNullOrEmpty()] [String]$Condition, [Parameter(Position=3)] [Type[]]$Type = [Object] ) $m = ([Linq.Enumerable].GetMember( $Method, [Reflection.MemberTypes]8, [Reflection.BindingFlags]24 ) | Where-Object { $_.IsGenericMethod -and $_.GetParameters( ).Length -eq 2 }).MakeGenericMethod($Type) switch -Regex ($Method) { '\A(Skip|Take)\Z' { $i = 0 if (![Int32]::TryParse($Condition, [ref]$i)) { return $null } $m.Invoke($null, @($Collection, $i)) } '\A(All|Any|First|Last)\Z' { $e = Invoke-Expression "[Func[$Type, Boolean]]{param( $(([Regex]'\$\w+').Match($Condition).Value) ) $Condition}" $m.Invoke($null, @($Collection, $e)) } } } } process { if ($args) { $l = [Array]::IndexOf($args, $args[1]) + 1 switch ($args.Length) { 3 { switch -Regex ($args[1]) { '\A-(any|all|first|last|skip|take)\Z' { return Invoke-Linq "$([Char]::ToUpper($args[1][1]) )$(-join $args[1][2..$args[1].Length])" $args[0] $args[$l] } '\A-sh(l|r)\Z' { # do not use it on PowerShell -ge 3 if ($collect) { return (Set-Shift $(switch ( $args[1][-1]) {'l'{'Left'}'r'{'Right'}}) ).Invoke($args[0], $args[$l]) } } } } # -any, -all, -first, -last, -shl, -shr, -skip and -take 5 { if (Invoke-Eval $args[0]) { return Invoke-Eval $args[$l] } return Invoke-Eval ($args[[Array]::IndexOf($args, ':', $l) + 1]) } # ternary } return Invoke-Eval $args[0] } } end { if ($collect) { $collect | ForEach-Object { [void]$ta::Remove($_) } } } }