parth

package module
v2.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 1, 2019 License: MIT Imports: 3 Imported by: 0

README

parth

go get github.com/codemodus/parth/v2

Package parth provides path parsing for segment unmarshaling and slicing. In other words, parth provides simple and flexible access to (URL) path parameters.

Along with string, all basic non-alias types are supported. An interface is available for implementation by user-defined types. When handling an int, uint, or float of any size, the first valid value within the specified segment will be used.

Usage

Variables
func Segment(path string, i int, v interface{}) error
func Sequent(path, key string, v interface{}) error
func Span(path string, i, j int) (string, error)
func SubSeg(path, key string, i int, v interface{}) error
func SubSpan(path, key string, i, j int) (string, error)
type Parth
    func New(path string) *Parth
    func NewBySpan(path string, i, j int) *Parth
    func NewBySubSpan(path, key string, i, j int) *Parth
    func (p *Parth) Err() error
    func (p *Parth) Segment(i int, v interface{})
    func (p *Parth) Sequent(key string, v interface{})
    func (p *Parth) Span(i, j int) string
    func (p *Parth) SubSeg(key string, i int, v interface{})
    func (p *Parth) SubSpan(key string, i, j int) string
type Unmarshaler
Setup ("By Index")
import (
    "fmt"

    "github.com/codemodus/parth/v2"
)

func handler(w http.ResponseWriter, r *http.Request) {
    var s string
    if err := parth.Segment(r.URL.Path, 4, &s); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }

    fmt.Println(r.URL.Path)
    fmt.Printf("%v (%T)\n", s, s)

    // Output:
    // /some/path/things/42/others/3
    // others (string)
}
Setup ("By Key")
import (
    "fmt"

    "github.com/codemodus/parth/v2"
)

func handler(w http.ResponseWriter, r *http.Request) {
    var i int64
    if err := parth.Sequent(r.URL.Path, "things", &i); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }

    fmt.Println(r.URL.Path)
    fmt.Printf("%v (%T)\n", i, i)

    // Output:
    // /some/path/things/42/others/3
    // 42 (int64)
}
Setup (Parth Type)
import (
    "fmt"

    "github.com/codemodus/parth/v2"
)

func handler(w http.ResponseWriter, r *http.Request) {
    var s string
    var f float32

    p := parth.New(r.URL.Path)
    p.Segment(2, &s)
    p.SubSeg("key", 1, &f)
    if err := p.Err(); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }

    fmt.Println(r.URL.Path)
    fmt.Printf("%v (%T)\n", s, s)
    fmt.Printf("%v (%T)\n", f, f)

    // Output:
    // /zero/one/two/key/four/5.5/six
    // two (string)
    // 5.5 (float32)
}
Setup (Unmarshaler)
import (
    "fmt"

    "github.com/codemodus/parth/v2"
)

func handler(w http.ResponseWriter, r *http.Request) {
    /*
        type mytype []byte

        func (m *mytype) UnmarshalSegment(seg string) error {
            *m = []byte(seg)
        }
    */

    var m mytype
    if err := parth.Segment(r.URL.Path, 4, &m); err != nil {
        fmt.Fprintln(os.Stderr, err)
    }

    fmt.Println(r.URL.Path)
    fmt.Printf("%v == %q (%T)\n", m, m, m)

    // Output:
    // /zero/one/two/key/four/5.5/six
    // [102 111 117 114] == "four" (mypkg.mytype)
}

More Info

Keep Using http.HandlerFunc And Minimize context.Context Usage

The most obvious use case for parth is when working with any URL path such as the one found at http.Request.URL.Path. parth is fast enough that it can be used multiple times in place of a single use of similar router-parameter schemes or even context.Context. There is no need to use an alternate http handler function definition in order to pass data that is already being passed. The http.Request type already holds URL data and parth is great at handling it. Additionally, parth takes care of parsing selected path segments into the types actually needed. Parth not only does more, it's usually faster and less intrusive than the alternatives.

Indexes

If an index is negative, the negative count begins with the last segment. Providing a 0 for the second index is a special case which acts as an alias for the end of the path. An error is returned if: 1. Any index is out of range of the path; 2. When there are two indexes, the first index does not precede the second index.

Keys

If a key is involved, functions will only handle the portion of the path subsequent to the provided key. An error is returned if the key cannot be found in the path.

First Whole, First Decimal (Restated - Important!)

When handling an int, uint, or float of any size, the first valid value within the specified segment will be used.

Documentation

View the GoDoc

Benchmarks

Go 1.11
benchmark                             iter       time/iter   bytes alloc        allocs
---------                             ----       ---------   -----------        ------
BenchmarkSegmentString-8          30000000     39.60 ns/op        0 B/op   0 allocs/op
BenchmarkSegmentInt-8             20000000     65.60 ns/op        0 B/op   0 allocs/op
BenchmarkSegmentIntNegIndex-8     20000000     86.60 ns/op        0 B/op   0 allocs/op
BenchmarkSpan-8                  100000000     18.20 ns/op        0 B/op   0 allocs/op
BenchmarkStdlibSegmentString-8     5000000    454.00 ns/op       50 B/op   2 allocs/op
BenchmarkStdlibSegmentInt-8        3000000    526.00 ns/op       50 B/op   2 allocs/op
BenchmarkStdlibSpan-8              3000000    518.00 ns/op       69 B/op   2 allocs/op
BenchmarkContextLookupSetGet-8     1000000   1984.00 ns/op      480 B/op   6 allocs/op

Documentation

Overview

Package parth provides path parsing for segment unmarshaling and slicing. In other words, parth provides simple and flexible access to (URL) path parameters.

Along with string, all basic non-alias types are supported. An interface is available for implementation by user-defined types. When handling an int, uint, or float of any size, the first valid value within the specified segment will be used.

Example
var s string
if err := parth.Segment(r.URL.Path, 4, &s); err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Printf("%v (%T)\n", s, s)
Output:

/zero/1/2/key/nn4.4nn/5.5
nn4.4nn (string)

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	ErrUnknownType = errors.New("unknown type provided")

	ErrFirstSegNotFound = errors.New("first segment not found by index")
	ErrLastSegNotFound  = errors.New("last segment not found by index")
	ErrSegOrderReversed = errors.New("first segment must precede last segment")
	ErrKeySegNotFound   = errors.New("segment not found by key")

	ErrDataUnparsable = errors.New("data cannot be parsed")
)

Err{Name} values facilitate error identification.

Functions

func Segment

func Segment(path string, i int, v interface{}) error

Segment locates the path segment indicated by the index i and unmarshals it into the provided type v. If the index is negative, the negative count begins with the last segment. An error is returned if: 1. The type is not a pointer to an instance of one of the basic non-alias types and does not implement the Unmarshaler interface; 2. The index is out of range of the path; 3. The located path segment data cannot be parsed as the provided type or if an error is returned when using a provided Unmarshaler implementation.

Example
var s string
if err := parth.Segment(r.URL.Path, 4, &s); err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Printf("%v (%T)\n", s, s)
Output:

/zero/1/2/key/nn4.4nn/5.5
nn4.4nn (string)

func Sequent

func Sequent(path, key string, v interface{}) error

Sequent is similar to Segment, but uses a key to locate a segment and then unmarshal the subsequent segment. It is a simple wrapper over SubSeg with an index of 0.

Example
var f float32
if err := parth.Sequent(r.URL.Path, "key", &f); err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Printf("%v (%T)\n", f, f)
Output:

/zero/1/2/key/nn4.4nn/5.5
4.4 (float32)

func Span

func Span(path string, i, j int) (string, error)

Span returns the path segments between two segment indexes i and j including the first segment. If an index is negative, the negative count begins with the last segment. Providing a 0 for the last index j is a special case which acts as an alias for the end of the path. If the first segment does not begin with a slash and it is part of the requested span, no slash will be added. An error is returned if: 1. Either index is out of range of the path; 2. The first index i does not precede the last index j.

Example
s, err := parth.Span(r.URL.Path, 2, 4)
if err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Println(s)
Output:

/zero/1/2/key/nn4.4nn/5.5
/2/key

func SubSeg

func SubSeg(path, key string, i int, v interface{}) error

SubSeg is similar to Segment, but only handles the portion of the path subsequent to the provided key. For example, to access the segment immediately after a key, an index of 0 should be provided (see Sequent). An error is returned if the key cannot be found in the path.

Example
var f float64
if err := parth.SubSeg(r.URL.Path, "key", 1, &f); err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Printf("%v (%T)\n", f, f)
Output:

/zero/1/2/key/nn4.4nn/5.5
5.5 (float64)

func SubSpan

func SubSpan(path, key string, i, j int) (string, error)

SubSpan is similar to Span, but only handles the portion of the path subsequent to the provided key. An error is returned if the key cannot be found in the path.

Example
s0, err := parth.SubSpan(r.URL.Path, "zero", 2, 4)
if err != nil {
	fmt.Fprintln(os.Stderr, err)
}

s1, err := parth.SubSpan(r.URL.Path, "1", 1, 3)
if err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Println(s0)
fmt.Println(s1)
Output:

/zero/1/2/key/nn4.4nn/5.5
/key/nn4.4nn
/key/nn4.4nn

Types

type Parth

type Parth struct {
	// contains filtered or unexported fields
}

Parth manages path and error data for processing a single path multiple times while error checking only once. Only the first encountered error is stored as all subsequent calls to Parth methods that can error are elided.

Example
var s string
var f float32

p := parth.New(r.URL.Path)
p.Segment(0, &s)
p.SubSeg("key", 1, &f)
if err := p.Err(); err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Printf("%v (%T)\n", s, s)
fmt.Printf("%v (%T)\n", f, f)
Output:

/zero/1/2/key/nn4.4nn/5.5
zero (string)
5.5 (float32)

func New

func New(path string) *Parth

New constructs a pointer to an instance of Parth around the provided path.

func NewBySpan

func NewBySpan(path string, i, j int) *Parth

NewBySpan constructs a pointer to an instance of Parth after preprocessing the provided path with Span.

func NewBySubSpan

func NewBySubSpan(path, key string, i, j int) *Parth

NewBySubSpan constructs a pointer to an instance of Parth after preprocessing the provided path with SubSpan.

func (*Parth) Err

func (p *Parth) Err() error

Err returns the first error encountered by the *Parth receiver.

func (*Parth) Segment

func (p *Parth) Segment(i int, v interface{})

Segment operates the same as the package-level function Segment.

func (*Parth) Sequent

func (p *Parth) Sequent(key string, v interface{})

Sequent operates the same as the package-level function Sequent.

func (*Parth) Span

func (p *Parth) Span(i, j int) string

Span operates the same as the package-level function Span.

func (*Parth) SubSeg

func (p *Parth) SubSeg(key string, i int, v interface{})

SubSeg operates the same as the package-level function SubSeg.

func (*Parth) SubSpan

func (p *Parth) SubSpan(key string, i, j int) string

SubSpan operates the same as the package-level function SubSpan.

type Unmarshaler

type Unmarshaler interface {
	UnmarshalSegment(string) error
}

Unmarshaler is the interface implemented by types that can unmarshal a path segment representation of themselves. It is safe to assume that the segment data will not include slashes.

Example
/*
	type mytype []byte

	func (m *mytype) UnmarshalSegment(seg string) error {
		*m = []byte(seg)
	}
*/}
*/

var m mytype

if err := parth.Segment(r.URL.Path, 4, &m); err != nil {
	fmt.Fprintln(os.Stderr, err)
}

fmt.Println(r.URL.Path)
fmt.Printf("%v == %q (%T)\n", m, m, m)
Output:

/zero/1/2/key/nn4.4nn/5.5
[110 110 52 46 52 110 110] == "nn4.4nn" (parth_test.mytype)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL