stubbleorg / stubble Goto Github PK
View Code? Open in Web Editor NEWTrimmed down {{mustache}} templates in .NET
License: Other
Trimmed down {{mustache}} templates in .NET
License: Other
Hi,
BaseSettingsBuilder.SetParserPipeline
exists today to be able to set a pipeline with own parsers, this is used in https://github.com/StubbleOrg/Stubble.Helpers project to be able to add template methods that is executed instead of inserting values for the tokens that is found. This SetParserPipeline
method is little hard to work with when you have multiple extensions project that all need to modify the parser pipeline. I think this should be replaced with a builder instead, example
new RendererSettingsBuilder()
.ConfigureParserPipeline(pipe => pipe
.Replace(...)
.AddAfter(...)
.AddBefore(....)
)
.BuildSettings();
where the BuildSettings()
is calling the ParserPipelineBuilder.Build()
to build the parser pipeline.
What do you think of a change like this?
When creating templates I sometimes have the need to repeat the sections X amount of times. If we see the current sections implementation it handle number as if-condition (0 = false,other value = true). If the section got a list or dictionary as value the template is iterating over the items in the value.
Is there any possibility today to do something like this?
Is it possible to add the feature into the SectionTokenRenderer
so they from the input data; when a number that is positive value, creating a list of items that is used?
Example data:
{
"count": 5
}
With template:
{{#count}}
Item {{.}}
{{/count}}
Should generate:
Item 1
Item 2
Item 3
Item 4
Item 5
Since System.String impements IEnumerable it gets looped through as though it's a list. For now I can just add certain types to an IEnumerable blacklist to avoid this.
Would it make sense to change the name of the main stubble class (and interface) to StubbleRenderer?
I noticed that the class name clashes with the root namespace (Stubble.Core.Stubble) so references to the class need to be fully qualified. Your tests don't have this problem because they all exist in Stubble.Core.Tests.
So for a simple contrived example: -
using System;
using Stubble.Core;
namespace StubbleTest
{
class MainClass
{
public static void Main (string[] args)
{
var stubble = new Stubble();
var output = stubble.Render("{{Foo}}", new { Foo = "Bar" });
Console.WriteLine("Output[" + output + "]");
}
}
}
You get the compiler error: -
Error CS0118: 'Stubble' is a 'namespace' but a 'type' was expected (CS0118) (StubbleTest)
On the other hand, maybe I am missing something obvious...
This will allow people to use them when extending tag renderers
Hi, Thank you for this system, it works great so far!
I have a couple questions:
I understand this is kind of a ridiculous request but I am working on an porting an app that used Nustache to .Net core and it seems like your previous version wasn't compatible with the latest version of .Net core. I'm assuming the new alpha will have compatibility so I was wondering when it will be available on Nuget?
Thanks
The "How to use" section is not up to date.
The example:
var stubble = new Stubble();
var myObj = new MyObj();
using (StreamReader streamReader = new StreamReader(".\Path\To\My\File.Mustache", Encoding.UTF8))
{
var output = stubble.Render(streamReader.ReadToEnd(), myObj);
}
should be:
var stubble = new StubbleBuilder().Build();
var myObj = new MyObj();
using (StreamReader streamReader = new StreamReader(".\Path\To\My\File.Mustache", Encoding.UTF8))
{
var output = await stubble.RenderAsync(streamReader.ReadToEnd(), myObj);
}
The culture for the tests is currently assumed, we tried replacing it using both the xunit sample for use culture here and with the extension library by natemcmaster here.
It only seems to fail when run via Cake. I can only assume it's something to do with paralellism but more investigation needs to be done to fix it.
The PR we had to revert was #57
It's certainly possible that people will want to store templates on the file system or in a database and so loading interfaces could be blocking.
We should add an async method to the IStubbleRenderer
which calls an AsyncLoad
method of IStubbleBuilder
. For efficiency (since the majority of the calls should be non-blocking) the async interface should implement ValueTask
Hi,
Thank you for this great library you provide.
I have a question about its usage.
Is it safe to use RenderAsync method of a StubbleVisitorRenderer instance in parallel with different parameters?
I am planning to provide it in a service wrapper which will have one instance at a time via Unity.
Thank you,
Change the tag renderers to use a more visitor based pattern so we can have different kinds of visitors that take the same tags. This will eventually allow for different kinds of renderers so we can render to a string, or a function or even an assembly.
Currently this is hard coded and doesn't allow looping through thing such as dictionaries which you may want in your specific case.
The full spec can be found "here". <= this link.
Instead of using WebUtility.HtmlEncode
, is it possible to support customized html encode method?
It would be good if we could target Stubble for a variety of platforms and framework versions much like NodaTime as it would be good for People to be able to use Stubble on Mono, or DNX or .Net Core .etc
To keep parity with Nustache we should provide a renderer that will render templates to an Expression Tree which can be compiled to a strongly typed Func.
To see if we can get better speed, clarity or less garbage generation
I have a UWP project that use Stubble to render some mustache file. Some time I'll get this exception:
You have reached the maximum recursion limit of 256.
What does it means?
Thanks
Hi all,
Disclaimer: I am not a very versed .net developer....
I am looking to use Mustache templates in PowerShell. Would it be doable to use Stubble?
I would like to render \r
, \n
and \r\n
as a line break. Looking at other issues and the documentation I tried playing with RenderSettings SkipHtmlEncoding true, but this did not help me.
Is there a place I can hook into the rendering process to replace line breaks with a <br>
tag to make this work for me?
Thanks for all your hard work!
This is useful if taking templates from javascript style naming to c# style naming e.g.
myVariable โ MyVariable
IsTruthy
could be incorrect for certain implementations of the interface such as JToken
which implements IEnumerable
and can have a value but not contain child elements which would cause IEnumerable
to be falsey.
It may be worth adding a registry to this so you can override or add to this much like the other planned extensions.
the example code:
var data = JsonConvert.DeserializeObject("{ \"name\": \"test\" }");
var tpl = "My name is: {{name}}";
var stubble = new StubbleBuilder().Build();
var res = stubble.Render(tpl, data);
I expected value:
My name is: test
But just only:
My name is:
It would be great to easily use Mustache in Cake scripts. I propose creating a Cake.Stubble plugin with some signatures like:
string MustacheRender(string template, object viewModel);
string MustacheRender(string template, object viewModel, Action<RendererSettingsBuilder> configurator);
string MustacheRenderFile(FilePath templateFile, object viewModel);
string MustacheRenderFile(FilePath templateFile, object viewModel, Action<RendererSettingsBuilder> configurator);
The Cake team discussed adding templating support to Cake at one point, but I think it fell through.
I'm trying to figure out how to intercept the token resolver so that I can provide a different value if the key is not in the context dictionary. My specific use case is that I will always have an entity ID but may not have details on that entity and would like to print the id instead of the details when details are not present.
Hello {{User.Email}}, // want to default to value to "user: {{User.Id}}" as this will always be populated.
I've tried playing with the value getter but couldn't get it to do what I wanted - is there any other hook I should look at ?
private StubbleVisitorRenderer _builder = new StubbleBuilder()
.Configure(settings =>
{
settings.AddValueGetter(typeof(IDictionary<string, object>), (key, value, ignoreCase) =>
{
Console.WriteLine("HERE", key, value, ignoreCase); // won't trigger
return value;
});
When enumerating through an IEnumerator we don't reset after the first time so if using twice in the same context no values are returned.
I am using the type reflection based approach to convert ReactiveUI's EventBuilder over to use Stubble, previously it was using Mustache.
What this event builder does is generate code based around events in a class.
The ReflectionHelper.GetMemberFunctionLookup() can't handle this case at the moment due to just directly adding to the dictionary and not checking to see if the key already exists. It's crashing for me on get_DeclaredType().
Adding a ContainsValue() check can eliminate the crash. Not sure if that's quite desired functionality.
using Stubble.Core.Builders;
using System;
class Program
{
static string template =
@"Lorem ipsum dolor sit amet, consectetur adipiscing elit.
{{{ATag}}}
{{{ATag}}}
{{{ATag}}}
{{{ATag}}}
Nulla non nulla sit amet ligula fringilla gravida sed vitae felis.
{{#ASection}}Aenean eu dui tincidunt risus fringilla fringilla.{{/ASection}}
{{#ASection}}Aenean eu dui tincidunt risus fringilla fringilla.{{/ASection}}
{{#ASection}}Aenean eu dui tincidunt risus fringilla fringilla.{{/ASection}}
{{#ASection}}Aenean eu dui tincidunt risus fringilla fringilla.{{/ASection}}
Nulla nisl nulla, vulputate quis dui eget, sagittis placerat neque. Aliquam eu arcu eget elit semper dapibus.";
static void Main (string[] args)
{
var stubble = new StubbleBuilder().Build();
var document = stubble.Render(template, null);
Console.Write(document);
Console.ReadKey();
}
}
I've come across a bug when rendering partial templates in Stubble.Core Version 1.1.2
If the partial tag is indented, e.g.
<div>
{{>Body}}
</div>
Then additional spaces can get appended to the end of variable tags that appear in the partial.
e.g if Body.mustache is
<a href="{{Url}}">
My Link
</a>
and the data is
{ "Url": "https://github.com" }
then the output is
<div>
<a href="https://github.com ">
My Link
</a>
</div>
Note the extra spaces that get rendered at the end of {{Url}}.
See https://github.com/StarLeafRob/StubblePartialBugExample for a program that reproduces this.
If you'd like me to have a go at fixing this, let me know - but I thought I'd report it as an issue first as I'm not very familiar with the Stubble code yet.
The following example code was not working for me (in Stubble/docs/how-to.md
):
(I did not copy the code but used it as a example.)
var obj2 = new {
Bar = "Bar",
Foo = new Func<string, object>((str) => { return "Foo {{Bar}}"; })
};
stubble.Render("{{Foo}} Hello World {{/Foo}}", obj2); //Outputs: "Foo Bar"
I found in Stubble/test/Stubble.Core.Tests/StaticStubbleTest.cs
that a # is required in the start tag ({{#Foo}}).
[EDIT]
I'm looking at SectionTokenRenderer and I can't see any lambdas that would hand the current context.
What could be handy is that a rendering function is passed to the lambdas like in mustache.js
Not sure about the code, but it's the idea.
//line SectionTokenRenderer:51
else if (value is Func<dynamic, string, object> || value is Func<string, object>)
{
var functionDynamicValue = value as Func<dynamic, string, object>;
var functionStringValue = value as Func<string, object>;
var sectionContent = obj.SectionContent;
value = functionDynamicValue != null
? functionDynamicValue.Invoke(context.View, sectionContent.ToString())
: functionStringValue.Invoke(sectionContent.ToString());
renderer.Render(context.RendererSettings.Parser.Parse(value.ToString(), obj.Tags), context);
}
//additionnal function type
value is Func<dynamic, string, Action<string>, object>
var functionDynamicValueWithContext = value as Func<dynamic, string, Action<string>, object>
value = functionDynamicValue.Invoke(context.View, sectionContent.ToString(), toRender => RENDER_FUNC_WITH_CONTEXT
Usage :
object MyLambda( dynamic data, string text, Action<string> renderer)
{
return renderer( "{{{" + renderer( data.Far.Boo ) + "}}}" );
}
[ORIGINAL]
Hi I'm comming from Nustache, and mainly I want to swap to Stubble because it is maintained and closer to Mustache Specs. I used to work with mustache.js for 2 years prior to going to c# world and I can't find the correct lib to get what I was doing with lambdas.
Now my setup is already working quite well with nustache but for one thing. I can't get the context to apply on Lambda functions :
I create an instance scoped object that will then be utilized by the lambdas, so I can get access recursively to my data object and lambdas when for instance doing recursive templating.
_data = new Dictionary<string, object>
{
{ "Dy", (Lambda) DyLambda }, // this is used in example
{ "Rec", (Lambda) RecLambda },
{ "SkBase", (Lambda) SkBaseLambda },
{ "Sk", (Lambda) SkLambda },
{ "SkCol", (Lambda) SkColLambda },
{ "SkDesc", (Lambda) SkDescLambda },
{ "Math", (Lambda) MathLambda },
{ "Readable", (Lambda) ReadableLambda },
{ "Lang", LangSerializable },
{ "Data", data }
};
private object DyLambda(string content, RenderContext context, RenderFunc writer)
{
return Render.StringToString("{{{" + RenderWithPartial(content, GetDataFromCtx(context)) + "}}}",
GetDataFromCtx(context), PartialResolver);
}
public string RenderWithPartial(string content, object data, RenderContextBehaviour context = null)
{
return Render.StringToString(content, data, PartialResolver, context);
}
private object GetDataFromCtx(RenderContext context)
{
return new Dictionary<string, object>
{
{ "Dy", (Lambda) DyLambda },
{ "Rec", (Lambda) RecLambda },
{ "Readable", (Lambda) ReadableLambda },
{ "SkBase", (Lambda) SkBaseLambda },
{ "Sk", (Lambda) SkLambda },
{ "SkCol", (Lambda) SkColLambda },
{ "SkDesc", (Lambda) SkDescLambda },
{ "Lang", LangSerializable },
{ "Data", context.GetValue("Data") },
{ "Skill", context.GetValue("Skill") },
{ "Skills", context.GetValue("Skills") },
{ "Math", (Lambda) MathLambda }
};
}
But then I can't consistently get the context of my data :
For instance if I have my data :
{
"Value" : "a",
"ValueDictionnary" :
{
"a" : "A is Cool",
"b" : "B is Hot"
}
}
I'd like to do :
{{#Data}}{{#Dy}}ValueDictionnary.{{Value}}{{/Dy}}{{/Data}}
to get A is Cool
But I can only do this as current context is not available in the lambdas :
{{#Dy}}Data.ValueDictionnary.{{Data.Value}}{{/Dy}}
It also makes impossible any array work in lambdas because scope is lost, I'm not even talking about the memory/processing overhead.
So what I'm asking, is the StubbleBuilder keeping a trace of current context, or is there a way to access it in the lambdas ? If not can we easily get it done ?
Maybe you'll tell me I was doing it all wrong it Nustache ...
In Mustache.js it was dead simple as one of the Lambda parameter was giving the builder with the current scope. The nustache solution was really hair-pulling.
From Mustache.js readme, this bold function will render text with all current context, lambdas and partials :
{
"name": "Tater",
"bold": function () {
return function (text, render) {
return "<b>" + render(text) + "</b>";
}
}
}
Thanks a lot !
Hello, I'm not sure if this is a bug, but if I do:
Dictionary<string, object> dataHash = new Dictionary<string, object>();
var output = StaticStubbleRenderer.Render("{{Foo.Value}}", dataHash);
Console.WriteLine(output);
it will print System.Collections.Generic.Dictionary
2[System.String,System.Object]I can also set Foo to null and it will still give me that message, wouldn't it be better to just show nothing or return a empty string? actually this will happen as soon as I only use
{{ foo }}`. if foo is not defined it will just return a empty string.
At the moment I can override the behaviour by registering a custom AddValueGetter
:
RendererSettings rsb = new RendererSettingsBuilder().AddValueGetter(typeof(IDictionary<string, object>), (o, s) =>
{
if (o is IDictionary<string, object>) // this might be unnecessary
{
var oo = o as IDictionary<string, object>;
if (oo.ContainsKey(s))
{
return oo[s];
}
}
return ""; // the problem might be that the default implementation emits null, which will yield the Dictionary message
}).BuildSettings();
Sometimes types are both objects and lists such as IDictionary
which you don't want the standard iteration functionality of a section tag.
We have a blacklist for these types which currently defaults to string
and IDictionary
and you can override this entirely however if you want to add a singular item on top of the defaults you can't.
It's possible to have Visual Studio generate a file on save of another file using a Single File Generator. T4 templates use the built-in TextTemplatingFileGenerator
, but I believe other custom generators can be installed by a Visual Studio Extension.
It'd be great to have this functionality with Mustache templates as well.
Stubble will fail as it will eventually always reach the max recursion depth after enough use.
This seems to be the default recommended version by microsoft and is the suggested version to target. We'll still provide a Net45 build for anyone on .Net Framework who would be left unsupported i.e. Net46
Would you consider adding a non standard, .net related extension like this one:
https://github.com/emazv72/Stubble.Extensions.StringFormatter
Thank you
Here is currently no way to set ValueGetters in
CompilerSettingsBuilder, it is missing
AddValueGetterand
AddEnumerationConverters`.
I tried to remove Parsers from the Pipeline.
First I tried to use the RendererSettingsBuilder SetParserPipeline method, but the ParserPipeline class is internal - no luck there.
And there is no way to bypass the ParserPipeline class :(
But why even provide a SetParserPipeline method then?
Is there any way to configure the behavior of stubble, if the key of template is not found from provide map ?
For example, there is one template {{name}}
, with Dictionary {"city": "abc"}
, when try to Process by default the {{name}}
will be replace to ""
silently. Here I would like to execption out or complain the key is missing from Dictionary.
The current regex parser creates more garbage than needed and also makes it difficult to add new complicated tags that include for example arguments.
Replace the parser and renderers with those inspired by Markdig. Parse the template using tag explicit parsers (which can be added to) and render them using tag explict renderers allowing eventually for different kinds of renderers such as a compile renderer.
Since we're building cross platform using the new CLI i'm finding that the build steps are becoming out of sync in the two environments and much of the logic is being put into the appveyor and travis configs.
We should migrate these steps to Cake which will allow consistency while also allowing specific logic for each such as the fact we can't currently do code coverage on Travis due to the newness of the cross plat story for dotnet.
We should use SourceLink to provide symbols for debugging. The only pitfall I can see currently is that OpenCover may not look for the PDB inside the dll.
Add Assert Template compile correctly for unit testing
I have the following template:
{{#infoRows}}
Caption: {{caption}} <br>
Party: { Name: {{party.name}} } <br> <br>
{{/infoRows}}
and have following data in json
{
"infoRows": [
{
"caption": "Caption #1",
"party": {
"name": "Party Name #1"
}
},
{
"caption": "Caption #2",
"party": {
"name": "Party Name #2"
}
}
]
}
Which look this way as at runtime:
When I use usual new StubbleBuilder().Build().Render(Template, Context)
, I get this:
When I use compilation
var renderer = new StubbleCompilationBuilder()
.Build()
.Compile<Dictionary<string, object>>(Template);
renderer(Context)
Why does it work this way?
Hey there, sorry for the question but I've exhausted all the tests/example code that I could find.
I've got a template that is similar to:
{{#Components}}
InComponents
{{#Schemas}}
InSchemas
// Trying to do a lot of different things in here.
{{/Schemas}}
{{/Components}}
And my data context is along the lines of:
public class MyBase {
public MyBase();
public MyComponents Components { get; set; }
}
public class MyComponents {
public MyComponents();
public IDictionary<string, MySchema> Schemas { get; set; }
}
public class MySchema {
public MySchema();
public string Description { get; set; }
}
My usage so far:
MyBase myBase = GetMyBase();
StubbleVisitorRenderer stubble = new StubbleBuilder().Build();
using (StreamReader streamReader = new StreamReader(@"template.mustache", Encoding.UTF8)) {
var output = stubble.Render(streamReader.ReadToEnd(), myBase);
Debug.WriteLine(output);
}
I was using a different library before that would output the following assuming myBase.Components.Schemas.Count == 3
:
InComponents
InSchemas
InSchemas
InSchemas
Stubble only outputs:
InComponents
InSchemas
I have figured out how to create a section with a specific key in the dictionary via {{#MyKeyName}}{{Description}}{{/MyKeyName}}
.
Along the same lines, I'd like to get the key name while looping.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.