Skip to content

Commit 01c3592

Browse files
author
James Brundage
committed
feat: Get-Turtle property support ( Fixes #102 )
Also adding internal documentation
1 parent d6ee9ae commit 01c3592

File tree

1 file changed

+106
-46
lines changed

1 file changed

+106
-46
lines changed

Commands/Get-Turtle.ps1

Lines changed: 106 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,12 @@ function Get-Turtle {
1818
if (-not $script:TurtleTypeData) {
1919
$script:TurtleTypeData = Get-TypeData -TypeName Turtle
2020
}
21-
$methodNames = @(foreach ($memberName in $script:TurtleTypeData.Members.Keys) {
22-
if ($script:TurtleTypeData.Members[$memberName] -is
23-
[Management.Automation.Runspaces.ScriptMethodData]) {
24-
$memberName
25-
}
26-
})
21+
$memberNames = @($script:TurtleTypeData.Members.Keys)
2722

2823
if ($wordToComplete) {
29-
return $methodNames -like "$wordToComplete*"
24+
return $memberNames -like "$wordToComplete*"
3025
} else {
31-
return $methodNames
26+
return $memberNames
3227
}
3328
})]
3429
[Parameter(ValueFromRemainingArguments)]
@@ -43,68 +38,133 @@ function Get-Turtle {
4338
$InputObject
4439
)
4540

46-
begin {
47-
$turtleType = Get-TypeData -TypeName Turtle
48-
$memberNames = @(foreach ($memberName in $turtleType.Members.Keys) {
49-
if (
50-
($turtleType.Members[$memberName] -is [Management.Automation.Runspaces.ScriptMethodData]) -or
51-
(
52-
$turtleType.Members[$memberName] -is
53-
[Management.Automation.Runspaces.AliasPropertyData] -and
54-
$turtleType.Members[
55-
$turtleType.Members[$memberName].ReferencedMemberName
56-
] -is [Management.Automation.Runspaces.ScriptMethodData]
57-
)
58-
) {
59-
$memberName
60-
}
61-
})
41+
begin {
42+
# Get information about our turtle pseudo-type.
43+
$turtleType = Get-TypeData -TypeName Turtle
44+
# any member name is a potential command
45+
$memberNames = $turtleType.Members.Keys
6246

63-
$memberNames = $memberNames | Sort-Object @{Expression={ $_.Length };Descending=$true}, Name
47+
# We want to sort the member names by length, in case we need them in a pattern or want to sort quickly.
48+
$memberNames = $memberNames | Sort-Object @{Expression={ $_.Length };Descending=$true}, name
49+
# Create a new turtle object in case we have no turtle input.
6450
$currentTurtle = [PSCustomObject]@{PSTypeName='Turtle'}
6551
}
6652

67-
process {
68-
53+
process {
6954
if ($PSBoundParameters.InputObject -and
7055
$PSBoundParameters.InputObject.pstypenames -eq 'Turtle') {
7156
$currentTurtle = $PSBoundParameters.InputObject
57+
} elseif ($PSBoundParameters.InputObject) {
58+
# If input was passed, and it was not a turtle, pass it through.
59+
return $PSBoundParameters.InputObject
7260
}
7361

74-
$currentMethod = $null
7562

76-
$wordsAndArguments = foreach ($arg in $ArgumentList) {
63+
# First we want to split each argument into words.
64+
# This way, it is roughly the same if you say:
65+
# * `turtle 'forward 10'`
66+
# * `turtle forward 10`
67+
# * `turtle 'forward', 10`
68+
$wordsAndArguments = @(foreach ($arg in $ArgumentList) {
69+
# If the argument is a string, split it by whitespace.
7770
if ($arg -is [string]) {
7871
$arg -split '\s{1,}'
7972
} else {
73+
# otherwise, leave the argument alone.
8074
$arg
8175
}
82-
}
76+
})
77+
78+
# Now that we have a series of words, we can process them.
79+
# We want to keep track of the current member,
80+
# and continue to the next word until we find a member name.
81+
$currentMember = $null
8382

84-
:findCommand for ($argIndex =0; $argIndex -lt $wordsAndArguments.Length; $argIndex++) {
83+
# To do this in one pass, we will iterate through the words and arguments.
84+
# We use an indexed loop so we can skip past claimed arguments.
85+
for ($argIndex =0; $argIndex -lt $wordsAndArguments.Length; $argIndex++) {
8586
$arg = $wordsAndArguments[$argIndex]
86-
if ($arg -in $memberNames) {
87-
$currentMethod = $arg
88-
for (
89-
$methodArgIndex = $argIndex + 1;
90-
$methodArgIndex -lt $wordsAndArguments.Length -and
91-
$wordsAndArguments[$methodArgIndex] -notin $memberNames;
92-
$methodArgIndex++) {
87+
# If the argument is not in the member names list, we can complain about it.
88+
if ($arg -notin $memberNames) {
89+
if (-not $currentMember -and $arg -is [string]) {
90+
Write-Warning "Unknown command '$arg'."
9391
}
94-
# Command without parameters
95-
if ($methodArgIndex -eq $argIndex) {
96-
$argList = @()
97-
$currentTurtle = $currentTurtle.$currentMethod.Invoke()
92+
continue
93+
}
94+
95+
96+
# If we have a current member, we can invoke it or get it.
97+
$currentMember = $arg
98+
# We can also begin looking for arguments
99+
for (
100+
# at the next index.
101+
$methodArgIndex = $argIndex + 1;
102+
# We will continue until we reach the end of the words and arguments,
103+
$methodArgIndex -lt $wordsAndArguments.Length -and
104+
$wordsAndArguments[$methodArgIndex] -notin $memberNames;
105+
$methodArgIndex++) {
106+
}
107+
# Now we know how long it took to get to the next member name.
108+
109+
# And we can determine if we have any parameters
110+
$argList =
111+
if ($methodArgIndex -eq ($argIndex + 1)) {
112+
@()
98113
}
99114
else {
100-
$argList = $wordsAndArguments[($argIndex + 1)..($methodArgIndex - 1)]
101-
$currentTurtle = $currentTurtle.$currentMethod.Invoke($argList)
102-
# "$($currentMethod) $($argList -join ' ')"
115+
$wordsAndArguments[($argIndex + 1)..($methodArgIndex - 1)]
103116
$argIndex = $methodArgIndex - 1
104117
}
118+
119+
# Look up the member information for the current member.
120+
$memberInfo = $turtleType.Members[$currentMember]
121+
# If it's an alias
122+
if ($memberInfo.ReferencedMemberName) {
123+
# try to resolve it.
124+
$currentMember = $memberInfo.ReferencedMemberName
125+
$memberInfo = $turtleType.Members[$currentMember]
126+
}
127+
128+
129+
# Now we want to get the output from the step.
130+
$stepOutput =
131+
if (
132+
# If the member is a method, let's invoke it.
133+
$memberInfo -is [Management.Automation.Runspaces.ScriptMethodData] -or
134+
$memberInfo -is [Management.Automation.PSMethod]
135+
) {
136+
# If we have arguments,
137+
if ($argList) {
138+
# pass them to the method.
139+
$currentTurtle.$currentMember.Invoke($argList)
140+
} else {
141+
# otherwise, just invoke the method with no arguments.
142+
$currentTurtle.$currentMember.Invoke()
143+
}
144+
} else {
145+
# If the member is a property, we can get it or set it.
146+
147+
# If we have any arguments,
148+
if ($argList) {
149+
# lets try to set it.
150+
$currentTurtle.$currentMember = $argList
151+
} else {
152+
# otherwise, lets get the property
153+
$currentTurtle.$currentMember
154+
}
155+
}
156+
157+
# If the output is not a turtle object, we can output it.
158+
# NOTE: This will lead to multiple types of output in the pipeline.
159+
# Luckily, this should be one of the few cases where this does not annoy too much.
160+
# Properties being returned will largely be strings or numbers.
161+
if (-not ($stepOutput.pstypenames -eq 'Turtle')) {
162+
$stepOutput
163+
} else {
164+
$currentTurtle = $stepOutput
105165
}
106166
}
107-
167+
108168
return $currentTurtle
109169
}
110170
}

0 commit comments

Comments
 (0)