Skip to content

fezcode/go-piml

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

3 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

go-piml

go-piml is a Go package that provides functionality to marshal and unmarshal data to and from the PIML (Parenthesis Intended Markup Language) format. PIML is a human-readable, indentation-based data serialization format designed for configuration files and simple data structures.

Features

  • Intuitive Syntax: Easy-to-read key-value pairs, supporting nested structures.
  • Go-like Tagging: Uses piml:"tag" struct tags for flexible field mapping.
  • Primitive Types: Supports strings, integers, floats, and booleans.
  • Complex Types: Handles structs, slices (arrays), and maps.
  • Nil Handling: Explicitly represents nil for pointers, empty slices, and empty maps.
  • Multi-line Strings: Supports multi-line string values with indentation.
  • Comments: Allows single-line comments (lines starting with #). Inline comments are not supported. In multi-line strings, a leading # can be escaped with a backslash (\#) to be treated as a literal character.
  • Time Support: Marshals and unmarshals time.Time values using RFC3339Nano format.

PIML Format Overview

PIML uses a simple key-value structure. Keys are enclosed in parentheses (), and values follow. Indentation defines nesting.

(site_name) PIML Demo
(port) 8080
(is_production) false
(version) 1.2

(database)
  (host) localhost
  (port) 5432

(admins)
  > (User)
    (id) 1
    (name) Alice
  > (User)
    (id) 2
    (name) Bob

(features)
  > auth
  > logging
  > metrics

(description)
  This is a sample product description.
  It spans multiple lines.

  With an empty line in between.

(metadata)
(related_ids) nil

Installation

To use go-piml in your Go project, simply run:

go get github.com/fezcode/go-piml

Usage

Marshalling Go Structs to PIML

Define your Go struct with piml tags:

package main

import (
	"fmt"
	"time"
	"github.com/fezcode/go-piml"
)

type User struct {
	ID   int    `piml:"id"`
	Name string `piml:"name"`
}

type Config struct {
	SiteName    string    `piml:"site_name"`
	Port        int       `piml:"port"`
	IsProduction bool      `piml:"is_production"`
	Admins      []*User   `piml:"admins"`
	LastUpdated time.Time `piml:"last_updated"`
	Description string    `piml:"description"`
}

func main() {
	cfg := Config{
		SiteName:    "My Awesome Site",
		Port:        8080,
		IsProduction: true,
		Admins: []*User{
			{ID: 1, Name: "Admin One"},
			{ID: 2, Name: "Admin Two"},
		},
		LastUpdated: time.Date(2023, time.November, 10, 15, 30, 0, 0, time.UTC),
		Description: "This is a multi-line\ndescription for the site.",
	}

	pimlData, err := piml.Marshal(cfg)
	if err != nil {
		fmt.Println("Error marshalling:", err)
		return
	}
	fmt.Println(string(pimlData))
}

Output:

(site_name) My Awesome Site
(port) 8080
(is_production) true
(admins)
  > (User)
    (id) 1
    (name) Admin One
  > (User)
    (id) 2
    (name) Admin Two
(last_updated) 2023-11-10T15:30:00Z
(description)
  This is a multi-line
  description for the site.

Unmarshalling PIML to Go Structs

package main

import (
	"fmt"
	"time"
	"github.com/fezcode/go-piml"
)

type User struct {
	ID   int    `piml:"id"`
	Name string `piml:"name"`
}

type Config struct {
	SiteName    string    `piml:"site_name"`
	Port        int       `piml:"port"`
	IsProduction bool      `piml:"is_production"`
	Admins      []*User   `piml:"admins"`
	LastUpdated time.Time `piml:"last_updated"`
	Description string    `piml:"description"`
}

func main() {
	pimlData := []byte(`
(site_name) My Awesome Site
(port) 8080
(is_production) true
(admins)
  > (User)
    (id) 1
    (name) Admin One
  > (User)
    (id) 2
    (name) Admin Two
(last_updated) 2023-11-10T15:30:00Z
(description)
  This is a multi-line
  description for the site.
`)

	var cfg Config
	err := piml.Unmarshal(pimlData, &cfg)
	if err != nil {
		fmt.Println("Error unmarshalling:", err)
		return
	}

	fmt.Printf("%+v\n", cfg)
	for _, admin := range cfg.Admins {
		fmt.Printf("Admin: ID=%d, Name=%s\n", admin.ID, admin.Name)
	}
}

Output:

{SiteName:My Awesome Site Port:8080 IsProduction:true Admins:[0xc0000a4000 0xc0000a4020] LastUpdated:2023-11-10 15:30:00 +0000 UTC Description:This is a multi-line
description for the site.}
Admin: ID=1, Name=Admin One
Admin: ID=2, Name=Admin Two

Contributing

Contributions are welcome! Please open an issue or submit a pull request.

License

This project is licensed under the MIT License. See the LICENSE file for details.