functions/dsl.ps1
|
# define a domain specific language (DSL) for creating quizzes #Platyps apparently won't generate help for non-standard names so I'll use comment based help. function Quiz { <# .SYNOPSIS A PSQuiz DSL command to define a quiz .DESCRIPTION This command is used in a PSQuiz fixture, which is a PowerShell script written using the PSQuiz Domain Specific Language (DSL). This makes it easier to create a quiz. This is not a command you should run from a command prompt. It is designed to be used in a script file. Run New-PSQuizFixture to generate a script file using this DSL element. If you run the fixture script in the VSCode integrated terminal, VSCode will open the JSON file for further editing and review. The basic syntax looks like this: Quiz 'Your quiz name' -protect @( #settings hashtable must be the first element @{ Path = "c:\quiz-source\quiz-src.ps1" Author = "Art Deco" Description = "my first quiz" } #followed by a list of questions Question @{} Question @{} ) You can use -protect to mask all answers, distractors, and notes. Or you can mask individual questions. See Questions. Do not include SpectreConsole formatting in the quiz. You also do not need to escape square brackets. That will handled when the JSON file is created. .PARAMETER Name The quiz name. This should be a little descriptive, e.g. 'PowerShell Remoting Basics' .PARAMETER Protect Mask all answers, distractors, notes. If you use this, you don't need to mask individual questions. .PARAMETER Data The data used to create the quiz. The first item must be the settings hashtable. .EXAMPLE PS C:\> help about_PSQuizDSL This command is intended to be used in a script file. Read the about help topic for more information. .INPUTS None .OUTPUTS System.IO.FileInfo .LINK New-PSQuizFixture .LINK Question #> [cmdletbinding()] param( [Parameter(Position = 0, Mandatory,HelpMessage = "The quiz name")] [string]$Name, [Parameter(Position = 1, Mandatory,HelpMessage = "The data used to create the quiz" )] [object[]]$Data, [Parameter(HelpMessage = "Mask all answers and distractors")] [alias("Mask")] [switch]$Protect ) $settings = $Data[0] $splat = @{ Name = $Name Path = Split-Path $settings.Path ShortName = ($settings.Path | Split-Path -Leaf).split('.')[0] Description = $settings.Description ErrorAction = 'Stop' } #validate the path if (-not (Test-Path -path $splat.path)) { #create a detailed warning message $pro = ($Protect) ?"-protect" : $null $msg = @" `e[38;5;208m WARNING Failed to find or validate the folder: $($splat.path). You might need to update the settings hashtable. Quiz '$Name' $pro @( @{ Path = `e[3;5m$($settings.path)`e[0m`e[38;5;208m Author = $($settings.author) Description = $($settings.description) } ...`e[0m "@ Write-Host $msg Return } if ($settings.Author) { $splat['Author'] = $settings.Author } else { $splat['Author'] = [System.Environment]::UserName } Write-Host ("Creating quiz file {0}{1}{4} at {2}{3}{4}" -f "`e[96;3m",$Name,"`e[38;5;192m",$settings.Path,"`e[0m") try { $script:quizFile = New-PSQuizFile @splat if (Test-Path $script:quizFile) { $questionArray = $data | Select-Object -Skip 1 Write-Host ("{0}Updating $script:quizFile with {1} questions:{2}" -f "`e[38;5;159m",$QuestionArray.Count,"`e[0m") $questionArray | ForEach-Object { " - $($_.Question)" | Write-Host -ForegroundColor yellow } Set-PSQuizFile -Path $script:quizFile -Question $questionArray if ($Protect) { Write-Host "Protecting quiz file" -ForegroundColor magenta Protect-PSQuizFile -Path $script:quizFile } #open the file if in VSCode If ($host.Name -match 'code') { Write-Host "Opening $script:quizFile in VSCode" psedit $script:quizFile } } else { Write-Warning 'Quiz file was not created.' } } #try catch { $_ } } function Question { <# .SYNOPSIS A PSQuiz DSL command to create a quiz question .DESCRIPTION This command is intended to be used in a PSQuiz fixture to define a new quiz. Read about_PSQuizDSL to learn more. .EXAMPLE PS C:\> help about_PSQuizDSL This command is intended to be used in a script file. Read the about help topic for more information. .INPUTS None .OUTPUTS psQuizItem .LINK New-PSQuizFixture .LINK New-PSQuizQuestion .LINK Quiz #> [cmdletbinding()] param( [hashtable]$Data, [switch]$Mask ) New-PSQuizQuestion @data -MaskAnswer:$Mask } #a function to generate a DSL outline Function New-PSQuizFixture { [cmdletbinding(SupportsShouldProcess)] [OutputType("System.IO.FileInfo")] Param( [Parameter(Position = 0, Mandatory,HelpMessage = "What is the long name for your new quiz?")] [ValidateNotNullOrEmpty()] [string]$Name, [Parameter(Mandatory,HelpMessage = "Specify the path and filename for the fixture file. It should be a .ps1 file.")] [ValidatePattern('\.ps1',ErrorMessage = "The path should point to a .ps1 file.")] [ValidateScript({Split-Path $_ | Test-Path},ErrorMessage = "Failed to find or verify the parent folder for {0}")] [ValidateNotNullOrEmpty()] [string]$Path, [Parameter(HelpMessage = "Do you want to protect the file quiz file")] [switch]$Protect, [Parameter(HelpMessage = "How many initial questions do you intend to ask?")] [ValidateScript({$_ -gt 0},ErrorMessage = "You must specify a value greater than 0")] [Alias("Count")] [int]$Questions = 5 ) DynamicParam { # Open the new file in the current editor If ($host.name -eq 'Visual Studio Code Host') { $paramDictionary = New-Object -Type System.Management.Automation.RuntimeDefinedParameterDictionary # Defining parameter attributes $attributeCollection = New-Object -Type System.Collections.ObjectModel.Collection[System.Attribute] $attributes = New-Object System.Management.Automation.ParameterAttribute $attributes.ParameterSetName = '__AllParameterSets' $attributes.HelpMessage = 'Open the new quiz file in the current editor.' $attributeCollection.Add($attributes) # Defining the runtime parameter $dynParam1 = New-Object -Type System.Management.Automation.RuntimeDefinedParameter('UseEditor', [Switch], $attributeCollection) $paramDictionary.Add('UseEditor', $dynParam1) return $paramDictionary } # end if } #end DynamicParam Begin { if ($Protect) { $protectString = "-protect" } else { $protectString = $Null } } #begin Process { $base = @" #requires -version 7.6 #requires -module PSQuizMaster #This is a fixture for a new quiz file #usage: $path <# Use -protect to mask all answers, distractors, and notes Do not include SpectreConsole formatting in the quiz data here. You also can insert formatting in the quiz json file. You also do not need to escape square brackets. That will be handled when the JSON file is created. #> Quiz '$Name' $protectString @( @{ Path = # specify the full path to the quiz json file, e.g. c:\quizzes\subject.quiz.json Author = $([System.Environment]::UserName) Description = # add a meaningful one-line description } "@ for ($i = 1;$i -le $Questions;$i++) { $base += @" Question $($protect ? $null : '-mask') @{ Question = #What is your question Answer = #what is the correct answer Distractors = #enter a comma-separated list of distractors Note = #enter an optional note with more information } "@ } #adding questions #close $base += @" <# $($protect ? $null : "`n`t`tYou can remove -mask to unprotect answers") You can delete Note if not used At least 4 distractors are recommended You can delete this comment #> ) "@ $base | Out-File -FilePath $Path if ( (-Not $WhatIfPreference) -and (Test-Path $Path)) { Get-Item $Path } } #process End { if ($PSBoundParameters.ContainsKey("UseEditor")) { psedit $path } } #end } |