CDSoft / pp

PP - Generic preprocessor (with pandoc in mind) - macros, literate programming, diagrams, scripts...
http://cdelord.fr/pp
GNU General Public License v3.0
252 stars 21 forks source link

Question: execute a shell call only once and reuse the result? #101

Closed schittli closed 3 years ago

schittli commented 3 years ago

Good evening

It is an excellent feature that we can execute a PowerShell script with !powershell(...) and then use the result in PP macros.

This way, we can e.g. create a new GUID every time we call the PP macro:

// PP-Macro
!define[GetNewGUID][!powershell((New-Guid).guid)]

// Usage: PP creates a new GUID, e.g. a3f1a53d-…-…-…-…
!GetNewGUID
// Usage: PP creates a new GUID, e.g. 900aa310-…-…-…-…
!GetNewGUID

Is it somehow possible to evaluate the result of a shell call only once and reuse the same result multiple times?

I tried to use !quiet() and !eval() combined with !ifdef() but I did not found a working solution. It should act as following:

// PP-Macro
!define[GetNewGUIDOnce][ ??? ]

// First usage: PP creates a new GUID, e.g. 30548337-…-…-…-…
!GetNewGUIDOnce
// 2nd usage: PP reuses the GUID, e.g. 30548337-…-…-…-…
!GetNewGUIDOnce

My failed tests

I tried to use !quiet() and !pp(), but it does not work :-(

// The Macro !GetRandomInt calls PowerShell and returns an random int
!define[GetRandomInt][!powershell(Get-Random)]

// Test 1: Try to dynamically create a new pp macro
!define[Static_GetRandomInt_Test1][!GetRandomInt]

// Test 2: use !quiet(), Variant 1: !quiet() is used to call the !GetRandomInt macro:
!define[Static_GetRandomInt_Test2][!quiet(!GetRandomInt)]

// Test 3: use !quiet(), Variant 2: !quiet() is used to declare the new macro:
!quiet(!define[Static_GetRandomInt_Test3][!GetRandomInt])

// Test 4: use !pp(), Variant 1: !pp() is used to call the !GetRandomInt macro:
!define[Static_GetRandomInt_Test4][!pp(!GetRandomInt)]

// Test 5: use !pp(), Variant 1: !pp() is used to call the !GetRandomInt macro:
!pp(!define[Static_GetRandomInt_Test5][!GetRandomInt])

Thanks a lot for any help, kind regards, Thomas

CDSoft commented 3 years ago

Hi, A simple solution would be to generate this value once before calling pp. e.g. on bash with $RANDOM: pp -DGUID=$RANDOM. Then !GUID is a constant always returning the same number.

➜ echo '!UID !UID' | pp -DUID=$RANDOM
19090 19090

When a macro is called its value is recomputed by evaluating its definition. So if you define:

!define(GUID)(
    !ifndef(_GUID)(!define(_GUID)(!sh(echo $RANDOM)))
    !_GUID
)

Then _GUID is defined once but its definition is !sh(echo $RANDOM) and you get a new random number each time you call GUID.

CDSoft commented 3 years ago

pp evaluation is sometimes a bit tricky. I have written a much simpler preprocessor (https://github.com/CDSoft/upp) that can be scripted in Lua. e.g.:

:(guid = math.random())

$(guid)
$(guid)
$(guid)

or with an external command (bash, powershell, ...):

:(guid = io.popen("echo $RANDOM"):read())

$(guid)
$(guid)
$(guid)

:(...) is a block of Lua code that is executed but nothing is returned to the document (unless the block explicitly returns a non nil value). $(...) is a Lua expression which value will appear in the document.

schittli commented 3 years ago

Thank you very much, @CDSoft, for your great support!

I'm still studying UPP as well - generic text preprocessors are a tricky and surprisingly exciting topic... and very useful :-)