Coder Social home page Coder Social logo

eps's Introduction

Build status

EPS

EPS ( Embedded PowerShell ), inspired by ERB, is a templating tool that embeds PowerShell code into a text document. It is conceptually and syntactically similar to ERB for Ruby or Twig for PHP.

EPS can be used to generate any kind of text. The example below illustrates generating plain text, but it could be used to generate HTML as in DS or PowerShell code as in the Forge Module generator.

EPS is available in the PowerShell Gallary. You can install the module with the following command:

Install-Module -Name EPS

Syntax

EPS allows PowerShell code to be embedded within a pair of <% ... %>, <%= ... %>, or <%# ... %> as well:

  • Code in <% CODE %> blocks are executed but no value is inserted.
    • If started with <%- : the preceding indentation is trimmed.
    • If terminated with -%> : the following line break is trimmed.
  • Code in <%= EXPRESSION %> blocks insert the value of EXPRESSION.
    • If terminated with -%> : the following line break is trimmed.
  • Text in <%# ... %> blocks are treated as comments and are removed from the output.
    • If terminated with -%> : the following line break is trimmed.
  • <%% and %%> : are replaced respectively by <% and %> in the output.

All blocks accept multi-line content as long as it is valid PowerShell.

Command Line Usage

Invoke-EpsTemplate [-Template <string>] [-Binding <hashtable>] [-Safe]  [<CommonParameters>]

Invoke-EpsTemplate [-Path <string>] [-Binding <hashtable>] [-Safe]  [<CommonParameters>]
  • use -Template to render the template in the corresponding string. than a file
  • use -Path to render the template in the corresponding file.
  • -Safe renders the template in isolated mode (in another thread/powershell instance) to avoid variable pollution (variable that are already in the current scope).
  • if -Safe is provided, you must bind your values using -Binding option with a Hashtable containing key/value pairs.

Example

A very simple example of EPS would be :

$name = "Dave"

Invoke-EpsTemplate -Template 'Hello <%= $name %>!'

This script produces the following result:

Hello Dave!

In a template file Test.eps:

Hi <%= $name %>

<%# this is a comment -%>
Please buy me the following items:
<% 1..5 | %{ -%>
  - <%= $_ %> pigs ...
<% } -%>

Dave is a <% if($True) { %>boy<% } else { %>girl<% } %>.

Thanks,
Dave
<%= (Get-Date -f yyyy-MM-dd) %>

Then render it in on the command line:

Import-Module EPS

$name = "ABC"
Invoke-EpsTemplate -Path Test.eps

Here it is in non-safe mode (render template with values in current run space) To use safe mode (render the template in an isolated scope) execute: Invoke-EpsTemplate -Path Test.eps -Safe with binding values

It will produce:

Hi dave

Please buy me the following items:
  - 1 pigs ...
  - 2 pigs ...
  - 3 pigs ...
  - 4 pigs ...
  - 5 pigs ...

Dave is a boy.

Thanks,
Dave
2016-12-07

Or you can use safe mode with data bindings:

Invoke-EpsTemplate -Path Test.eps -Safe -binding @{ name = "dave" }

which will generate the same output.

More examples

Multi-line code or expression blocks

You can use multi-line statements in blocks:

$name = "Dave"

Invoke-EpsTemplate -Template @'
Hello <%= $name %>!
Today is <%= Get-Date -UFormat %x %>.
'@

will produce:

Hello Dave!
Today is 11/12/17.

Iterating and joining the results

Sometimes we would like to iterate over a collection, generate some text for each element and finally join the generated blocks together with a separator.

Inside expression blocks

In an expression block we can use the following idiomatic PowerShell snippet:

Invoke-EpsTemplate -Template @'
<%= ("Id", "Name", "Description" | ForEach-Object { "[String]`$$_" }) -Join ",`n" -%>
'@

which would generate the following result:

[String]$Id,
[String]$Name,
[String]$Description

With EPS templating elements

However, due to EPS internal workings, the following code would not work:

Invoke-EpsTemplate -Template @'
<% ("Id", "Name", "Description" | ForEach-Object { -%>
[String]$<%= $_ -%>
<% }) -join ",`n" -%>
'@

The -join operator is ignored by EPS:

[String]$Id[String]$Name[String]$Description

This is expected behavior because -join is applied to the result of ForEach-Object which is defined inside a CODE block and should not produce any output.

EPS provides an internal Each function whose behavior is similar to ForEach-Object but achieves the desired result inside a template :

Each [-Process] <scriptblock> [-InputObject <Object[]>] [-Begin <scriptblock>] [-End <scriptblock>] [-Join <string>]

Each can only be used in PS v3 or above.

This snippet of EPS would generate the desired result (notice that -Join is a parameter of Each and is not applied to its result value as would be the case with the -join operator):

Invoke-EpsTemplate -Template @'
<% "Id", "Name", "Description" | Each { -%>
[String]$<%= $_ -%>
<% } -Join ",`n" -%>
'@

and generate:

[String]$Id,
[String]$Name,
[String]$Description

In some cases it can be useful to also generate a prefix and suffix to the iterated part:

Invoke-EpsTemplate -Template @'
<% "Id", "Name", "Description" | Each { -%>
[String]$<%= $_ -%>
<% } -Begin { %>[NSSession]$Session<% } -End { %>[String]$LogLevel<% } -Join ",`n" -%>
'@

will generate:

[NSSession]$Session,
[String]$Id,
[String]$Name,
[String]$Description,
[String]$LogLevel

Notice that when using -Begin and/or -End with -Join all blocks are joined together.

If you want to prefix and suffix, without joining the prefix and suffix, use the following pattern:

Invoke-EpsTemplate -Template @'
Param(
<% "Id", "Name", "Description" | Each { -%>
    [String]$<%= $_ -%>
<% } -Join ",`n" %>
)
'@

Which will generate:

Param(
    [String]$Id,
    [String]$Name,
    [String]$Description
)

Iterating with an index

In some cases it is useful to iterate over a collection while maintaining an index of the current item. The Each function exposes a $index variable to the script blocks it executes. The $index variable starts at 0 for the first element.

Invoke-EpsTemplate -Template @'
<% "Dave", "Bob", "Alice" | Each { -%>
<%= $Index + 1 %>. <%= $_ %>
<% } -%>
'@

would generate the following listing:

1. Dave
2. Bob
3. Alice

Handling default values

Using default values if the provided variable is $Null or empty (as returned by the [string]::IsNullOrEmpty function) is a very common pattern which can be done easily with a template like:

$config = [PSCustomObject]@{
  Host = "localhost"
  #Port = "8080" # this would be an optional configuration value
}
Invoke-EpsTemplate -Template @'
<%= $config.Host 
%>:<%= 
  if ([string]::IsNullOrEmpty($config.Port)) { "80" } else { $config.Port }
%>
'@

EPS provides a Get-OrElse function that allows for a shorter version:

$config = [PSCustomObject]@{
  Host = "localhost"
  #Port = "8080" # this would be an optional configuration value
}
Invoke-EpsTemplate -Template @'
<%= $config.Host %>:<%= Get-OrElse $config.Port "80" %>
<%= $config.Host %>:<%=  $config.Port | Get-OrElse -Default "80" %>
'@

Helper functions

If there's a more complicated piece of powershell code that should be reused across multiple files, it can be encapsulated in a helper function, i.e.:

$helpers = @{
   NumberedList = { 
     param($arr)
     $i = 1
     $arr | foreach-object { "$i. $_"; $i++ } | out-string 
  }
}

$helpers should be passed to Invoke-Eps:

Invoke-EpsTemplate -Path Test.eps -helpers $helpers

Now, NumberedList can be used in the template.

<%= NumberedList "Dave", "Bob", "Alice" %>

would generate the following listing:

1. Dave
2. Bob
3. Alice

Contribution

Help find more bugs! Or find more usage of this tool... Author's email: [email protected]

eps's People

Contributors

straightdave avatar dbroeglin avatar qbikez avatar kimuraw avatar

Watchers

James Cloos avatar Sytone avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.