Skip to content

Commit ec789b6

Browse files
Merge pull request #106 from PowerShellWeb/turtle-minor
Turtle 0.1.2
2 parents f4cc8e3 + cbd7830 commit ec789b6

File tree

11 files changed

+327
-49
lines changed

11 files changed

+327
-49
lines changed

CHANGELOG.md

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,14 @@
1+
## Turtle 0.1.2:
2+
3+
* `Get-Turtle/Turtle` can now get or set properties or methods
4+
* New Methods:
5+
* `Turtle.Distance()` determines the distance to a point
6+
* `Turtle.Towards()` determines the angle to a point
7+
* `Turtle.Home()` sends the turtle to 0,0
8+
* `Turtle.lt/rt` aliases help original Logo compatibility
9+
* `Turtle.Save()` calls Save-Turtle
10+
* Explicitly exporting commands from module
11+
112
## Turtle 0.1.1:
213

314
* Updates:

Commands/Get-Turtle.ps1

Lines changed: 126 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,13 @@
11
function Get-Turtle {
22
<#
3+
.SYNOPSIS
4+
Gets Turtle in PowerShell
5+
.DESCRIPTION
6+
Gets, sets, and moves a turtle object in PowerShell.
7+
.NOTES
8+
Each argument can be the name of a member of the turtle object.
9+
10+
After a member name is encountered, subsequent arguments will be passed to the member as parameters.
311
.EXAMPLE
412
turtle square 50
513
.EXAMPLE
@@ -8,6 +16,7 @@ function Get-Turtle {
816
turtle polygon 10 6
917
.EXAMPLE
1018
turtle ('forward', 10, 'rotate', 120 * 3)
19+
1120
#>
1221
[CmdletBinding(PositionalBinding=$false)]
1322
[Alias('turtle')]
@@ -18,17 +27,12 @@ function Get-Turtle {
1827
if (-not $script:TurtleTypeData) {
1928
$script:TurtleTypeData = Get-TypeData -TypeName Turtle
2029
}
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-
})
30+
$memberNames = @($script:TurtleTypeData.Members.Keys)
2731

2832
if ($wordToComplete) {
29-
return $methodNames -like "$wordToComplete*"
33+
return $memberNames -like "$wordToComplete*"
3034
} else {
31-
return $methodNames
35+
return $memberNames
3236
}
3337
})]
3438
[Parameter(ValueFromRemainingArguments)]
@@ -43,68 +47,143 @@ function Get-Turtle {
4347
$InputObject
4448
)
4549

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-
})
50+
begin {
51+
# Get information about our turtle pseudo-type.
52+
$turtleType = Get-TypeData -TypeName Turtle
53+
# any member name is a potential command
54+
$memberNames = $turtleType.Members.Keys
6255

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

67-
process {
68-
62+
process {
6963
if ($PSBoundParameters.InputObject -and
7064
$PSBoundParameters.InputObject.pstypenames -eq 'Turtle') {
7165
$currentTurtle = $PSBoundParameters.InputObject
66+
} elseif ($PSBoundParameters.InputObject) {
67+
# If input was passed, and it was not a turtle, pass it through.
68+
return $PSBoundParameters.InputObject
7269
}
7370

74-
$currentMethod = $null
7571

76-
$wordsAndArguments = foreach ($arg in $ArgumentList) {
72+
# First we want to split each argument into words.
73+
# This way, it is roughly the same if you say:
74+
# * `turtle 'forward 10'`
75+
# * `turtle forward 10`
76+
# * `turtle 'forward', 10`
77+
$wordsAndArguments = @(foreach ($arg in $ArgumentList) {
78+
# If the argument is a string, split it by whitespace.
7779
if ($arg -is [string]) {
7880
$arg -split '\s{1,}'
7981
} else {
82+
# otherwise, leave the argument alone.
8083
$arg
8184
}
82-
}
85+
})
8386

84-
:findCommand for ($argIndex =0; $argIndex -lt $wordsAndArguments.Length; $argIndex++) {
87+
# Now that we have a series of words, we can process them.
88+
# We want to keep track of the current member,
89+
# and continue to the next word until we find a member name.
90+
$currentMember = $null
91+
$outputTurtle = $false
92+
93+
# To do this in one pass, we will iterate through the words and arguments.
94+
# We use an indexed loop so we can skip past claimed arguments.
95+
for ($argIndex =0; $argIndex -lt $wordsAndArguments.Length; $argIndex++) {
8596
$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++) {
97+
# If the argument is not in the member names list, we can complain about it.
98+
if ($arg -notin $memberNames) {
99+
if (-not $currentMember -and $arg -is [string]) {
100+
Write-Warning "Unknown command '$arg'."
93101
}
94-
# Command without parameters
95-
if ($methodArgIndex -eq $argIndex) {
96-
$argList = @()
97-
$currentTurtle = $currentTurtle.$currentMethod.Invoke()
102+
continue
103+
}
104+
105+
106+
# If we have a current member, we can invoke it or get it.
107+
$currentMember = $arg
108+
# We can also begin looking for arguments
109+
for (
110+
# at the next index.
111+
$methodArgIndex = $argIndex + 1;
112+
# We will continue until we reach the end of the words and arguments,
113+
$methodArgIndex -lt $wordsAndArguments.Length -and
114+
$wordsAndArguments[$methodArgIndex] -notin $memberNames;
115+
$methodArgIndex++) {
116+
}
117+
# Now we know how long it took to get to the next member name.
118+
119+
# And we can determine if we have any parameters
120+
$argList =
121+
if ($methodArgIndex -eq ($argIndex + 1)) {
122+
@()
98123
}
99124
else {
100-
$argList = $wordsAndArguments[($argIndex + 1)..($methodArgIndex - 1)]
101-
$currentTurtle = $currentTurtle.$currentMethod.Invoke($argList)
102-
# "$($currentMethod) $($argList -join ' ')"
125+
$wordsAndArguments[($argIndex + 1)..($methodArgIndex - 1)]
103126
$argIndex = $methodArgIndex - 1
104127
}
128+
129+
# Look up the member information for the current member.
130+
$memberInfo = $turtleType.Members[$currentMember]
131+
# If it's an alias
132+
if ($memberInfo.ReferencedMemberName) {
133+
# try to resolve it.
134+
$currentMember = $memberInfo.ReferencedMemberName
135+
$memberInfo = $turtleType.Members[$currentMember]
136+
}
137+
138+
139+
# Now we want to get the output from the step.
140+
$stepOutput =
141+
if (
142+
# If the member is a method, let's invoke it.
143+
$memberInfo -is [Management.Automation.Runspaces.ScriptMethodData] -or
144+
$memberInfo -is [Management.Automation.PSMethod]
145+
) {
146+
# If we have arguments,
147+
if ($argList) {
148+
# pass them to the method.
149+
$currentTurtle.$currentMember.Invoke($argList)
150+
} else {
151+
# otherwise, just invoke the method with no arguments.
152+
$currentTurtle.$currentMember.Invoke()
153+
}
154+
} else {
155+
# If the member is a property, we can get it or set it.
156+
157+
# If we have any arguments,
158+
if ($argList) {
159+
# lets try to set it.
160+
$currentTurtle.$currentMember = $argList
161+
} else {
162+
# otherwise, lets get the property
163+
$currentTurtle.$currentMember
164+
}
165+
}
166+
167+
# If the output is not a turtle object, we can output it.
168+
# NOTE: This will lead to multiple types of output in the pipeline.
169+
# Luckily, this should be one of the few cases where this does not annoy too much.
170+
# Properties being returned will largely be strings or numbers.
171+
if (-not ($stepOutput.pstypenames -eq 'Turtle')) {
172+
# Output the step
173+
$stepOutput
174+
# and set the output turtle to false.
175+
$outputTurtle = $false
176+
} else {
177+
# Set the current turtle to the step output.
178+
$currentTurtle = $stepOutput
179+
# and output it later (presumably).
180+
$outputTurtle = $true
105181
}
106182
}
107-
108-
return $currentTurtle
183+
184+
# If the last members returned a turtle object, we can output it.
185+
if ($outputTurtle) {
186+
return $currentTurtle
187+
}
109188
}
110189
}

README.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22

33
<div align='center'>
44
<img src='./Examples/SierpinskiTriangle.svg' alt='SierpinskiTriangle' width='50%' />
5+
<br/>
6+
<a href='https://www.powershellgallery.com/packages/Turtle/' >
7+
<img src='https://img.shields.io/powershellgallery/dt/Turtle' />
8+
</a>
59
</div>
610

711

README.md.ps1

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ param()
1414
1515
<div align='center'>
1616
<img src='./Examples/SierpinskiTriangle.svg' alt='SierpinskiTriangle' width='50%' />
17+
<br/>
18+
<a href='https://www.powershellgallery.com/packages/Turtle/' >
19+
<img src='https://img.shields.io/powershellgallery/dt/Turtle' />
20+
</a>
1721
</div>
1822
1923

Turtle.psd1

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
@{
22
# Version number of this module.
3-
ModuleVersion = '0.1.1'
3+
ModuleVersion = '0.1.2'
44
# Description of the module
55
Description = "Turtles in a PowerShell"
66
# Script module or binary module file associated with this manifest.
@@ -16,11 +16,18 @@
1616
Copyright = '2025 Start-Automating'
1717
# Type files (.ps1xml) to be loaded when importing this module
1818
TypesToProcess = @('Turtle.types.ps1xml')
19+
20+
FunctionsToExport =
21+
'Get-Turtle',
22+
'Move-Turtle',
23+
'New-Turtle',
24+
'Set-Turtle',
25+
'Save-Turtle'
1926
# Format files (.ps1xml) to be loaded when importing this module
2027
# FormatsToProcess = @()
2128
# Functions to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no functions to export.
2229
VariablesToExport = '*'
23-
AliasesToExport = '*'
30+
AliasesToExport = 'Turtle'
2431
PrivateData = @{
2532
PSData = @{
2633
# Tags applied to this module. These help with module discovery in online galleries.
@@ -30,6 +37,17 @@
3037
# A URL to the license for this module.
3138
LicenseURI = 'https://github.com/PowerShellWeb/Turtle/blob/main/LICENSE'
3239
ReleaseNotes = @'
40+
## Turtle 0.1.2:
41+
42+
* `Get-Turtle/Turtle` can now get or set properties or methods
43+
* New Methods:
44+
* `Turtle.Distance()` determines the distance to a point
45+
* `Turtle.Towards()` determines the angle to a point
46+
* `Turtle.Home()` sends the turtle to 0,0
47+
* `Turtle.lt/rt` aliases help original Logo compatibility
48+
* `Turtle.Save()` calls Save-Turtle
49+
* Explicitly exporting commands from module
50+
3351
## Turtle 0.1.1:
3452
3553
* Updates:

0 commit comments

Comments
 (0)