Compare commits

...

3 Commits

Author SHA1 Message Date
Tristan B. Velloza Kildaire 4ecc8f428a
Merge 8dca2ebf73 into 0e232822fa 2024-04-26 14:50:13 +00:00
Tristan B. Velloza Kildaire 8dca2ebf73 Tree
- Reworking opSlicwe
2024-04-26 16:50:01 +02:00
Tristan B. Velloza Kildaire 0e232822fa
Feature: Prompting framework (#16)
* Prompter

- Added

Prompt

- Added

* Prompter

- Fixed source `File` check

Prompter (unittests)

- Added a unittest

* Prompter

- Fixed `prompt()`

Prompter (unittests)

- `flush()` pipe write end

* Prompter (unittests)

- Cleaned up

* Prompter (unittests)

- Cleaned up

* Prompter (unittests)

- Fixed missing import

* Prompter

- Added more docs

* Prompter

- Added more docs

* Prompt

- Documented

* Prompter

- Cleand up

* Prompter (unittests)

- Removed unittest

* README

- Updated
2024-04-15 10:45:16 +02:00
3 changed files with 237 additions and 2 deletions

View File

@ -40,6 +40,8 @@ is expected to grow over time.
* `niknaks.containers`
* Some useful container types
* Things such as `CacheMap`
* `niknaks.mechanisms`
* User-defined input prompter, retry mechanisms
## License

View File

@ -839,9 +839,41 @@ public class Tree(T)
return false;
}
public T opIndex(size_t idx)
// public T opIndex(size_t idx)
// {
// return idx < this.children.length ? this.children[idx].getValue() : T.init;
// }
private bool isTreeNodeType(E)()
{
return idx < this.children.length ? this.children[idx].getValue() : T.init;
return __traits(isSame, E, Tree!(T)[]);
}
private bool isTreeValueType(E)()
{
return __traits(isSame, E, T[]);
}
public E opSlice(E)()
if(isTreeNodeType!(E) || isTreeValueType!(E))
{
// If the children as tree nodes is requested
static if(isTreeNodeType!(E))
{
return this.children;
}
else static if(isTreeValueType!(E))
{
T[] slice;
foreach(Tree!(Tree) tnode; this.children)
{
slice ~= tnode.getValue();
}
return slice;
import std.algorithm.iteration : map;
return map!(&getValue, this.children);
}
}
public T getValue()

View File

@ -9,6 +9,8 @@ import std.functional : toDelegate;
import std.datetime : Duration;
import std.datetime.stopwatch : StopWatch, AutoStart;
import core.thread : Thread;
import std.stdio : File, write;
import std.string : strip;
/**
* A verdict-providing function
@ -291,4 +293,203 @@ unittest
}
}
/**
* A user-defined prompt
*/
public struct Prompt
{
private string query;
private string value;
/**
* Constructs a new prompt
* with the given query
*
* Params:
* query = the prompt
* query itself
*/
this(string query)
{
this.query = query;
}
/**
* Gets the prompt query
*
* Returns: the query
*/
public string getQuery()
{
return this.query;
}
/**
* Retrieves this prompt's
* answer
*
* Returns: the answer
*/
public string getValue()
{
return this.value;
}
/**
* Fill this prompt's
* query with a corresponding
* answer
*
* Params:
* value = the answer
*/
public void fill(string value)
{
this.value = value;
}
}
/**
* A prompting mechanism
* which can be filled up
* with questions and a
* file-based source to
* read answers in from
* and associate with
* their original respective
* questions
*/
public class Prompter
{
/**
* Source file
*/
private File source;
/**
* Whether or not to close
* the source file on destruction
*/
private bool closeOnDestruct;
/**
* Prompts to query by
*/
private Prompt[] prompts;
/**
* Constructs a new prompter
* with the given file source
* from where the input is to
* be read from.
*
* Params:
* source = the `File` to
* read from
* closeOnDestruct = if
* set to `true` then on
* destruction we will close
* the source, if `false` it
* is left untouched
*
* Throws:
* Exception if the provided
* `File` is not open
*/
this(File source, bool closeOnDestruct = false)
{
if(!source.isOpen())
{
throw new Exception("Source not open");
}
this.closeOnDestruct = closeOnDestruct;
this.source = source;
}
/**
* Appends the given prompt
*
* Params:
* prompt = the prompt
*/
public void addPrompt(Prompt prompt)
{
this.prompts ~= prompt;
}
/**
* Performs the prompting
* by querying each attached
* prompt for an answer
* which is then associated
* with the given prompt
*
* Returns: the answered
* prompts
*/
public Prompt[] prompt()
{
char[] buff;
foreach(ref Prompt prompt; this.prompts)
{
scope(exit)
{
buff.length = 0;
}
// Perform the query
write(prompt.getQuery());
this.source.readln(buff);
// Fill answer into prompt
prompt.fill(strip(cast(string)buff));
}
return this.prompts;
}
/**
* Destructor
*/
~this()
{
if(this.closeOnDestruct)
{
this.source.close();
}
}
}
version(unittest)
{
import std.process : pipe, Pipe;
import std.conv : to;
import std.stdio : writeln;
}
unittest
{
Pipe pipe = pipe();
// Create a prompter with some prompts
Prompter p = new Prompter(pipe.readEnd());
p.addPrompt(Prompt("What is your name?"));
p.addPrompt(Prompt("How old are you"));
// Fill up pipe with data for read end
File writeEnd = pipe.writeEnd();
writeEnd.writeln("Tristan Brice Velloza Kildaire");
writeEnd.writeln(1);
writeEnd.flush();
// Perform the prompt and get the
// answers back out
Prompt[] ans = p.prompt();
writeln(ans);
assert(ans[0].getValue() == "Tristan Brice Velloza Kildaire");
assert(to!(int)(ans[1].getValue()) == 1); // TODO: Allow union conversion later
}