2025-07-17 11:31:32 +02:00
import sys as _sys
2025-07-17 14:15:27 +02:00
import re as _re
2025-07-17 11:31:32 +02:00
import json as _json
import yaml as _yaml
import argparse as _argparse
def convey (
x ,
fs
) :
y = x
for f in fs :
y = f ( y )
return y
def string_coin (
template ,
arguments ,
options = None
) :
options = (
{
" character_open " : " {{ " ,
2025-07-17 14:15:27 +02:00
" character_close " : " }} " ,
" ignore_whitespaces " : True ,
2025-07-17 11:31:32 +02:00
}
|
( options or { } )
)
result = template
for ( key , value , ) in arguments . items ( ) :
2025-07-17 14:15:27 +02:00
pattern = (
_re . escape ( options [ " character_open " ] )
+
( " \ s* " if options [ " ignore_whitespaces " ] else " " )
+
_re . escape ( key )
+
( " \ s* " if options [ " ignore_whitespaces " ] else " " )
+
_re . escape ( options [ " character_close " ] )
)
result = _re . sub (
pattern ,
value ,
result
2025-07-17 11:31:32 +02:00
)
return result
def file_read (
path
) :
handle = open ( path , " r " )
content = handle . read ( )
handle . close ( )
return content
def handle_value (
value ,
options = None
) :
options = (
{
" indicator " : " @ " ,
}
|
( options or { } )
)
return (
file_read ( value [ len ( options [ " indicator " ] ) : ] )
2025-07-17 14:41:06 +02:00
if value . startswith ( options [ " indicator " ] ) else
2025-07-17 11:31:32 +02:00
value
)
def data_from_file (
path
) :
return (
{ }
if
( path is None )
else
(
(
lambda content : (
_json . loads ( content )
2025-07-17 14:41:06 +02:00
if path . endswith ( " .json " ) else
2025-07-17 11:31:32 +02:00
_yaml . safe_load ( content )
)
) ( file_read ( path ) )
)
)
2025-07-17 14:41:06 +02:00
def data_from_adhoc_arguments (
2025-07-17 11:31:32 +02:00
arguments
) :
return dict (
map (
lambda argument : (
(
lambda parts : (
parts [ 0 ] ,
handle_value ( parts [ 1 ] ) ,
)
) ( argument . split ( " : " , 1 ) )
) ,
( arguments or { } )
)
)
def main (
) :
## args
argument_parser = _argparse . ArgumentParser (
prog = " coin " ,
formatter_class = _argparse . ArgumentDefaultsHelpFormatter ,
2025-07-17 14:41:06 +02:00
description = " transforms a template string to its refined version by substituting its placeholders with concrete values; example: »echo ' {{ flowers}} are {{ color}} ' | coin -a flowers:roses -a color:red« " ,
)
argument_parser . add_argument (
" -t " ,
" --template-path " ,
dest = " template_path " ,
type = str ,
metavar = " <template-path> " ,
default = None ,
help = " default: read from stdin " ,
2025-07-17 11:31:32 +02:00
)
argument_parser . add_argument (
" -d " ,
" --data-path " ,
type = str ,
default = None ,
metavar = " <data-path> " ,
help = " path to JSON or YAML file, containing placeholder assignments (e.g. » { \" flowers \" : \" roses \" , \" color \" : \" red \" }«) " ,
)
argument_parser . add_argument (
" -a " ,
2025-07-17 14:41:06 +02:00
" --adhoc-argument " ,
2025-07-17 11:31:32 +02:00
type = str ,
2025-07-17 14:41:06 +02:00
dest = " adhoc_arguments " ,
2025-07-17 11:31:32 +02:00
action = " append " ,
2025-07-17 14:41:06 +02:00
metavar = " <adhoc-argument-key>:<adhoc-argument-value> " ,
2025-07-17 11:31:32 +02:00
help = " prefixing <value> with ' @ ' causes the value to be interpreted as the path to a text file, whose content shall be used " ,
)
argument_parser . add_argument (
" -o " ,
" --character-open " ,
type = str ,
default = " {{ " ,
metavar = " <character-open> " ,
help = " placeholder opening character " ,
)
argument_parser . add_argument (
" -c " ,
" --character-close " ,
type = str ,
default = " }} " ,
metavar = " <character-close> " ,
help = " placeholder closing character " ,
)
2025-07-17 14:15:27 +02:00
argument_parser . add_argument (
" -w " ,
" --heed-whitespaces " ,
action = " store_true " ,
help = " whether whitespace characters in the template string shall be heeded, i.e. not be ignored " ,
)
2025-07-17 11:31:32 +02:00
args = argument_parser . parse_args ( )
## exec
2025-07-17 14:41:06 +02:00
content_in = (
_sys . stdin . read ( )
if ( args . template_path is None ) else
file_read ( args . template_path )
)
2025-07-17 11:31:32 +02:00
data = (
data_from_file ( args . data_path )
|
2025-07-17 14:41:06 +02:00
data_from_adhoc_arguments ( args . adhoc_arguments )
2025-07-17 11:31:32 +02:00
)
content_out = string_coin (
content_in ,
data ,
{
" character_open " : args . character_open ,
" character_close " : args . character_close ,
2025-07-17 14:15:27 +02:00
" ignore_whitespaces " : ( not args . heed_whitespaces ) ,
2025-07-17 11:31:32 +02:00
}
)
_sys . stdout . write ( content_out )
main ( )