Skip to content
This repository has been archived by the owner on Apr 19, 2024. It is now read-only.

Commit

Permalink
Merge pull request #34 from AlecAivazis/feat/v1
Browse files Browse the repository at this point in the history
Added support for non-string prompts
  • Loading branch information
AlecAivazis authored Apr 18, 2017
2 parents f0bb030 + 46e65ef commit e9561ce
Show file tree
Hide file tree
Showing 32 changed files with 925 additions and 399 deletions.
10 changes: 10 additions & 0 deletions .tasks.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
tests:
summary: Run the test suite
command: go test {{.files}}

install-deps:
summary: Install all of package dependencies
command: go get -t {{.files}}

variables:
files: '$(go list -v ./... | grep -Ev "github.com/AlecAivazis/survey/(tests|examples)")'
7 changes: 5 additions & 2 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
language: go

before_install:
- go get github.com/AlecAivazis/run

install:
- go get -t . ./terminal/...
- run install-deps

script:
- go test -v . ./terminal/...
- run tests
137 changes: 130 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Survey
[![Build Status](https://travis-ci.org/AlecAivazis/survey.svg?branch=feature%2Fpretty)](https://travis-ci.org/AlecAivazis/survey)
[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg)](https://godoc.org/github.com/alecaivazis/survey)
[![GoDoc](http://img.shields.io/badge/godoc-reference-5272B4.svg)](https://godoc.org/github.com/AlecAivazis/survey)


A library for building interactive prompts. Heavily inspired by the great [inquirer.js](https://github.com/SBoudrias/Inquirer.js/).
Expand All @@ -14,7 +14,7 @@ package main

import (
"fmt"
"gopkg.in/alecaivazis/survey.v0"
"gopkg.in/AlecAivazis/survey.v1"
)

// the questions to ask
Expand All @@ -26,23 +26,146 @@ var qs = []*survey.Question{
},
{
Name: "color",
Prompt: &survey.Choice{
Prompt: &survey.Select{
Message: "Choose a color:",
Choices: []string{"red", "blue", "green"},
Options: []string{"red", "blue", "green"},
Default: "red",
},
},
}

func main() {
answers, err := survey.Ask(qs)
// the answers will be written to this struct
answers := struct {
Name string // survey will match the question and field names
FavoriteColor string `survey:"color"` // or you can tag fields to match a specific name
}{}

// perform the questions
err := survey.Ask(qs, &answers)
if err != nil {
fmt.Println("\n", err.Error())
fmt.Println(err.Error())
return
}

fmt.Printf("%s chose %s.", answers["name"], answers["color"])
fmt.Printf("%s chose %s.", answers.Name, answers.FavoriteColor)
}
```

## Examples
Examples can be found in the `examples/` directory. Run them
to see basic behavior:
```bash
go get github.com/AlecAivazis/survey

# ... navigate to the repo in your GOPATH

go run examples/simple.go
go run examples/validation.go
```

## Prompts

### Input
<img src="https://media.giphy.com/media/3og0IxS8JsuD9Z8syA/giphy.gif" width="400px"/>

```golang
name := ""
prompt := &survey.Input{
Message: "ping",
}
survey.AskOne(prompt, &name, nil)
```


### Password
<img src="https://media.giphy.com/media/26FmQr6mUivkq71GE/giphy.gif" width="400px" />

```golang
password := ""
prompt := &survey.Password{
Message: "Please type your password",
}
survey.AskOne(prompt, &password, nil)
```


### Confirm
<img src="https://media.giphy.com/media/3oKIPgsUmTp4m3eo4E/giphy.gif" width="400px"/>

```golang
name := false
prompt := &survey.Confirm{
Message: "Do you like pie?",
}
survey.AskOne(prompt, &name, nil)
```


### Select
<img src="https://media.giphy.com/media/3oKIPxigmMu5YqpUPK/giphy.gif" width="400px"/>

```golang
color := ""
prompt := &survey.Select{
Message: "Choose a color:",
Options: []string{"red", "blue", "green"},
}
survey.AskOne(prompt, &color, nil)
```


### MultiSelect
<img src="https://media.giphy.com/media/3oKIP8lHYFtGeQDH0c/giphy.gif" width="400px"/>

```golang
days := []string{}
prompt := &survey.MultiSelect{
Message: "What days do you prefer:",
Options: []string{"Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday"},
}
survey.AskOne(prompt, &days, nil)
```

## Validation

Validating individual responses for a particular question can be done by defining a
`Validate` field on the `survey.Question` to be validated. This function takes an
`interface{}` type and returns an error to show to the user, prompting them for another
response:

```golang
q := &survey.Question{
Prompt: &survey.Input{Message: "Hello world validation"},
Validate: func (val interface{}) error {
// since we are validating an Input, this will always succeed
if str, ok := val.(string) ; ok {
if len(str) > 10 {
return errors.New("This response cannot be longer than 10 characters.")
}
}
}
}
```

### Built-in Validators
`survey` comes prepackaged with a few validators to fit common situations. Currently these
validators include:

| name | valid types | description |
|--------------|-----------------|---------------------------------------------------------------|
| Required | any | Rejects zero values of the response type |
| MinLength(n) | string | Enforces that a response is at least the given length |
| MaxLength(n) | string | Enforces that a response is no longer than the given length |

## Versioning

This project tries to maintain semantic GitHub releases as closely as possible. As such, services
like [gopkg.in](http://labix.org/gopkg.in) work very well to ensure non-breaking changes whenever
you build your application. For example, importing v1 of survey would look something like

```golang
package main

import "gopkg.in/AlecAivazis/survey.v1"
```
39 changes: 19 additions & 20 deletions confirm.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,15 @@ import (
"fmt"
"regexp"

"github.com/alecaivazis/survey/terminal"
"github.com/AlecAivazis/survey/core"
"github.com/AlecAivazis/survey/terminal"
"github.com/chzyer/readline"
)

// Confirm is a regular text input that accept yes/no answers.
type Confirm struct {
Message string
Default bool
Answer *bool
}

// data available to the templates when processing
Expand Down Expand Up @@ -64,7 +64,7 @@ func (c *Confirm) getBool(rl *readline.Instance) (bool, error) {
answer = c.Default
default:
// we didnt get a valid answer, so print error and prompt again
out, err := RunTemplate(
out, err := core.RunTemplate(
ErrorTemplate, fmt.Errorf("%q is not a valid answer, please try again.", val),
)
// if something went wrong
Expand All @@ -88,16 +88,9 @@ func (c *Confirm) getBool(rl *readline.Instance) (bool, error) {

// Prompt prompts the user with a simple text field and expects a reply followed
// by a carriage return.
func (c *Confirm) Prompt(rl *readline.Instance) (string, error) {
// if we weren't passed an answer
if c.Answer == nil {
// build one
answer := false
c.Answer = &answer
}

func (c *Confirm) Prompt(rl *readline.Instance) (interface{}, error) {
// render the question template
out, err := RunTemplate(
out, err := core.RunTemplate(
ConfirmQuestionTemplate,
ConfirmTemplateData{Confirm: *c},
)
Expand All @@ -116,24 +109,30 @@ func (c *Confirm) Prompt(rl *readline.Instance) (string, error) {
return "", err
}

// return the value
*c.Answer = answer

// convert the boolean into the appropriate string
return yesNo(answer), nil
return answer, nil
}

// Cleanup overwrite the line with the finalized formatted version
func (c *Confirm) Cleanup(rl *readline.Instance, val string) error {
func (c *Confirm) Cleanup(rl *readline.Instance, val interface{}) error {
// go up one line
terminal.CursorPreviousLine(1)
// clear the line
terminal.EraseInLine(1)
terminal.EraseInLine(0)

// the string version of the answer
ans := ""
// if the value was previously true
if val.(bool) {
ans = "yes"
} else {
ans = "no"
}

// render the template
out, err := RunTemplate(
out, err := core.RunTemplate(
ConfirmQuestionTemplate,
ConfirmTemplateData{Confirm: *c, Answer: val},
ConfirmTemplateData{Confirm: *c, Answer: ans},
)
if err != nil {
return err
Expand Down
10 changes: 6 additions & 4 deletions confirm_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@ package survey

import (
"testing"

"github.com/AlecAivazis/survey/core"
)

func init() {
// disable color output for all prompts to simplify testing
DisableColor = true
core.DisableColor = true
}

func TestConfirmFormatQuestion(t *testing.T) {
Expand All @@ -16,7 +18,7 @@ func TestConfirmFormatQuestion(t *testing.T) {
Default: true,
}

actual, err := RunTemplate(
actual, err := core.RunTemplate(
ConfirmQuestionTemplate,
ConfirmTemplateData{Confirm: *prompt},
)
Expand All @@ -38,7 +40,7 @@ func TestConfirmFormatQuestionDefaultFalse(t *testing.T) {
Default: false,
}

actual, err := RunTemplate(
actual, err := core.RunTemplate(
ConfirmQuestionTemplate,
ConfirmTemplateData{Confirm: *prompt},
)
Expand All @@ -60,7 +62,7 @@ func TestConfirmFormatAnswer(t *testing.T) {
Message: "Is pizza your favorite food?",
}

actual, err := RunTemplate(
actual, err := core.RunTemplate(
ConfirmQuestionTemplate,
ConfirmTemplateData{Confirm: *prompt, Answer: "Yes"},
)
Expand Down
2 changes: 1 addition & 1 deletion template.go → core/template.go
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
package survey
package core

import (
"bytes"
Expand Down
Loading

0 comments on commit e9561ce

Please sign in to comment.