strumt

package module
Version: v2.0.0+incompatible Latest Latest
Warning

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

Go to latest
Published: Dec 15, 2017 License: MIT Imports: 5 Imported by: 1

README

Strumt Build Status codebeat badge codecov Go Report Card GoDoc

Strumt is a library to create prompt chain. It provides multiline prompt, input validation, retry on error, ability to customize prompt and error display, a recording of prompt session and the ability to easily test your prompt scenario.

Example

Checkout godoc to have more examples : https://godoc.org/github.com/antham/strumt


asciicast

package main

import (
    "bufio"
    "fmt"
    "os"
    "strconv"

    "github.com/antham/strumt"
)

func main() {
    user := User{}

    p := strumt.NewPromptsFromReaderAndWriter(bufio.NewReader(os.Stdin), os.Stdout)
    p.AddLinePrompter(&StringPrompt{&user.FirstName, "Enter your first name", "userName", "lastName", "userName"})
    p.AddLinePrompter(&StringPrompt{&user.LastName, "Enter your last name", "lastName", "age", "lastName"})
    p.AddLinePrompter(&IntPrompt{&user.Age, "Enter your age", "age", "", "age"})
    p.SetFirst("userName")
    p.Run()

    for _, step := range p.Scenario() {
        fmt.Println(step.PromptString())
        fmt.Println(step.Inputs()[0])

        if step.Error() != nil {
            fmt.Println(step.Error())
        }
    }

    fmt.Println()
    fmt.Printf("User datas : %#v", user)

}

type StringPrompt struct {
    store             *string
    prompt            string
    currentID         string
    nextPrompt        string
    nextPromptOnError string
}

func (s *StringPrompt) ID() string {
	return s.currentID
}

func (s *StringPrompt) PromptString() string {
    return s.prompt
}

func (s *StringPrompt) Parse(value string) error {
    if value == "" {
        return fmt.Errorf("Empty value given")
    }

    *(s.store) = value

    return nil
}

func (s *StringPrompt) NextOnSuccess(value string) string {
    return s.nextPrompt
}

func (s *StringPrompt) NextOnError(err error) string {
    return s.nextPromptOnError
}

type IntPrompt struct {
    store             *int
    prompt            string
    currentID         string
    nextPrompt        string
    nextPromptOnError string
}

func (i *IntPrompt) ID() string {
	return i.currentID
}

func (i *IntPrompt) PromptString() string {
    return i.prompt
}

func (i *IntPrompt) Parse(value string) error {
    age, err := strconv.Atoi(value)

    if err != nil {
        return fmt.Errorf("%s is not a valid number", value)
    }

    if age <= 0 {
        return fmt.Errorf("Give a valid age")
    }

    *(i.store) = age

    return nil
}

func (i *IntPrompt) NextOnSuccess(value string) string {
    return i.nextPrompt
}

func (i *IntPrompt) NextOnError(err error) string {
    return i.nextPromptOnError
}

type User struct {
    FirstName string
    LastName  string
    Age       int
}

Documentation

Overview

Package strumt provides a way to defines scenarios for prompting informations on command line

Example
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"
	"strconv"

	"github.com/antham/strumt"
)

func main() {
	user := User{}

	buf := "\nBrad\n\nBlanton\nwhatever\n0\n31\n"

	p := strumt.NewPromptsFromReaderAndWriter(bytes.NewBufferString(buf), ioutil.Discard)
	p.AddLinePrompter(&StringPrompt{&user.FirstName, "Enter your first name", "userName", "lastName", "userName"})
	p.AddLinePrompter(&StringPrompt{&user.LastName, "Enter your last name", "lastName", "age", "lastName"})
	p.AddLinePrompter(&IntPrompt{&user.Age, "Enter your age", "age", "", "age"})
	p.SetFirst("userName")
	p.Run()

	for _, step := range p.Scenario() {
		fmt.Println(step.PromptString())
		fmt.Println(step.Inputs()[0])

		if step.Error() != nil {
			fmt.Println(step.Error())
		}
	}

	fmt.Println()
	fmt.Printf("User datas : %#v", user)

}

type StringPrompt struct {
	store             *string
	prompt            string
	currentID         string
	nextPrompt        string
	nextPromptOnError string
}

func (s *StringPrompt) ID() string {
	return s.currentID
}

func (s *StringPrompt) PromptString() string {
	return s.prompt
}

func (s *StringPrompt) Parse(value string) error {
	if value == "" {
		return fmt.Errorf("Empty value given")
	}

	*(s.store) = value

	return nil
}

func (s *StringPrompt) NextOnSuccess(value string) string {
	return s.nextPrompt
}

func (s *StringPrompt) NextOnError(err error) string {
	return s.nextPromptOnError
}

type IntPrompt struct {
	store             *int
	prompt            string
	currentID         string
	nextPrompt        string
	nextPromptOnError string
}

func (i *IntPrompt) ID() string {
	return i.currentID
}

func (i *IntPrompt) PromptString() string {
	return i.prompt
}

func (i *IntPrompt) Parse(value string) error {
	age, err := strconv.Atoi(value)

	if err != nil {
		return fmt.Errorf("%s is not a valid number", value)
	}

	if age <= 0 {
		return fmt.Errorf("Give a valid age")
	}

	*(i.store) = age

	return nil
}

func (i *IntPrompt) NextOnSuccess(value string) string {
	return i.nextPrompt
}

func (i *IntPrompt) NextOnError(err error) string {
	return i.nextPromptOnError
}

type User struct {
	FirstName string
	LastName  string
	Age       int
}
Output:

Enter your first name

Empty value given
Enter your first name
Brad
Enter your last name

Empty value given
Enter your last name
Blanton
Enter your age
whatever
whatever is not a valid number
Enter your age
0
Give a valid age
Enter your age
31

User datas : strumt_test.User{FirstName:"Brad", LastName:"Blanton", Age:31}
Example (CustomizePromptOutput)
package main

import (
	"bytes"
	"fmt"
	"io"
	"strings"

	"github.com/antham/strumt"
)

func main() {
	var stdout bytes.Buffer
	buf := "whatever\nyes\n"

	p := strumt.NewPromptsFromReaderAndWriter(bytes.NewBufferString(buf), &stdout)
	p.AddLinePrompter(&AreYouOkPrompt{})
	p.SetFirst("okprompt")
	p.Run()

	for {
		line, err := stdout.ReadString('\n')

		if err == io.EOF {
			break
		}

		fmt.Println(strings.TrimSpace(line))
	}
}

type AreYouOkPrompt struct {
}

func (a *AreYouOkPrompt) ID() string {
	return "okprompt"
}

func (a *AreYouOkPrompt) PromptString() string {
	return "Are you Ok ?"
}

func (a *AreYouOkPrompt) Parse(value string) error {
	if value == "yes" || value == "no" {
		return nil
	}

	return fmt.Errorf("You must answer yes or no")
}

func (a *AreYouOkPrompt) NextOnSuccess(value string) string {
	return ""
}

func (a *AreYouOkPrompt) NextOnError(err error) string {
	return "okprompt"
}

func (a *AreYouOkPrompt) PrintPrompt(w io.Writer, prompt string) {
	fmt.Fprintf(w, "==> %s\n", prompt)
}

func (a *AreYouOkPrompt) PrintError(w io.Writer, err error) {
	fmt.Fprintf(w, "An error occurred : %s", err)
}
Output:

==> Are you Ok ?
An error occurred : You must answer yes or no
==> Are you Ok ?
Example (MultilinePrompt)
package main

import (
	"bytes"
	"fmt"
	"io/ioutil"

	"github.com/antham/strumt"
)

func main() {
	var datas []string
	buf := "test1\ntest2\ntest3\ntest4\n\n"

	p := strumt.NewPromptsFromReaderAndWriter(bytes.NewBufferString(buf), ioutil.Discard)
	p.AddMultilinePrompter(&SlicePrompt{&datas})
	p.SetFirst("sliceprompt")
	p.Run()

	fmt.Println(datas)
}

type SlicePrompt struct {
	datas *[]string
}

func (s *SlicePrompt) ID() string {
	return "sliceprompt"
}

func (s *SlicePrompt) PromptString() string {
	return "Give several input"
}

func (s *SlicePrompt) Parse(values []string) error {
	*(s.datas) = values

	return nil
}

func (s *SlicePrompt) NextOnSuccess(values []string) string {
	return ""
}

func (s *SlicePrompt) NextOnError(err error) string {
	return "sliceprompt"
}
Output:

[test1 test2 test3 test4]

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type ErrorRenderer

type ErrorRenderer interface {
	PrintError(io.Writer, error)
}

ErrorRenderer can be implemented to customize the way an error returned by Parse is rendered

type LinePrompter

type LinePrompter interface {
	Prompter
	NextOnSuccess(string) string
	Parse(string) error
}

LinePrompter defines a one line prompter that will ask only for one user input.

NextOnSuccess must returns the id of the next prompt to be called. To mark prompter as the last prompter NextOnSucces must returns an empty string

type MultilinePrompter

type MultilinePrompter interface {
	Prompter
	NextOnSuccess([]string) string
	Parse([]string) error
}

MultilinePrompter defines a mutiline prompter that will let the possibility to the user to provide several input, result is provided as an input slice.

NextOnSuccess must returns the id of the next prompt to be called. To mark prompter as the last prompter NextOnSucces must returns an empty string

type PromptRenderer

type PromptRenderer interface {
	PrintPrompt(io.Writer, string)
}

PromptRenderer can be implemented to customize the way prompt is rendered, PromptString result is given as parameter

type Prompter

type Prompter interface {
	ID() string
	PromptString() string
	NextOnError(error) string
}

Prompter defines a generic common prompt.

ID returns a string id to identify prompter and to let other prompter call it.

PromptString returns a string to be diplayed as prompt.

NextOnError is triggered when an error occurred during prompt sequence, it must returns the id of the prompt to be called when an error occured, most of the time it would be the id of the current prompt to loop on it

type Prompts

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

Prompts stores all defined prompts and current running prompt

func NewPrompts

func NewPrompts() Prompts

NewPrompts creates a new prompt from stdin

func NewPromptsFromReaderAndWriter

func NewPromptsFromReaderAndWriter(reader io.Reader, writer io.Writer) Prompts

NewPromptsFromReaderAndWriter creates a new prompt from a given reader and writer, useful for testing purpose

func (*Prompts) AddLinePrompter

func (p *Prompts) AddLinePrompter(prompt LinePrompter)

AddLinePrompter add a new LinePrompter mapped to a given id

func (*Prompts) AddMultilinePrompter

func (p *Prompts) AddMultilinePrompter(prompt MultilinePrompter)

AddMultilinePrompter add a new MultilinePrompter mapped to a given id

func (*Prompts) Run

func (p *Prompts) Run()

Run executes a prompt sequence

func (*Prompts) Scenario

func (p *Prompts) Scenario() []Step

Scenario retrieves all steps done during a prompt sequence

func (*Prompts) SetFirst

func (p *Prompts) SetFirst(id string)

SetFirst defines from which prompt the prompt sequence has to start

type SeparatorRenderer

type SeparatorRenderer interface {
	PrintSeparator(io.Writer)
}

SeparatorRenderer can be implemented to customize the way a prompt is separated from another, default is to add a new line

type Step

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

Step represents a scenario step which is the result of a prompt execution. We store the prompt string, inputs that the user has given, and the prompt error if one occurred

func (Step) Error

func (s Step) Error() error

Error returns the error, if any, triggered on a prompt error

func (Step) Inputs

func (s Step) Inputs() []string

Inputs retrieves all inputs given by user,

func (Step) PromptString

func (s Step) PromptString() string

PromptString returns prompt string displayed by the prompt string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
t or T : Toggle theme light dark auto
y or Y : Canonical URL