provisioning/docs/src/architecture/nickel-executable-examples.md

1 line
16 KiB
Markdown
Raw Normal View History

# Nickel Executable Examples & Test Cases\n\n**Status**: Practical Developer Guide\n**Last Updated**: 2025-12-15\n**Purpose**: Copy-paste ready examples, validatable patterns, runnable test cases\n\n---\n\n## Setup: Run Examples Locally\n\n### Prerequisites\n\n```\n# Install Nickel\nbrew install nickel\n# or from source: https://nickel-lang.org/getting-started/\n\n# Verify installation\nnickel --version # Should be 1.0+\n```\n\n### Directory Structure for Examples\n\n```\nmkdir -p ~/nickel-examples/{simple,complex,production}\ncd ~/nickel-examples\n```\n\n---\n\n## Example 1: Simple Server Configuration (Executable)\n\n### Step 1: Create Contract File\n\n```\ncat > simple/server_contracts.ncl << 'EOF'\n{\n ServerConfig = {\n name | String,\n cpu_cores | Number,\n memory_gb | Number,\n zone | String,\n },\n}\nEOF\n```\n\n### Step 2: Create Defaults File\n\n```\ncat > simple/server_defaults.ncl << 'EOF'\n{\n web_server = {\n name = "web-01",\n cpu_cores = 4,\n memory_gb = 8,\n zone = "us-nyc1",\n },\n\n database_server = {\n name = "db-01",\n cpu_cores = 8,\n memory_gb = 16,\n zone = "us-nyc1",\n },\n\n cache_server = {\n name = "cache-01",\n cpu_cores = 2,\n memory_gb = 4,\n zone = "us-nyc1",\n },\n}\nEOF\n```\n\n### Step 3: Create Main Module with Hybrid Interface\n\n```\ncat > simple/server.ncl << 'EOF'\nlet contracts = import "./server_contracts.ncl" in\nlet defaults = import "./server_defaults.ncl" in\n\n{\n defaults = defaults,\n\n # Level 1: Maker functions (90% of use cases)\n make_server | not_exported = fun overrides =>\n let base = defaults.web_server in\n base & overrides,\n\n # Level 2: Pre-built instances (inspection/reference)\n DefaultWebServer = defaults.web_server,\n DefaultDatabaseServer = defaults.database_server,\n DefaultCacheServer = defaults.cache_server,\n\n # Level 3: Custom combinations\n production_web_server = defaults.web_server & {\n cpu_cores = 8,\n memory_gb = 16,\n },\n\n production_database_stack = [\n defaults.database_server & { name = "db-01", zone = "us-nyc1" },\n defaults.database_server & { name = "db-02", zone = "eu-fra1" },\n ],\n}\nEOF\n```\n\n### Test: Export and Validate JSON\n\n```\ncd simple/\n\n# Export to JSON\nnickel export server.ncl --format json | jq .\n\n# Expected output:\n# {\n# "defaults": { ... },\n# "DefaultWebServer": { "name": "web-01", "cpu_cores": 4, ... },\n# "DefaultDatabaseServer": { ... },\n# "DefaultCacheServer": { ... },\n# "production_web_server": { "name": "web-01", "cpu_cores": 8, ... },\n# "production_database_stack": [ ... ]\n# }\n\n# Verify specific fields\nnickel export server.ncl --format json | jq '.production_web_server.cpu_cores'\n# Output: 8\n```\n\n### Usage in Consumer Module\n\n```\ncat > simple/consumer.ncl << 'EOF'\nlet server = import "./server.ncl" in\n\n{\n # Use maker function\n staging_web = server.make_server {\n name = "staging-web",\n zone = "eu-fra1",\n },\n\n # Reference defaults\n default_db = server.DefaultDatabaseServer,\n\n # Use pre-built\n production_stack = server.production_database_stack,\n}\nEOF\n\n# Export and verify\nnickel export consumer.ncl --format json | jq '.staging_web'\n```\n\n---\n\n## Example 2: Complex Provider Extension (Production Pattern)\n\n### Create Provider Structure\n\n```\nmkdir -p complex/upcloud/{contracts,defaults,main}\ncd complex/upcloud\n```\n\n### Provider Contracts\n\n```\ncat > upcloud_contracts.ncl << 'EOF'\n{\n StorageBackup = {\n backup_id | String,\n frequency | String,\n retention_days | Number,\n },\n\n ServerConfig = {\n name | String,\n plan | String,\n zone | String,\n backups | Array,\n },\n\n ProviderConfig = {\n api_key | String,\n api_password | String,\n servers | Array,\n },\n}\nEOF\n```\n\n### Provider Defaults\n\n```\ncat > upcloud_defaults.ncl << 'EOF'\n{\n backup = {\n backup_id = "",\n frequency = "daily",\n retention_days = 7,\n },\n\n server = {\n name = "",\n plan = "1xCPU-1 GB",\n zone = "us-nyc1"