@@ -27,6 +27,7 @@ A fast and simple command-line template rendering tool using [MiniJinja](https:/
2727 - [ Path Manipulation Functions] ( #path-manipulation-functions )
2828 - [ Data Parsing Functions] ( #data-parsing-functions )
2929 - [ Data Serialization Functions] ( #data-serialization-functions )
30+ - [ Object Manipulation Functions] ( #object-manipulation-functions )
3031 - [ Validation Functions] ( #validation-functions )
3132 - [ Debugging & Development Functions] ( #debugging--development-functions )
3233- [ Advanced Examples] ( #advanced-examples )
@@ -47,9 +48,8 @@ Get started in 30 seconds:
4748# Or use Docker to copy the binary (recommended for CI/CD):
4849# Create a Dockerfile to extract the binary
4950cat > Dockerfile << 'EOF '
50- FROM ghcr.io/bordeux/tmpltool:latest AS tmpltool
5151FROM alpine:latest
52- COPY --from=tmpltool /tmpltool /usr/local/bin/tmpltool
52+ COPY --from=ghcr.io/bordeux/ tmpltool:latest /tmpltool /usr/local/bin/tmpltool
5353EOF
5454
5555docker build -t myapp .
@@ -69,6 +69,7 @@ tmpltool greeting.tmpl
6969- ** Filesystem** : Read files, check existence, list directories, glob patterns, file info, path manipulation
7070- ** Data Parsing** : Parse and read JSON, YAML, TOML files
7171- ** Data Serialization** : Convert objects to JSON, YAML, TOML strings with pretty-printing options
72+ - ** Object Manipulation** : Deep merge, get/set nested values by path, extract keys/values, check key existence
7273- ** Validation** : Validate emails, URLs, IPs, UUIDs, regex matching
7374- ** System & Network** : Get hostname, username, directories, IP addresses, DNS resolution, port availability
7475- ** Debugging & Development** : Debug output, type checking, assertions, warnings, error handling
@@ -2045,6 +2046,331 @@ port = 5432
20452046{{ to_toml(object=env_config) }}
20462047` ` `
20472048
2049+ # ## Object Manipulation Functions
2050+
2051+ Work with objects (maps/dictionaries) to merge, access nested values, and inspect structure. These functions are essential for complex configuration generation and data transformation.
2052+
2053+ # ### `object_merge(obj1, obj2)`
2054+
2055+ Deep merge two objects. When keys conflict, values from ` obj2` override values from ` obj1` . Nested objects are merged recursively.
2056+
2057+ ** Arguments:**
2058+ - ` obj1` (required) - First object (base)
2059+ - ` obj2` (required) - Second object (overlay, takes precedence)
2060+
2061+ ** Returns:** New object with merged values
2062+
2063+ ** Examples:**
2064+ ` ` ` jinja
2065+ {# Simple merge #}
2066+ {% set base = {" a" : 1, " b" : 2} %}
2067+ {% set overlay = {" c" : 3, " d" : 4} %}
2068+ {% set merged = object_merge(obj1=base, obj2=overlay) %}
2069+ {{ to_json(object=merged) }}
2070+ {# Output: {"a":1,"b":2,"c":3,"d":4} #}
2071+
2072+ {# Override values #}
2073+ {% set defaults = {" host" : " localhost" , " port" : 8080, " debug" : false} %}
2074+ {% set custom = {" port" : 3000, " debug" : true} %}
2075+ {% set config = object_merge(obj1=defaults, obj2=custom) %}
2076+ {{ to_json(object=config) }}
2077+ {# Output: {"host":"localhost","port":3000,"debug":true} #}
2078+
2079+ {# Deep merge nested objects #}
2080+ {% set base_config = {
2081+ " server" : {" host" : " localhost" , " port" : 8080},
2082+ " database" : {" host" : " db.local" , " port" : 5432}
2083+ } %}
2084+ {% set env_overrides = {
2085+ " server" : {" port" : 9000, " ssl" : true},
2086+ " cache" : {" enabled" : true}
2087+ } %}
2088+ {% set final_config = object_merge(obj1=base_config, obj2=env_overrides) %}
2089+ {{ to_json(object=final_config, pretty=true) }}
2090+ {# Output:
2091+ {
2092+ " server" : {
2093+ " host" : " localhost" ,
2094+ " port" : 9000,
2095+ " ssl" : true
2096+ },
2097+ " database" : {
2098+ " host" : " db.local" ,
2099+ " port" : 5432
2100+ },
2101+ " cache" : {
2102+ " enabled" : true
2103+ }
2104+ }
2105+ # }
2106+ ` ` `
2107+
2108+ # ### `object_get(object, path)`
2109+
2110+ Get nested value from an object using dot-separated path notation. Supports accessing nested objects and array indices.
2111+
2112+ ** Arguments:**
2113+ - ` object` (required) - Object to query
2114+ - ` path` (required) - Dot-separated path (e.g., " a.b.c" or " items.0" )
2115+
2116+ ** Returns:** Value at the specified path, or undefined if not found
2117+
2118+ ** Examples:**
2119+ ` ` ` jinja
2120+ {# Simple property access #}
2121+ {% set config = {"host": "localhost", "port": 8080} %}
2122+ {{ object_get(object=config, path="host") }}
2123+ {# Output: localhost #}
2124+
2125+ {# Nested property access #}
2126+ {% set config = {
2127+ "server": {
2128+ "database": {
2129+ "host": "db.example.com",
2130+ "port": 5432
2131+ }
2132+ }
2133+ } %}
2134+ {{ object_get(object=config, path="server.database.host") }}
2135+ {# Output: db.example.com #}
2136+
2137+ {# Array index access #}
2138+ {% set data = {"items": [10, 20, 30, 40]} %}
2139+ {{ object_get(object=data, path="items.1") }}
2140+ {# Output: 20 #}
2141+
2142+ {# Safe access with default fallback #}
2143+ {% set config = {"server": {"host": "localhost"}} %}
2144+ {% set port = object_get(object=config, path="server.port") %}
2145+ {% if port is undefined %}
2146+ Port not configured, using default: 8080
2147+ {% else %}
2148+ Port: {{ port }}
2149+ {% endif %}
2150+
2151+ {# Complex nested access #}
2152+ {% set k8s_config = {
2153+ "spec": {
2154+ "template": {
2155+ "spec": {
2156+ "containers": [
2157+ {"name": "app", "image": "myapp:latest"}
2158+ ]
2159+ }
2160+ }
2161+ }
2162+ } %}
2163+ {{ object_get(object=k8s_config, path="spec.template.spec.containers.0.image") }}
2164+ {# Output: myapp:latest #}
2165+ ` ` `
2166+
2167+ # ### `object_set(object, path, value)`
2168+
2169+ Set nested value in an object using dot-separated path notation. Creates intermediate objects as needed.
2170+
2171+ ** Arguments:**
2172+ - ` object` (required) - Object to modify
2173+ - ` path` (required) - Dot-separated path (e.g., " a.b.c" )
2174+ - ` value` (required) - Value to set
2175+
2176+ ** Returns:** New object with the value set at the specified path
2177+
2178+ ** Examples:**
2179+ ` ` ` jinja
2180+ {# Simple property set #}
2181+ {% set config = {"host": "localhost"} %}
2182+ {% set updated = object_set(object=config, path="port", value=8080) %}
2183+ {{ to_json(object=updated) }}
2184+ {# Output: {"host":"localhost","port":8080} #}
2185+
2186+ {# Set nested property #}
2187+ {% set config = {"server": {"host": "localhost"}} %}
2188+ {% set updated = object_set(object=config, path="server.port", value=8080) %}
2189+ {{ to_json(object=updated) }}
2190+ {# Output: {"server":{"host":"localhost","port":8080}} #}
2191+
2192+ {# Create nested path automatically #}
2193+ {% set config = {} %}
2194+ {% set updated = object_set(object=config, path="database.primary.host", value="db1.example.com") %}
2195+ {{ to_json(object=updated, pretty=true) }}
2196+ {# Output:
2197+ {
2198+ "database": {
2199+ "primary": {
2200+ "host": "db1.example.com"
2201+ }
2202+ }
2203+ }
2204+ #}
2205+
2206+ {# Build configuration step by step #}
2207+ {% set config = {} %}
2208+ {% set config = object_set(object=config, path="server.host", value=get_env(name="HOST", default="0.0.0.0")) %}
2209+ {% set config = object_set(object=config, path="server.port", value=get_env(name="PORT", default="8080") | int) %}
2210+ {% set config = object_set(object=config, path="database.url", value=get_env(name="DATABASE_URL")) %}
2211+ {{ to_json(object=config, pretty=true) }}
2212+ ` ` `
2213+
2214+ # ### `object_keys(object)`
2215+
2216+ Get all keys from an object as an array.
2217+
2218+ ** Arguments:**
2219+ - ` object` (required) - Object to get keys from
2220+
2221+ ** Returns:** Array of string keys
2222+
2223+ ** Examples:**
2224+ ` ` ` jinja
2225+ {# Get all keys #}
2226+ {% set config = {"host": "localhost", "port": 8080, "debug": true} %}
2227+ {% set keys = object_keys(object=config) %}
2228+ {{ to_json(object=keys) }}
2229+ {# Output: ["host","port","debug"] #}
2230+
2231+ {# Iterate over keys #}
2232+ {% set config = {"host": "localhost", "port": 8080, "debug": true} %}
2233+ Configuration keys:
2234+ {% for key in object_keys(object=config) %}
2235+ - {{ key }}
2236+ {% endfor %}
2237+ {# Output:
2238+ Configuration keys:
2239+ - host
2240+ - port
2241+ - debug
2242+ #}
2243+
2244+ {# Dynamic configuration display #}
2245+ {% set config = {
2246+ "SERVER_HOST": "localhost",
2247+ "SERVER_PORT": 8080,
2248+ "DATABASE_URL": "postgres://localhost/mydb"
2249+ } %}
2250+ # Environment Variables
2251+ {% for key in object_keys(object=config) %}
2252+ {{ key }}={{ config[key] }}
2253+ {% endfor %}
2254+ ` ` `
2255+
2256+ # ### `object_values(object)`
2257+
2258+ Get all values from an object as an array.
2259+
2260+ ** Arguments:**
2261+ - ` object` (required) - Object to get values from
2262+
2263+ ** Returns:** Array of values
2264+
2265+ ** Examples:**
2266+ ` ` ` jinja
2267+ {# Get all values #}
2268+ {% set config = {"a": 1, "b": 2, "c": 3} %}
2269+ {% set values = object_values(object=config) %}
2270+ {{ to_json(object=values) }}
2271+ {# Output: [1,2,3] #}
2272+
2273+ {# Process all values #}
2274+ {% set ports = {"http": 80, "https": 443, "app": 8080} %}
2275+ Open ports:
2276+ {% for port in object_values(object=ports) %}
2277+ - {{ port }}
2278+ {% endfor %}
2279+ {# Output:
2280+ Open ports:
2281+ - 80
2282+ - 443
2283+ - 8080
2284+ #}
2285+
2286+ {# Mixed type values #}
2287+ {% set config = {"str": "hello", "num": 42, "bool": true} %}
2288+ {% for value in object_values(object=config) %}
2289+ Value: {{ value }} (type: {{ type_of(value=value) }})
2290+ {% endfor %}
2291+ ` ` `
2292+
2293+ # ### `object_has_key(object, key)`
2294+
2295+ Check if an object has a specific key.
2296+
2297+ ** Arguments:**
2298+ - ` object` (required) - Object to check
2299+ - ` key` (required) - Key to check for
2300+
2301+ ** Returns:** Boolean - true if key exists, false otherwise
2302+
2303+ ** Examples:**
2304+ ` ` ` jinja
2305+ {# Simple key check #}
2306+ {% set config = {"host": "localhost", "port": 8080} %}
2307+ {{ object_has_key(object=config, key="host") }}
2308+ {# Output: true #}
2309+
2310+ {{ object_has_key(object=config, key="database") }}
2311+ {# Output: false #}
2312+
2313+ {# Conditional configuration #}
2314+ {% set config = {"host": "localhost", "port": 8080} %}
2315+ {% if object_has_key(object=config, key="debug") %}
2316+ Debug mode: {{ config.debug }}
2317+ {% else %}
2318+ Debug mode not configured (using default: false)
2319+ {% endif %}
2320+
2321+ {# Validate required fields #}
2322+ {% set config = read_json_file(path="config.json") %}
2323+ {% set required_keys = ["host", "port", "database_url"] %}
2324+ {% for key in required_keys %}
2325+ {% if not object_has_key(object=config, key=key) %}
2326+ ERROR: Missing required configuration key: {{ key }}
2327+ {% endif %}
2328+ {% endfor %}
2329+
2330+ {# Feature flags #}
2331+ {% set features = {"api": true, "websockets": true} %}
2332+ {% if object_has_key(object=features, key="websockets") and features.websockets %}
2333+ WebSocket support enabled
2334+ {% endif %}
2335+ ` ` `
2336+
2337+ ** Practical Example - Configuration Merging:**
2338+ ` ` ` jinja
2339+ {# Load base configuration #}
2340+ {% set base_config = read_json_file(path="config.base.json") %}
2341+
2342+ {# Load environment-specific overrides #}
2343+ {% set env = get_env(name="ENVIRONMENT", default="development") %}
2344+ {% set env_config_path = "config." ~ env ~ ".json" %}
2345+
2346+ {% if file_exists(path=env_config_path) %}
2347+ {% set env_config = read_json_file(path=env_config_path) %}
2348+ {% set config = object_merge(obj1=base_config, obj2=env_config) %}
2349+ {% else %}
2350+ {% set config = base_config %}
2351+ {% endif %}
2352+
2353+ {# Apply environment variable overrides #}
2354+ {% if get_env(name="DATABASE_URL") %}
2355+ {% set config = object_set(object=config, path="database.url", value=get_env(name="DATABASE_URL")) %}
2356+ {% endif %}
2357+
2358+ {% if get_env(name="PORT") %}
2359+ {% set config = object_set(object=config, path="server.port", value=get_env(name="PORT") | int) %}
2360+ {% endif %}
2361+
2362+ {# Validate required keys #}
2363+ {% set required = ["server.host", "server.port", "database.url"] %}
2364+ {% for key_path in required %}
2365+ {% if object_get(object=config, path=key_path) is undefined %}
2366+ ERROR: Missing required configuration: {{ key_path }}
2367+ {% endif %}
2368+ {% endfor %}
2369+
2370+ {# Output final configuration #}
2371+ {{ to_json(object=config, pretty=true) }}
2372+ ` ` `
2373+
20482374# ## System & Network Functions
20492375
20502376Access system information and perform network operations.
0 commit comments