Remove entire subscription model

It was a valiant effort, and the implementation was solid and
dependable, but at the end of the day we can achieve the same
functionality in a much simpler fashion with commands, especially
because Go is not held to the same restrictions as Elm.
This commit is contained in:
Christian Rocha
2020-05-12 17:56:30 -04:00
parent 82ddbb8e12
commit ade8203c21
13 changed files with 136 additions and 322 deletions

View File

@@ -14,21 +14,17 @@ type model int
type tickMsg time.Time
func newTickMsg(t time.Time) boba.Msg {
return tickMsg(t)
}
func main() {
boba.AltScreen()
defer boba.ExitAltScreen()
err := boba.NewProgram(initialize, update, view, subscriptions).Start()
err := boba.NewProgram(initialize, update, view).Start()
if err != nil {
log.Fatal(err)
}
}
func initialize() (boba.Model, boba.Cmd) {
return model(5), nil
return model(5), tick()
}
func update(message boba.Msg, mdl boba.Model) (boba.Model, boba.Cmd) {
@@ -51,19 +47,20 @@ func update(message boba.Msg, mdl boba.Model) (boba.Model, boba.Cmd) {
if m <= 0 {
return m, boba.Quit
}
return m, tick()
}
return m, nil
}
func subscriptions(_ boba.Model) boba.Subs {
return boba.Subs{
"tick": boba.Every(time.Second, newTickMsg),
}
}
func view(mdl boba.Model) string {
m, _ := mdl.(model)
return fmt.Sprintf("\n\n Hi. This program will exit in %d seconds...", m)
}
func tick() boba.Cmd {
return boba.Tick(time.Second, func(t time.Time) boba.Msg {
return tickMsg(t)
})
}

View File

@@ -23,7 +23,7 @@ type statusMsg int
type errMsg error
func main() {
p := boba.NewProgram(initialize, update, view, nil)
p := boba.NewProgram(initialize, update, view)
if err := p.Start(); err != nil {
log.Fatal(err)
}

View File

@@ -22,7 +22,6 @@ func main() {
initialize,
update,
view,
subscriptions,
)
if err := p.Start(); err != nil {
@@ -38,7 +37,7 @@ func initialize() (boba.Model, boba.Cmd) {
return Model{
textInput: inputModel,
err: nil,
}, nil
}, input.Blink(inputModel)
}
func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
@@ -74,20 +73,6 @@ func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
return m, cmd
}
func subscriptions(model boba.Model) boba.Subs {
m, ok := model.(Model)
if !ok {
return nil
}
sub, err := input.MakeSub(m.textInput)
if err != nil {
return nil
}
return boba.Subs{
"input": sub,
}
}
func view(model boba.Model) string {
m, ok := model.(Model)
if !ok {

View File

@@ -18,7 +18,11 @@ func main() {
boba.AltScreen()
defer boba.ExitAltScreen()
if err := pager.NewProgram(string(content)).Start(); err != nil {
if err := boba.NewProgram(
pager.Init(string(content)),
pager.Update,
pager.View,
).Start(); err != nil {
fmt.Println("could not run program:", err)
os.Exit(1)
}

View File

@@ -13,7 +13,7 @@ import (
// A model can be more or less any type of data. It holds all the data for a
// program, so often it's a struct. For this simple example, however, all
// we'll need is a simple integer.
type Model int
type model int
// Messages are events that we respond to in our Update function. This
// particular one indicates that the timer has ticked.
@@ -21,22 +21,22 @@ type tickMsg time.Time
func main() {
// Initialize our program
p := boba.NewProgram(initialize, update, view, subscriptions)
p := boba.NewProgram(initialize, update, view)
if err := p.Start(); err != nil {
log.Fatal(err)
}
}
func initialize() (boba.Model, boba.Cmd) {
return Model(5), nil
return model(5), tick
}
// Update is called when messages are recived. The idea is that you inspect
// the message and update the model (or send back a new one) accordingly. You
// can also return a commmand, which is a function that peforms I/O and
// returns a message.
func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
m, _ := model.(Model)
func update(msg boba.Msg, mdl boba.Model) (boba.Model, boba.Cmd) {
m, _ := mdl.(model)
switch msg.(type) {
case boba.KeyMsg:
@@ -46,23 +46,19 @@ func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
if m <= 0 {
return m, boba.Quit
}
return m, tick
}
return m, nil
}
// Views take data from the model and return a string which will be rendered
// to the terminal.
func view(model boba.Model) string {
m, _ := model.(Model)
func view(mdl boba.Model) string {
m, _ := mdl.(model)
return fmt.Sprintf("Hi. This program will exit in %d seconds. To quit sooner press any key.\n", m)
}
// This is a subscription which we setup in NewProgram(). It waits for one
// second, sends a tick, and then restarts.
func subscriptions(_ boba.Model) boba.Subs {
return boba.Subs{
"tick": boba.Every(time.Second, func(t time.Time) boba.Msg {
return tickMsg(t)
}),
}
func tick() boba.Msg {
time.Sleep(time.Second)
return tickMsg{}
}

View File

@@ -22,7 +22,7 @@ type Model struct {
type errMsg error
func main() {
p := boba.NewProgram(initialize, update, view, subscriptions)
p := boba.NewProgram(initialize, update, view)
if err := p.Start(); err != nil {
fmt.Println(err)
os.Exit(1)
@@ -30,12 +30,12 @@ func main() {
}
func initialize() (boba.Model, boba.Cmd) {
m := spinner.NewModel()
m.Type = spinner.Dot
s := spinner.NewModel()
s.Type = spinner.Dot
return Model{
spinner: m,
}, nil
spinner: s,
}, spinner.Tick(s)
}
func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
@@ -64,8 +64,9 @@ func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
return m, nil
default:
m.spinner, _ = spinner.Update(msg, m.spinner)
return m, nil
var cmd boba.Cmd
m.spinner, cmd = spinner.Update(msg, m.spinner)
return m, cmd
}
}
@@ -88,18 +89,3 @@ func view(model boba.Model) string {
}
return str
}
func subscriptions(model boba.Model) boba.Subs {
m, ok := model.(Model)
if !ok {
return nil
}
sub, err := spinner.MakeSub(m.spinner)
if err != nil {
return nil
}
return boba.Subs{
"tick": sub,
}
}

View File

@@ -23,7 +23,6 @@ func main() {
initialize,
update,
view,
subscriptions,
).Start(); err != nil {
fmt.Printf("could not start program: %s\n", err)
os.Exit(1)
@@ -53,7 +52,13 @@ func initialize() (boba.Model, boba.Cmd) {
email.Placeholder = "Email"
email.Prompt = blurredPrompt
return Model{0, name, nickName, email, blurredSubmitButton}, nil
return Model{0, name, nickName, email, blurredSubmitButton},
boba.Batch(
input.Blink(name),
input.Blink(nickName),
input.Blink(email),
)
}
func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
@@ -62,6 +67,8 @@ func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
panic("could not perform assertion on model")
}
var cmd boba.Cmd
switch msg := msg.(type) {
case boba.KeyMsg:
@@ -135,44 +142,29 @@ func update(msg boba.Msg, model boba.Model) (boba.Model, boba.Cmd) {
default:
// Handle character input
m = updateInputs(msg, m)
return m, nil
m, cmd = updateInputs(msg, m)
return m, cmd
}
default:
// Handle blinks
m = updateInputs(msg, m)
return m, nil
m, cmd = updateInputs(msg, m)
return m, cmd
}
}
func updateInputs(msg boba.Msg, m Model) Model {
m.nameInput, _ = input.Update(msg, m.nameInput)
m.nickNameInput, _ = input.Update(msg, m.nickNameInput)
m.emailInput, _ = input.Update(msg, m.emailInput)
return m
}
func subscriptions(model boba.Model) boba.Subs {
m, ok := model.(Model)
if !ok {
return nil
}
// It's a little hacky, but we're using the subscription from one
// input element to handle the blinking for all elements. It doesn't
// have to be this way, we're just feeling a bit lazy at the moment.
inputSub, err := input.MakeSub(m.nameInput)
if err != nil {
return nil
}
return boba.Subs{
// It's a little hacky, but we're using the subscription from one
// input element to handle the blinking for all elements. It doesn't
// have to be this way, we're just feeling a bit lazy at the moment.
"blink": inputSub,
}
func updateInputs(msg boba.Msg, m Model) (Model, boba.Cmd) {
var (
cmd boba.Cmd
cmds []boba.Cmd
)
m.nameInput, cmd = input.Update(msg, m.nameInput)
cmds = append(cmds, cmd)
m.nickNameInput, cmd = input.Update(msg, m.nickNameInput)
cmds = append(cmds, cmd)
m.emailInput, cmd = input.Update(msg, m.emailInput)
cmds = append(cmds, cmd)
return m, boba.Batch(cmds...)
}
func view(model boba.Model) string {

View File

@@ -1,6 +1,6 @@
package main
// TODO: This code feels messy. Clean it up.
// TODO: The views feel messy. Clean 'em up.
import (
"fmt"
@@ -17,7 +17,6 @@ func main() {
initialize,
update,
view,
subscriptions,
)
if err := p.Start(); err != nil {
fmt.Println("could not start program:", err)
@@ -26,17 +25,9 @@ func main() {
// MSG
type tickMsg time.Time
type tickMsg struct{}
func newTickMsg(t time.Time) boba.Msg {
return tickMsg(t)
}
type frameMsg time.Time
func newFrameMsg(t time.Time) boba.Msg {
return frameMsg(t)
}
type frameMsg struct{}
// MODEL
@@ -53,21 +44,19 @@ type Model struct {
// INIT
func initialize() (boba.Model, boba.Cmd) {
return Model{0, false, 10, 0, 0, false}, nil
return Model{0, false, 10, 0, 0, false}, tick
}
// SUBSCRIPTIONS
// CMDS
func subscriptions(model boba.Model) boba.Subs {
m, _ := model.(Model)
if !m.Chosen || m.Loaded {
return boba.Subs{
"tick": boba.Every(time.Second, newTickMsg),
}
}
return boba.Subs{
"frame": boba.Every(time.Second/60, newFrameMsg),
}
func tick() boba.Msg {
time.Sleep(time.Second)
return tickMsg{}
}
func frame() boba.Msg {
time.Sleep(time.Second / 60)
return frameMsg{}
}
// UPDATE
@@ -118,7 +107,7 @@ func updateChoices(msg boba.Msg, m Model) (boba.Model, boba.Cmd) {
m.Ticks -= 1
}
return m, nil
return m, tick
}
func updateChosen(msg boba.Msg, m Model) (boba.Model, boba.Cmd) {
@@ -137,7 +126,7 @@ func updateChosen(msg boba.Msg, m Model) (boba.Model, boba.Cmd) {
case frameMsg:
if !m.Loaded {
m.Frames += 1
m.Progress = ease.OutBounce(float64(m.Frames) / float64(120))
m.Progress = ease.OutBounce(float64(m.Frames) / float64(160))
if m.Progress >= 1 {
m.Progress = 1
m.Loaded = true
@@ -154,7 +143,7 @@ func updateChosen(msg boba.Msg, m Model) (boba.Model, boba.Cmd) {
}
}
return m, nil
return m, frame
}
// VIEW