<commit_before>package yaml

import (
	"bytes"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// A File represents the top-level YAML node found in a file.  It is intended
// for use as a configuration file.
type File struct {
	Root Node

	// TODO(kevlar): Add a cache?
}

// ReadFile reads a YAML configuration file from the given filename.
func ReadFile(filename string) (*File, error) {
	fin, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer fin.Close()

	f := new(File)
	f.Root, err = Parse(fin)
	if err != nil {
		return nil, err
	}

	return f, nil
}

// Config reads a YAML configuration from a static string.  If an error is
// found, it will panic.  This is a utility function and is intended for use in
// initializers.
func Config(yamlconf string) *File {
	var err error
	buf := bytes.NewBufferString(yamlconf)

	f := new(File)
	f.Root, err = Parse(buf)
	if err != nil {
		panic(err)
	}

	return f
}

// ConfigFile reads a YAML configuration file from the given filename and
// panics if an error is found.  This is a utility function and is intended for
// use in initializers.
func ConfigFile(filename string) *File {
	f, err := ReadFile(filename)
	if err != nil {
		panic(err)
	}
	return f
}

// Get retrieves a scalar from the file specified by a string of the same
// format as that expected by Child.  If the final node is not a Scalar, Get
// will return an error.
func (f *File) Get(spec string) (string, error) {
	node, err := Child(f.Root, spec)
	if err != nil {
		return "", err
	}

	scalar, ok := node.(Scalar)
	if !ok {
		return "", &NodeTypeMismatch{
			Full:     spec,
			Spec:     spec,
			Token:    "$",
			Expected: "yaml.Scalar",
			Node:     node,
		}
	}
	return scalar.String(), nil
}

// Count retrieves a the number of elements in the specified list from the file
// using the same format as that expected by Child.  If the final node is not a
// List, Count will return an error.
func (f *File) Count(spec string) (int, error) {
	node, err := Child(f.Root, spec)
	if err != nil {
		return -1, err
	}

	lst, ok := node.(List)
	if !ok {
		return -1, &NodeTypeMismatch{
			Full:     spec,
			Spec:     spec,
			Token:    "$",
			Expected: "yaml.List",
			Node:     node,
		}
	}<commit_msg>Fix Get/Count when given spec is missing<commit_after>package yaml

import (
	"bytes"
	"fmt"
	"os"
	"strconv"
	"strings"
)

// A File represents the top-level YAML node found in a file.  It is intended
// for use as a configuration file.
type File struct {
	Root Node

	// TODO(kevlar): Add a cache?
}

// ReadFile reads a YAML configuration file from the given filename.
func ReadFile(filename string) (*File, error) {
	fin, err := os.Open(filename)
	if err != nil {
		return nil, err
	}
	defer fin.Close()

	f := new(File)
	f.Root, err = Parse(fin)
	if err != nil {
		return nil, err
	}

	return f, nil
}

// Config reads a YAML configuration from a static string.  If an error is
// found, it will panic.  This is a utility function and is intended for use in
// initializers.
func Config(yamlconf string) *File {
	var err error
	buf := bytes.NewBufferString(yamlconf)

	f := new(File)
	f.Root, err = Parse(buf)
	if err != nil {
		panic(err)
	}

	return f
}

// ConfigFile reads a YAML configuration file from the given filename and
// panics if an error is found.  This is a utility function and is intended for
// use in initializers.
func ConfigFile(filename string) *File {
	f, err := ReadFile(filename)
	if err != nil {
		panic(err)
	}
	return f
}

// Get retrieves a scalar from the file specified by a string of the same
// format as that expected by Child.  If the final node is not a Scalar, Get
// will return an error.
func (f *File) Get(spec string) (string, error) {
	node, err := Child(f.Root, spec)
	if err != nil {
		return "", err
	}

	if node == nil {
		return "", &NodeNotFound{
			Full: spec,
			Spec: spec,
		}
	}

	scalar, ok := node.(Scalar)
	if !ok {
		return "", &NodeTypeMismatch{
			Full:     spec,
			Spec:     spec,
			Token:    "$",
			Expected: "yaml.Scalar",
			Node:     node,
		}
	}
	return scalar.String(), nil
}

// Count retrieves a the number of elements in the specified list from the file
// using the same format as that expected by Child.  If the final node is not a
// List, Count will return an error.
func (f *File) Count(spec string) (int, error) {
	node, err := Child(f.Root, spec)
	if err != nil {
		return -1, err
	}

	if node == nil {
		return -1, &NodeNotFound{
			Full: spec,
			Spec: spec,
		}
	}

	lst, ok := node.(List)
	if !ok {
		return -1, &NodeTypeMismatch{
			Full:     spec,
			Spec:     spec,
			Token:    "$",
			Expected: "yaml.List",
			Node:     node,
		}
	}
{'fraction_non_alphanumeric': 0.1167632539171496, 'fraction_numerical': 0.0010731916720326251, 'mean_word_length': 2.860811930405965, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6561927', 'n_tokens_mistral': 1675, 'n_tokens_neox': 1579, 'n_words': 637}