ScriptBlock에는 GetNewClosure
라는 재미있는 함수가 있습니다. 이 함수를 사용하면 정말 Closure처럼 사용할 수 있는 객체가 리턴됩니다. 펄에서 처럼 &
문자를 사용해서 실행합니다.
closure
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
| <#
.SYNOPSIS
store logging messages and write out to the file
.DESCRIPTION
Provide logging method
.EXAMPLE
$logger = Logger -Name <filename>
To log messages:
& logger -Messages "12345", "45678", "abcde"
# accept values from pipeline
echo "123", "456", "789" | & $logger
.EXAMPLE
$logger = Logger -Name <filename> -Path c:\dc
To write output to the file:
& $logger -Flush
#>
function New-Logger {
[CmdletBinding()]
Param(
[Parameter(Position = 0)]
[String] $Path = "C:\log"
)
$buffer = [System.Text.StringBuilder]::new()
$f = {
[CmdletBinding(DefaultParameterSetName = 'Argument')]
Param(
[Parameter(Mandatory = $true, ParameterSetName = 'Argument', Position = 0)]
[Parameter(Mandatory = $true, ParameterSetName = 'Pipeline', ValueFromPipeline = $true, Position = 0)]
[Parameter(Mandatory = $false, ParameterSetName = 'Flush')]
[Object[]] $Messages,
[Parameter(ParameterSetName = 'Flush')]
[String] $Name = "log",
[Parameter(ParameterSetName = 'Flush')]
[Switch] $Flush
)
Process {
if ($Messages) {
$Messages | ForEach-Object {
Write-Debug "$_"
[void]$script:buffer.AppendLine($_)
}
}
if ($Name) {
$script:name = $Name
}
if ($Flush) {
$sLogPath = $Path
$sLogName = "$Name.txt"
$sLogFile = Join-Path -Path $sLogPath -ChildPath $sLogName
$buffer.ToString() | Out-File -FilePath $sLogFile -Encoding utf8 -Append
}
}
}.GetNewClosure()
$f
}
|
개인적인 소감은
- 간결해서 쓸만하다고 생각합니다.
- 이런 방식으로 사용하는 것에 팀원들이 거부감을 느끼지 않는다면 말이죠.
- 마치 perl의 문법을 사용하고 있는 듯한 느낌도 들었습니다.
- VSCode나 IDE에서 intellisense에 문제가 없는 지 확인해야 합니다.
class
class Logger {
[string] $Path
hidden [System.Text.StringBuilder] $buffer
hidden [void] Logging([string] $LogString) {
$this.buffer.AppendLine($LogString)
}
[void] Debug ([string] $LogString) {
Write-Debug "$LogString"
$this.Logging("[DEBUG] $LogString")
}
[void] Error ([string] $LogString) {
# do something, like send messages to chatwork
$this.Logging("[ERROR] $LogString")
}
[void] Flush ([string] $Name) {
$sLogFile = Join-Path -Path $this.Path -ChildPath "$Name.txt"
$this.buffer.ToString() | Out-File -FilePath $sLogFile -Encoding utf8 -Append
}
Logger ([string] $Path) {
$this.Path = $Path
$this.buffer = [System.Text.StringBuilder]::new()
}
Logger () {
$this.Path = "C:\log"
$this.buffer = [System.Text.StringBuilder]::new()
}
}
개인적인 소감은
- OOP적인 느낌입니다
- Closure보다는 좀 Verbose합니다.
- 조금 Closure보다는 알기 쉽습니다. 버그가 있다면 잡을 때 시간이 덜 걸릴 것입니다.
- 역시 VSCode나 IDE에서 intellisense에 문제가 없는 지 확인해야 합니다.
결론
특정상황에 좀 더 유리한 것이 있겠지만, 양쪽 다 좋습니다.
ref