Open dcsan opened 5 years ago
I think its down to trying to capture the user's input chosen color here:
~ color
< What's your favorite color?
> *{color}
but when i remove that there's no way to capture the color in a variable for later, eg:
~ color
< What's your favorite color?
---
> purple
< Do you like Prince?
---
> blue
< Don't be sad!
---
> *{color}
< OK you like ${color}
if they say blue
or purple
I don't know of a way to capture that variable.
also there are some problems 'returning' from a conditional block
loaded in: 8.798ms
< OK lets go
< What's your favorite color?
> blue
< Don't be sad!
(now we're stuck, flow doesn't return from that block, and no other options get picked up either)
> cyan
WARN: [botml] No matching dialogue found.
> blue
WARN: [botml] No matching dialogue found.
however if I used an unknown color that fell through to the end it would work
> survey
< OK lets go
< What's your favorite color?
> asdfdsf
< OK you like asdfdsf
< How old are you?
>
so a bit puzzled on a few things here.
Hey DC
We're currently working on bubl, a codepen-like solution dedicated at designing botml-enabled bots.
It's not polished just yet, but could improve your workflow by letting you test it in a REPL way, validate your scripts and observe all the conversational paths dynamically.
Could you test your script there?
Got it, I saw that on your notion page.
The whole script is in the URL then? Hope that works :) I can see the same problems
so when the extra capture is there
~ colors
< Whats your favorite color?
> *{color}
---
> red
< roses are red
---
everything will get captured there. So actually it looks like I misunderstood that usage, I got it from your email example
https://github.com/codename-co/botml#conditional-branches
~ ask_for_email
> start email workflow
~ listen_email
< Your email please?
> *{email}
---
` !/^.+@.+\..+/.test('$email')
< This email $email seems not legit!
~ [listen_email]
---
< Cool. We'll reach you over at $email
but I guess in that case you are then capturing and doing tests later against the variable itself.
So this method works, it's just quite ugly to write:
~ colors
< Whats your favorite color?
> *{color}
---
` 'red'.test($color) `
< roses are red
---
` 'blue'.test($color) `
< sky is blue
---
> *{color}
< you like $color
So then the question is how to capture variables if just using normal expression matching without regexes
It seems clear that the conditional branches should be more documented.
You are right: there are two ways of using them, and a few things to know beforehand.
The first thing to know is that in botml, any block is linear, meaning there is a single start and a single end. Except for conditional branches, where we can conditionally fork into external paths.
To me the best example that describes it is the following authentication flow:
~ authenticate
< What is the password?
~ password-ask
--
> secret
~ [password-right]
--
< No, that is not the password. Try again.
~ [password-ask]
~ password-right
< Access granted.
Here, we see that very linear flow that relies on a breakpoint ~ password-ask
to loop (via ~ [password-ask]
).
But there is an edge case: which is actually knowing the passcode. And here we fork to an "external" branch (here it's at the end of the block, but it could be the reference of another workflow.
This is the primary way of using conditional branches, where the capture/test is done at each step and enables the more flexibility.
The second thing to know is that, because blocks are linear, they will "return" into their parent flow (if any) only when their main flow is reached; not the edge cases.
Another way of using conditional branches is to capture first, like in the docs:
~ ask_for_email
> start email workflow
~ listen_email
< Your email please?
> *{email}
---
` !/^.+@.+\..+/.test('$email')
< This email $email seems not legit!
~ [listen_email]
---
< Cool. We'll reach you over at $email
The best use case for this type of writing are validations. In such cases, we want to capture first, and fork to a branch only after a certain type of test.
We found this way of handling tests and validations way clearer. And very handy in production for handling real complex use cases.
But this can be subject to discussion, and I can understand that it may not the most clearer choice.
The second thing to know is that, because blocks are linear, they will "return" into their parent flow (if any) only when their main flow is reached; not the edge cases.
when you say "edge case" you mean when any condition is met other than the default/fall-through?
So I guess I understand, but that means there is no way to return
if you match anything. So I'm not sure what the use case would be beyond simple Q=>A scripts. Managing state / conditionals / control flow with botML seems very difficult?
The other method you've shown is basically writing javascript inside ``` blocks. So switching back and forth between the two, where all logic is actually JS. That seems a bit messy... Also that doesn't actually allow blocks to be treated as return from subroutines.
Did you think of other ways to handle conditionals?
I'm sure there's a bot ruby-like DSL that has the basic flow-control of a script language, but without all the extra {( )}
noise of a script. maybe it's just a coffeescript like transpile to JS...
For example if a line did NOT have one of the special symbols could it just be treated as JS?
if $input === 'password'
< good job!
return
or
:askpw
< whats the password
> *input
switch $input
when 'password'
< you got it!
return
when *
< not quite
go :askpw
for one of our YAML interpreters we ended up using a mongo like matching syntax, which was easy to parse but really ugly to hand-write.
- if { input: { $eq: "password" } }
for reference: https://www.rivescript.com/docs/tutorial#conditionals
+ what am i old enough to do
* <get age> == undefined => I don't know how old you are.
* <get age> > 25 => You can do anything you want.
* <get age> == 25 => You're old enough to rent a car with no extra fees.
conditionals aren't too bad and do allow you to also redirect
* <get age> > 25 => @tooYoung
if they just got rid of that XMLy stuff and had $age > 25 => @sub
I made a simple "survey" type bot, but the conditionals logic doesn't seem to work like expected. .bot script is here: https://github.com/dcsan/botml/blob/master/examples/survey.bot
I run it with
nodemon --ext js,bot lib/cli.js examples/survey.bot
but I get a result like this on running it: