Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Separator output bug #126

Open
BrianCatlin opened this issue Dec 15, 2019 · 5 comments
Open

Separator output bug #126

BrianCatlin opened this issue Dec 15, 2019 · 5 comments

Comments

@BrianCatlin
Copy link

BrianCatlin commented Dec 15, 2019

When iterating over a list, separators for items skipped at the beginning of a list are not output, but once an item in the list is output, separators are output for subsequent items, even when items are skipped. The following C# code illustrates this. The output is: "2 is even," (note the trailing comma separator, but there isn't a comma before the 2, for the first skipped item)

static void Main (string [] args)
        {
        List <Item> items = new List <Item> () { new Item ("1", false), new Item ("2", true), new Item ("3",false)};
        string      string_template_group =
@"
even_params (parameters) ::=
<<
<parameters:{p|<if (p.is_even)><p.value> is even<endif>}; separator = "", "">
>>
";
        TemplateGroup   group = new TemplateGroupString (string_template_group);

        Template even_params = group.GetInstanceOf ("even_params");
        even_params.Add ("parameters", items);
        Console.WriteLine (even_params.Render ());
        }   // End Main

class Item
    {
    public string   value   { get; set; }
    public bool     is_even { get; set; }

    public Item (string V, bool E)
        {
        value = V;
        is_even = E;
        }

    }   // End class Item
@chaami
Copy link

chaami commented Dec 18, 2019

Hi Brian,
I am no expert, but in your template, the odd parameters are not skipped per say, you simply don't output anything when treating them.
Considering that it has treated said parameter (even by not printing anything), string template logically adds a separator.
As ways to obtain what you are looking for, you could filter out items by adding a .where(i => i.isEven) LINQ call to items when adding them to the template ?
The template can then become the dead simple

<parameters;separator= "", "">

Another possibility that I see is to use two templates combined with the use of first() and rest() functions
You print the first element without a comma and then call another template:

$if(first($parameters).isEven)$$first($parameters).value$ is even$endif$$PrintFollowers(rest(parameters))$

In PrintFollowers you simply add the comma directly to each even parameter print.

Please notice that I am using slightly modified attribute names in the code above and '$' as delimiters 😅 .
Also I would suggest making the Value parameter as an int and compute isEven with a modulo for easier testing 😉

I hope this helps.
Kind regards.

@BrianCatlin
Copy link
Author

Thank you for your response @chaami

If what you say is true, then there should have been a separator between all items in the list, but there isn't; however, notice that there aren't separators for items not output for items at the beginning of the list, but once an item is output (in my example, the second item), then ST outputs a separator for every subsequent item. So, clearly ST knows that it shouldn't be outputting separators at the beginning of the list, but once it does output an item it forgot to suppress separators for items not output.

I hadn’t thought about using LINQ for filtering. Thank you for that!

@chaami
Copy link

chaami commented Dec 19, 2019

Hi @BrianCatlin,
Oups, actually the second workaround that I have given you missing the case when the first member is odd !
Complete solution:

<if(first(parameters).isEven)><first(parameters).value> is even<PrintFollowers(rest(parameters))>
<else><even_params(rest(parameters))><endif>

Actually if print the length of the list with

<length(parameters:{p|<if (p.is_even)><p.value> is even<endif>})>

Should yield to 3.
My guess is that StringTemplate handles gracefully empty first elements of lists and then you are on your own 😉
strip() unfortunately only remove null values...
I haven't found a way to push a null in a list through templates (only by specifically adding null in the c# Add call).

@BrianCatlin
Copy link
Author

Thanks!

@chaami
Copy link

chaami commented Dec 19, 2019

Glad I could help...
It helped me dig a little deeper into StringTemplate 😉
Good luck !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants