defining paths
parent
d01c8c5a44
commit
8cff8b3cd3
@ -0,0 +1,73 @@
|
||||
package blammo
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"strings"
|
||||
"unicode"
|
||||
)
|
||||
|
||||
// Path provides the basis of a hierarchical pathing system. Each path is a
|
||||
// singly linked list of strings. This is most often used to form the prefix
|
||||
// for a log line in a log file.
|
||||
//
|
||||
// Path is immutable by design. This allows us to make assumptions about a
|
||||
// given path. We know, for example, that because at each step the name cannot
|
||||
// be changed, the name of a given path's parent is never changed.
|
||||
type Path struct {
|
||||
name string
|
||||
parent *Path
|
||||
}
|
||||
|
||||
// Name gives the tail member of a path. This is analagous to the notion of a
|
||||
// file path's basename, or the last element of a linked list.
|
||||
func (p *Path) Name() string { return p.name }
|
||||
|
||||
// Parent gives the parent path of this path. The expected use-case for
|
||||
// retrieving a path's parent is to facilitate the construction of custom
|
||||
// blammo.Writer implementations.
|
||||
func (p *Path) Parent() *Path { return p.parent }
|
||||
|
||||
// String represents a canonical stringification of a path, represented as a
|
||||
// slash-delimited absolute path similar to a filesystem path.
|
||||
func (p *Path) String() string {
|
||||
if p.parent == nil {
|
||||
return p.name
|
||||
}
|
||||
return strings.TrimLeft(fmt.Sprintf("%s/%s", p.parent.String(), p.name), "/")
|
||||
}
|
||||
|
||||
// Child creates a child path having parent p. This is the recommended way of
|
||||
// constructing a hierarchical path.
|
||||
func (p *Path) Child(name string) *Path {
|
||||
return &Path{
|
||||
name: name,
|
||||
parent: p,
|
||||
}
|
||||
}
|
||||
|
||||
// NewPath creates a new path with a given root name. The supplied name string
|
||||
// is cleaned of unsafe characters.
|
||||
func NewPath(name string) *Path {
|
||||
return &Path{name: name}
|
||||
}
|
||||
|
||||
// IsSafeName determines whether a provided path name is considered to be a
|
||||
// "safe" name by the standards of blammo. A safe name in the context of blammo
|
||||
// is a name that consists of only unicode letters and numbers, plus the hyphen
|
||||
// and underscore characters. Note that the character classes being tested
|
||||
// against are unicode letters and numbers, not ascii letters and numbers;
|
||||
// letters with accents and letters that do not appear in English are
|
||||
// permitted. The purpose of the safe name guarantees is to ensure that logs
|
||||
// written by blammo are written with the expectation of being parseable.
|
||||
func IsSafeName(name string) bool {
|
||||
runes := []rune(name)
|
||||
for _, r := range runes {
|
||||
if r == '-' || r == '_' {
|
||||
continue
|
||||
}
|
||||
if !unicode.In(r, unicode.Letter, unicode.Number) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
package blammo
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestPath(t *testing.T) {
|
||||
p := NewPath("alice")
|
||||
if p.String() != "alice" {
|
||||
t.Error("bad root path generation")
|
||||
}
|
||||
|
||||
p = p.Child("bob")
|
||||
if p.String() != "alice/bob" {
|
||||
t.Error("bad child path generation")
|
||||
}
|
||||
|
||||
p = p.Child("carol")
|
||||
if p.String() != "alice/bob/carol" {
|
||||
t.Error("bad grandchild generation")
|
||||
}
|
||||
}
|
||||
|
||||
func TestSafeNames(t *testing.T) {
|
||||
safeNames := []string{
|
||||
"one",
|
||||
"1",
|
||||
"1one",
|
||||
"niño",
|
||||
"garçon",
|
||||
"你好",
|
||||
"",
|
||||
}
|
||||
|
||||
for _, n := range safeNames {
|
||||
if !IsSafeName(n) {
|
||||
t.Errorf("expected safe name is considered unsafe: %s", n)
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue