Dependencies (Included)

The Simple Stuff

Basically, you use FluTe like this, the same way you would
string.Format, except using named tokens and a special syntax for injection

string res = FluTe.Define("My name is {fname} {lname}")
.Bind(fname => "Greg")
.Bind(lname => "Ros");
//this actually uses an implicit conversion. The result of the Bind method is not a string.

In this example, the names of the tokens are fname and
lname. We bind each of these tokens to the values
"Greg" and "Ros". The result is a template object containing the appropriate bindings. This template object is then implicitly converted into a string by being
resolved (i.e. all specially marked tokens are replaced with their bound values(.
Note that we match a token to its respective value using the lambdas; they are part of the special, fluent syntax. The lambdas are resolved immediately, and the single parameter only serves to mark the token we want to set. The value it passes is arbitrary.
If you don't like this lambdas syntax, don't worry,
FluTe has several additional syntax options to offer. See the documentation.Tip: FluTe ignores all whitespace within tokens.

A More Complicated Example

Imagine this scenario. You want to format an error message saying the user has exceeded the maximum number of characters in your textbox. Using
string.Format, you might write something like,

string.Format
("You've put {0} characters in the textbox {1}, more than the maximum of {2}.", numChars, textboxName, maxChars);

However, using FluTe you could actually encapsulate the template string, the input names, and the action of binding values to to those names in a single object. When defining this object, you'll write something like this:

FluTeInstance ErrorTemplate = "You've put {txtbox.Text.Length} characters in the textbox {txtbox.Name}, but it only supports up to {txtbox.MaxLength} characters.";
//As noted above, an implicit conversion occurs here as well.

This is the definition of the template string. Unlike in the basic example above, in this case we use the special reference syntax --
{txtbox.Name} -- to get some property within the value, rather than the value itself. The property is resolved dynamically, via late binding (using the
Impromptu framework, actually). You can also reference parameterless methods using this syntax, e.g. by writing
{txtbox.Method()}. You cannot reference other members using this syntax.

string errorMessage = ErrorTemplate
.Bind(txtbox => inputParam);

Just like in the simple example above, here we also bind a value. The main difference here, however, is that we have many tokens --
{txtbox.Name}, {txtbox.MaxLength}, etc. -- but they all reference the same value. The value referenced by various tokens is called the
input. Inputs have labels (identifiers or names). Here, the various tokens all reference a single input, named
txtbox and process it differently. That's why we only need to bind a single input to a value.Tip: FluTe is case-sensitive.

Static Inputs

Let's say that we want the error message shown above to echo the session information back to the user. Seeing as we want to reduce dependencies, we wouldn't want the same code that analyzes the contents of the textbox to reference the session object
and inject it into the string. The text validation code should probably have as little contact with the session as possible.

To facilitate this, we can use the FluTe feature called
static inputs. In the previous sections, we've explored inputs we bind on the spot. These inputs weren't part of the definition of the template -- they were actually part of its realization. However, we can also define inputs that are part of
the template. These inputs can even reference all sorts of information outside of the immediate scope.

FluTeInstance ErrorTemplate = "The input called {input.Name} of type {input.Type} only supports {input.MaxLength} characters, but you've gone and filled it with {input.Text.Length} characters. You should be ashamed, {$ session.LoginName}";

Inputs marked with the $ character are the aforementioned
static inputs. They are somewhat special, in that instead of defining them using a concrete value, we actually define them using a parameterless method (e.g. a lambda). This method gets resolved once, for each token that references the input (meaning,
it gets resolved multiple times if multiple tokens reference it).
Using static inputs, we can do something like this:

//define the template in some scope where the session object is accessible...
FluTeInstance ErrorTemplate = "The input called {input.Name} of type {input.Type} only supports {input.MaxLength} characters, but you've gone and filled it with {input.Text.Length} characters. You should be ashamed, {$ session.LoginName}".BindStatic(session => CurrentSessionObject); //CurrentSessionObject is accessible within this scope.

Then, the text validation code can access the template object from somewhere, without even knowing that it references the session object from wherever. When the template is resolved, it will get the value of
CurrentSessionObject in the scope where it was referenced (meaning, even if the value changed by that time). You could say that static inputs are evaluated lazily, while instance inputs are evaluated immediately.

By the way, if you don't care about getting the most recent value, you can do something similar to the above, except omit the
$ marker and use the standard
Bind method. FluTe actually supports partial resolution of templates, so you can just bind the input 'session' to a value, and send the template to another object. In this case, the input gets resolved immediately,
and only once. If you later change the value of the CurrentSessionObject property, the template will remain bound to the old value.

Oh, it is not possible to use the BindStatic method after you use the
Bind method. This is because the
Bind method returns an object that doesn't have the
BindStatic method. More on typing later.Tip: Note that the $ character modifies the input label, which is
session, rather than the token name , which is
session.LoginName.

Processing and Serializing Inputs

FluTe also allows you to process tokens before they are injected into the result string. Let me demonstrate this using a scenario.
We want to display a list of products to the user. This list is contained within the property
Products. Normally, we would have to do something like this:

We can clearly see that the logic joining the products into a string is totally separate from the template. However, from an organizational standpoint, the logic is actually inherently related to it.
FluTe allows us to embed this logic into the template using
processing steps. These are, essentially, objects that specify delegates which are to be performed sequentially upon the input referenced by a token. Here is an example of how they are used?

The For method attaches the delegate
products => string.Join(",",products to the token called
{products}. This means that, before the token {products} (a collection of some sort) is injected into the template, the constituent elemnts of the input it references will first be joined. Having defined the template,
we can do this:

listOfProducts.Bind(products => new[] {"Eggs", "Ham", "Butter"});

And the template listOfProducts will automatically join these items when the template is resolved.FluTe also allows you to concatenate processing steps using a fluent syntax. It incldues special, pre-written processing steps you can parameterize in order to shorten the definition of the template

This template will now take the token {products}, transform its constituents to upper case, and join them as though they were words. Using the same
Bind invocation as above, we'll now get:

This is what you bought: EGGS, HARM, and BUTTER.

Here, note that the method For returns a special configurator object that retains the token it configures in memory. Thus, the invocations of the methods
AsSeq, Select, etc, are applied only to the token denoted in the
For method. The Next property ends the configuration, and returns the finalized template, with all processing steps added.

If your template has several different tokens, you can used the
For method to configure them seperately, by name.

FluTeInstance listOfProducts = FluTe.Create("This is what you bought: {products}. You've made a {choiceKind}.")
.For("products").AsSeq<string>().Select(x => x.ToUpper()).WordJoin(", ", ", and ")
.For(choiceKind => choiceKind.ToUpper()).Next; //note that calling the method For in the context of another For configurator involves an implicit call to Next.

You can also set post-processing, which is invoked after all tokens have been injected into the template, and applies to the whole string. You do this using the
Finally method, which you invoke during the definition of the template, before calling a
Bind method.

Different Kinds of Tokens

FluTe actually allows you to define different kinds of tokens. Up until now, you've seen tokens that have a single input, and have an identical name as that input. However, what if you want to process the same information,
in different ways? Well, FluTe allows you to define tokens differently for such purposes.

An Aside on Typing

The three primary classes of FluTe are the following:

FluTe, a static class containing factory methods.

FluTePrototype, a class that is created by the method
FluTe.Create, and accepts an implicit conversion from string. Can be modified by adding processing steps, static inputs, etc. You cannot inject instance inputs into it, since it is not a finalized template.

FluTeInstance, a class created by an implicit conversion from
FluTePrototype, or via the instance method
FluTePrototype.Construct(). Cannot be modified by adding processing steps. Used for injecting input values and resolving to a string via implicit conversion, or
.Resolve() method. You can only resolve the
FluTeInstance if all the inputs have been filled.

I hope that clears up some of your confusion...

Future Feature: Template Serialization.

Template Serialization is a major feature that hasn't been developed yet. Basically, it allows you to serialize many templates into XML and other formats, and do whatever you want with them. This will be made possible using an expression serialization library,
though right now I'm not sure which one. I really haven't researched this possibility enough, so the only thing I can gurantee is that it will allow you to serialize
some templates and deserialize them while the FluTe assembly is referenced. It's also likely that templates will be naturally restricted in serialization by the data types they reference.

Immutability

Care has been taken to gurantee thread safety by simply ensuring the immutability of all, or nearly all classes. The only mutable objects the classes
FluTeLiquid and FluTeSolid employ are private, readonly, and never editted after the object is constructed. Nevertheless, the library hasn't undergone any serious thread safety tests, so
right now it should still be considered suspect.