https://github.com/oxequa/interact
Question/answer and multiple choice by command line
https://github.com/oxequa/interact
go golang golang-package golang-tools questions-and-answers tockins
Last synced: 2 months ago
JSON representation
Question/answer and multiple choice by command line
- Host: GitHub
- URL: https://github.com/oxequa/interact
- Owner: oxequa
- License: gpl-3.0
- Created: 2017-01-04T18:21:27.000Z (over 8 years ago)
- Default Branch: master
- Last Pushed: 2017-12-16T12:59:38.000Z (over 7 years ago)
- Last Synced: 2024-06-19T17:52:11.321Z (11 months ago)
- Topics: go, golang, golang-package, golang-tools, questions-and-answers, tockins
- Language: Go
- Homepage:
- Size: 53.7 KB
- Stars: 43
- Watchers: 4
- Forks: 11
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
### Interact
An easy and fast Go library, without external imports, to handle questions and answers by command line
##### Features
- [Single question](#single-question)
- [Questions list](#questions-list)
- [Multiple choice](#multiple-choice)
- [Sub questions](#sub-questions)
- [Question prefix](#question-prefix)
- [Default values](#default-values)
- [Custom errors](#custom-errors)
- [After/Before listeners](#after-before)
- [Skip a Question](#skip-a-question)
- [Reload a Question](#reload-a-question)
- [End signal](#end-signal)
- [Colors support (fatih/color)](#color-support)##### Installation
To install interact:
```
$ go get github.com/tockins/interact
```##### Single question
Run a simple question and manage the response.
The response field is used to get the answer as a specific type.
``` go
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Questions: []*i.Question{
{
Quest: i.Quest{
Msg: "Would you like some coffee?",
},
Action: func(c i.Context) interface{} {
val, err := c.Ans().Bool()
if err != nil{
return err
}
fmt.Println(val)
return nil
},
},
},
})
}
```##### Questions list
Define a list of questions to be run in sequence.
The Action func can be used for validate the answer and can return a custom error.Question struct is only for single question whereas **Interact struct** supports multiple questions
``` go
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Questions: []*i.Question{
{
Quest: i.Quest{
Msg: "Would you like some coffee?",
},
Action: func(c i.Context) interface{} {
val, err := c.Ans().Bool()
if err != nil{
return err
}
fmt.Println(val)
return nil
},
},
{
Quest: i.Quest{
Msg: "What's 2+2?",
},
Action: func(c i.Context) interface{} {
val, _ := c.Ans().Int()
// get the answer as integer
if val < 4 {
// return a custom error and rerun the question
return "INCREASE"
}else if val > 4 {
return "DECREASE"
}
return nil
},
},
},
})
}
```##### Multiple choice
Define a multiple choice question
``` go
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Questions: []*i.Question{
{
Quest: i.Quest{
Msg: "how much for a teacup?",
Choices: i.Choices{
Alternatives: []i.Choice{
{
Text: "Gyokuro teapcup",
Response: "20",
},
{
Text: "Sencha teacup",
Response: -10,
},
{
Text: "Matcha teacup",
Response: 15.50,
},
},
},
},
Action: func(c i.Context) interface{} {
val, _ := c.Ans().Int()
fmt.Println(val)
return nil
},
},
},
})
}
```##### Sub questions
The sub questions list is managed by the **"Resolve"** func.
Each sub question can access to the parent answer by the **"Parent"** method``` go
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Questions: []*i.Question{
{
Quest: i.Quest{
Msg: "Would you like some coffee?",
Resolve: func(c i.Context) bool {
val, _ := c.Ans().Bool()
return val
},
},
Subs: []*i.Question{
{
Quest: i.Quest{
Msg: "What Kind of Coffee?",
Choices: i.Choices{
Alternatives: []i.Choice{
{
Text: "Black coffee",
Response: "black",
},
{
Text: "With milk",
Response: "milk",
},
},
},
},
Action: func(c i.Context) interface{} {
// question (sub) answer
val, _ := c.Ans().String()
fmt.Println(val)
// parent answer
val, _ = c.Parent().Ans().String()
fmt.Println(val)
return nil
},
},
},
Action: func(c i.Context) interface{} {
// question answer
val, _ := c.Ans().String()
fmt.Println(val)
// sub question answer
fmt.Println(c.Qns().Get(0).Ans().Raw())
return nil
},
},
},
})
}
```##### Question prefix
Interact support a custom prefix for each question
You can define a **global prefix** for all questions but you can **overwrite it** in each question with ease
As the first param you can pass a custom **io.writer** instance
``` go
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Before: func(c i.Context) error{
c.SetPrfx(nil,"GLOBAL PREFIX")
return nil
},
Questions: []*i.Question{
{
Before: func(c i.Context) error{
c.SetPrfx(nil,"OVERWRITTEN PREFIX")
// print current prefix
fmt.Println(c.Prfx())
return nil
},
Quest: i.Quest{
Msg: "Would you like some coffee?",
},
Action: func(c i.Context) interface{} {
return nil
},
},
{
Before: func(c i.Context) error{
fmt.Println(c.Prfx())
return nil
},
Quest: i.Quest{
Msg: "What's 2+2?",
},
Action: func(c i.Context) interface{} {
return nil
},
},
},
})
}
```##### Default values
You can define a default value for each question and get it in the action func as an answer
``` go
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Questions: []*i.Question{
{
Before: func(c i.Context) error{
c.SetDef("test",default val")
return nil
},
Quest: i.Quest{
Msg: "Would you like some coffee?",
},
Action: func(c i.Context) interface{} {
val, _ := c.Ans().String()
fmt.Println(val)
return nil
},
},
{
Before: func(c i.Context) error{
c.SetDef("default","default val")
return nil
},
Quest: i.Quest{
Msg: "Would you like some coffee?",
},
Action: func(c i.Context) interface{} {
val, _ := c.Ans().Bool()
fmt.Println(val)
return nil
},
},
},
})
}
```##### Custom errors
You can define a default error for every question or you can set a default error message
``` go
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Before: func(c i.Context) error{
c.SetErr("Default error")
return nil
},
Questions: []*i.Question{
{
Quest: i.Quest{
Msg: "Would you like some coffee?",
Err: "Custom error fot this question",
},
Action: func(c i.Context) interface{} {
val, err := c.Ans().Bool()
if err {
return "Invalid answer"
}
return nil
},
},
{
Quest: i.Quest{
Msg: "Would you like some coffee?",
},
Action: func(c i.Context) interface{} {
val, err := c.Ans().Bool()
if err {
return c.Err()
}
return nil
},
},
},
})
}
```##### After Before
For every question and for each list of questions you can define custom commands to be run before or after the relative instance
``` go
package mainimport (
i "github.com/tockins/interact"
)function main(){
i.Run(&i.Interact{
Before: func(c i.Context) error{
c.SetPrfx(nil, "TEST")
return nil
},
Questions: []*i.Question{
{
Before: func(c i.Context) error{
c.SetPrfx(nil, "TEST A")
return nil
},
Quest: i.Quest{
Msg: "How much coffee?",
},
Action: func(c i.Context) interface{} {
return nil
},
After: func(c i.Context) error{
val, _ := c.Ans().Int()
fmt.Println(val)
return nil
},
},
{
Quest: i.Quest{
Msg: "How much coffee?",
},
Action: func(c i.Context) interface{} {
return nil
},
},
},
After: func(c i.Context) error{
for _, v := range c.Qns().List(){
fmt.Println(v.Quest(),v.Ans().Raw())
}
return nil
},
})
}
```##### Skip a Question
With the skip func you can stop the execution of the current question or you can skip the next.
``` go
package mainimport (
i "github.com/tockins/interact"
)function main(){
i.Run(&i.Interact{
Before: func(c i.Context) error{
// skip all questions
//c.Skip()
return nil
},
Questions: []*i.Question{
{
Before: func(c i.Context) error{
// skip the current question
//c.Skip()
return nil
},
Quest: i.Quest{
Msg: "How much coffee?",
},
Action: func(c i.Context) interface{} {
return nil
},
After: func(c i.Context) error{
// skip the next question
c.Skip()
return nil
},
},
{
Before: func(c i.Context) error{
return nil
},
Quest: i.Quest{
Msg: "How much tea?",
},
Action: func(c i.Context) interface{} {
return nil
},
After: func(c i.Context) error{
return nil
},
},
},
})
}
```##### Reload a Question
You can reload a question how many times as you want
``` go
package mainimport (
i "github.com/tockins/interact"
)function main(){
i.Run(&i.Interact{
Questions: []*i.Question{
{
Quest: i.Quest{
Msg: "Would you like Interact?",
},
Action: func(c i.Context) interface{}{
val, err := c.Ans().Bool()
if (err != nil || !val){
c.Reload()
}
return nil
},
},
},
})
}
```##### End signal
End a group of questions or sub-questions with a specific character or string
```
package mainimport (
i "github.com/tockins/interact"
)func main() {
i.Run(&i.Interact{
Before: func(c i.Context) error {
c.SetEnd("!*")
return nil
},
Questions: []*i.Question{
{
Before: func(c i.Context) error {
c.SetEnd("*")
return nil
},
Quest: i.Quest{
Msg: "Would you like some coffee? (insert '*' to stop this question or the sub questions)",
Resolve: func(c i.Context) bool {
val, _ := c.Ans().Bool()
return val
},
},
Subs: []*i.Question{
{
Before: func(c i.Context) error {
c.SetEnd("!")
return nil
},
Quest: i.Quest{
Msg: "What kind of Coffee? (insert '!' to stop)",
},
Action: func(c i.Context) interface{} {
c.Reload()
return nil
},
},
{
Quest: i.Quest{
Msg: "What type of Coffee?",
},
},
},
},
{
Quest: i.Quest{
Msg: "Would you like some tea?",
},
Action: func(c i.Context) interface{} {
c.Reload()
return nil
},
},
},
})
}
```##### Colors support
Interact supports the color scheme defined by the package "fatih/color"
``` go
package mainimport (
"github.com/fatih/color"
i "github.com/tockins/interact"
"fmt"
)func main() {
b := color.New(color.FgHiWhite).Add(color.BgRed).SprintfFunc()
y := color.New(color.FgYellow).SprintFunc()
r := color.New(color.FgRed).SprintFunc()
g := color.New(color.FgGreen).SprintFunc()
prefix := y("[") + "INTERACT" + y("]")i.Run(&i.Interact{
Before: func(c i.Context) error{
c.SetPrfx(color.Output, prefix)
return nil
},
Questions: []*i.Question{
{
Before: func(c i.Context) error{
c.SetPrfx(nil,y("[") + "INTERACT QUEST" + y("]"))
return nil
},
Quest: i.Quest{
Msg: "Would you like some coffee?",
Options: g("[yes/no]"),
Err: b("INVALID"),
Resolve: func(c i.Context) bool{
val, _ := c.Ans().Bool()
return val
},
},
Subs: []*i.Question{
{
Quest: i.Quest{
Msg: "What Kind of Coffee?",
Err: b("INVALID"),
Choices: i.Choices{
Color: g,
Alternatives: []i.Choice{
{
Text: "Black coffee",
Response: "black",
},
{
Text: "With milk",
Response: "milk",
},
},
},
},
Action: func(c i.Context) interface{}{
val, _ := c.Ans().String()
fmt.Println(val)
val, _ := c.Parent().Ans().String()
fmt.Println(val)
return nil
},
},
},
Action: func(c i.Context) interface{} {
val, _ := c.Ans().Bool()
if !val{
return r("INVALID INPUT")
}
fmt.Println(c.Quest(), val)
return nil
},
},
},
})
}
```