Skip to content

slaff-bg/yaml-hound

Repository files navigation

YAML Hound

The package covers uncommon needs when working with YAML files.

yh := yamlhound.YAMLTracer{}
if err := yamlReader("path/to/your/test.yaml", &yh.UnmYAML); err != nil {
    panic(err.Error())
}
yh.Footprints = []string{"version"}

fmt.Println("That's what you're looking for:", yh.Caught)

MIT licensed Top Language Go Version Go Reference

What is it?

Package working with unknown (dynamic generated) YAML structures.

Why do we need it?

Sometimes it is necessary to handle frequently modified YAML structures. This is common in a rapidly growing system where the configuration YAML file structure changes periodically. These changes lead to struct-types changes in our Go code. Therefore, this package offers an interim solution until the structure finalization of the YAML file.

Table of Contents

Features

  • Retrieves a value by key or series of known keys from an unknown dynamic YAML structure.
  • Retrieve the first-level keys.
  • Retrieve the next-level subkeys of a given key.
  • Retrieve the next-level subkeys of a given subset of keys in exact order.
  • etc.

Requirements/Dependencies

NOTE

The package should also work with version go1.19, but it was developed under version go1.20, and we still have no tests with the previous one.

NOTE

To get the expected results, you should use V.3 of the gopkg.in/yaml package to unmarshalling the XML file. Do not use version V.2 or earlier of this package.

Check the tests for more technical details.

Usage

# file.yaml

# Sample scenario 1
version: "Sample scenario 1 (first level)"

# Sample scenario 2
config:
  herbivores: deer
  predators:
    amphibians: "Saltwater crocodile"
    terrestrial:
      - lion
      - tiger
      - "polar bear"
      - wolf
    flying:
      eagles: "Bald eagle" # :)
      vultures: "Bearded vulture" # :)
      owls: ["Bare-legged owl", "Barn owl", "Snowy owl"]
  omnivores:
    chickens: "Brown Leghorn"
    pigs:
      European: [4, 7]
      Asians: [7, 47]
      American: [47, 84]

# Sample scenario 3
food:
  fast-food:
    chickens: ["KFC", "Chick-fil-A", "Popeyes"]
  desserts:
    chickens: "Sex in a Pan"
  herbivores: cow
  omnivores:
    pigs:
      grilled: n/a
      in-oven: n/a

# Sample scenario 4
vegetables:
  - tomato
  - cucumber
// base example
package main

import (
	"fmt"
	"os"

	yamlhound "github.com/slaff-bg/yaml-hound"
	yaml "gopkg.in/yaml.v3"
)

func main() {
  // instance of YAMLTracer{}
  yh := yamlhound.YAMLTracer{}

  // YAMLTracer.UnmYAML: unmarshalled YAML file
  if err := yamlReader("path/to/your/file.yaml", &yh.UnmYAML); err != nil {
    panic(err.Error())
  }

  // Set YAMLTracer.Footprints: the search key or
  // strict sequence of search keys.
  // 
  // e.g. 1.1.
  // 
  // In this case, it looks for a first-level YAML key.
  yh.Footprints = []string{"version"}

  // Performs the function of finding the value by the
  // defined key (or sequence of keys).
  if err := yh.FootprintSniffer(); err != nil {
    panic(err.Error())
  }

  // Lets us know if a value was found or not.
  if yh.Found {
    fmt.Println("That's what you're looking for:", yh.Caught)
  }
}

// yamlReader read and parse YAML file.
func yamlReader(f string, c *map[string]interface{}) error {
	yamlFile, err := os.ReadFile(f)
	if err != nil {
		return err
	}

	if err := yaml.Unmarshal([]byte(yamlFile), &c); err != nil {
		return err
	}

	return nil
}
  // e.g. 1.2.
  // 
  // In this case, it looks for a third-level YAML key.
  // The keys sequence provided is part of the YAML tree 
  // nd indicates that a key belonging to a specific part
  // of the tree sequence is being sought.
  yh.Footprints = []string{"omnivores", "chickens"}
  _ := yh.FootprintSniffer()
  fmt.Println(yh.Caught) // prints: Brown Leghorn
  // e.g. 1.3.
  // 
  // Similar to the previous example, except the key
  // is part of a different sequence.
  yh.Footprints = []string{"fast-food", "chickens"}
  _ := yh.FootprintSniffer()
  fmt.Println(yh.Caught) // prints: ["KFC", "Chick-fil-A", "Popeyes"]
  // e.g. 1.4.
  // 
  // Prints <nil> because no such key is found
  // ... OR ...
  // the key is part of a structure (with no specific value).
  yh.Footprints = []string{"food"}
  _ := yh.FootprintSniffer()
  fmt.Println(yh.Caught) // prints: <nil>
  // e.g. 1.5.
  // 
  // This test case covers the scenario where we have a
  // specified key (or sequence of keys) that is contained
  // twice in the YAML file.
  // Since a map (map[string]interface{}) is handled,
  // the traversal sequence cannot be predicted during
  // an iteration.
  yh.Footprints = []string{"herbivores"}
  _ := yh.FootprintSniffer()
  fmt.Println(yh.Caught) // prints: "deer" ... OR ... "cow"
  // KeysOfKey retrieves the first-level keys of the first
  // found match against the provided key. If more than
  // one key is provided, the function looks for an exact match
  // of the sequence in the YAML tree.
  //
  // e.g. 2.1.
  //
  // If no YAMLTracer.Footprints are provided will collect
  // the first-level keys of the YAML structure.
  _ = yt.KeysOfKey()
  fmt.Println(yh.Caught) // prints: ["vegetables", "version", "config", "food"]
  // e.g. 2.2.
  //
  // First-level key WITH sub-level.
  yt.Footprints = []string{"food"}
  _ = yt.KeysOfKey()
  fmt.Println(yh.Caught) // prints: ["fast-food", "desserts", "herbivores", "omnivores"]
  // e.g. 2.3.
  //
  // Second-level key WITH sub-level.
  yt.Footprints = []string{"predators"}
  _ = yt.KeysOfKey()
  fmt.Println(yh.Caught) // prints: ["amphibians", "terrestrial", "flying"]
  // e.g. 2.4.
  //
  // Second-level key WITH sub-level by using a strict key sequence.
  yt.Footprints = []string{"config", "predators"}
  _ = yt.KeysOfKey()
  fmt.Println(yh.Caught) // prints: ["amphibians", "terrestrial", "flying"]
  // e.g. 2.5.
  //
  // Third-level key WITH sub-level by using a strict key sequence.
  yt.Footprints = []string{"predators", "flying"}
  _ = yt.KeysOfKey()
  fmt.Println(yh.Caught) // prints: ["eagles", "vultures", "owls"]
  // e.g. 2.6.
  //
  // This test case covers the scenario where we have a specified key (or
  // sequence of keys) that is contained twice in the YAML file. Since a
  // map (map[string]interface{}) is handled, the traversal sequence
  // cannot be predicted during an iteration.
  yt.Footprints = []string{"pigs"}
  _ = yt.KeysOfKey()
  fmt.Println(yh.Caught)
  // prints: ["grilled", "in-oven"]
  // ... OR ...
  // ["European", "Asians", "American"]

Contributing

To contribute to YAML Hound, clone this repo locally and commit your code on a separate branch. Please write unit tests for your code, and run the linter before opening a pull-request:

License

License rights and limitations (MIT).

About

The package covers uncommon needs when working with YAML files.

Topics

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages