Example, how to use huge json in erlyDTL? - erlang

I have json
{
"_total": 824,
"_links": "self",
"top": [
{
"viewers": 80896,
"channels": 1177,
"game": {
"name": "League of Legends",
"_id": 21779,
}
},
{
"viewers": 31211,
"channels": 232,
"game": {
"name": "Dota 2",
"_id": 29595,
}
}
]
}
how best displayed "top" list? I try:
Tuple = jsx:decode(unicode:characters_to_binary(Json)),
[_, _, Top] = Tuple,
Games = element(2, Top);
but how using this in template?
{% for v in games %}
{{ v.viewers }}<br><br>
{{ v.channel }}<br><br>
{{ v.game.name }}<br><br>
{% endfor %}
not work, and then show {{ games.game.name }} ?

The code you did is fine, it just need a few updates, you shouldn't pass Games to the template, instead you should use top as the key, as an example, build a rebar file like:
%rebar.config
{deps, [
{erlydtl, ".*", {git, "git#github.com:erlydtl/erlydtl.git", "HEAD"}},
{jsx, ".*", {git, "git#github.com:talentdeficit/jsx.git", "HEAD"}}
]}.
then run:
rebar get-deps
rebar compile
Now define a template with the suggested update, named template.dtl:
{% for v in top %}
{{ v.viewers }}<br><br>
{{ v.channels }}<br><br>
{{ v.game.name }}<br><br>
{% endfor %}
Start an erlang shell:
erl -pa ./deps/erlydtl/ebin/ -pa ./deps/merl/ebin/ -pa ./deps/jsx/ebin/
and execute the commands which should display the template as expected
Json = "{
\"_total\": 824,
\"_links\": \"self\",
\"top\": [
{
\"viewers\": 80896,
\"channels\": 1177,
\"game\": {
\"name\": \"League of Legends\",
\"_id\": 21779,
}
},
{
\"viewers\": 31211,
\"channels\": 232,
\"game\": {
\"name\": \"Dota 2\",
\"_id\": 29595,
}
}
]
}".
Tuple = jsx:decode(unicode:characters_to_binary(Json)).
erlydtl:compile("./template.dtl", test).
test:render(Tuple).
which gives the expecte output
{ok,[[[<<"\n ">>,"80896",<<"<br><br>\n ">>,"1177",
<<"<br><br>\n\t">>,<<"League of Legends">>,<<"<br><br>\n">>],
[<<"\n ">>,"31211",<<"<br><br>\n ">>,"232",
<<"<br><br>\n\t">>,<<"Dota 2">>,<<"<br><br>\n">>]],
<<"\n">>]}
in few words, in your template, replace games with top and pass Tuple to the template

Related

Jenkins Groovy reading maps from file and rendering html

How to Render HTML inputs Control using Active Choices Reactive Reference Parameter in Jenkins.
I am trying to create a Map and provide options in the Jenkins pipeline for parameterized output using a groovy script. Below Groovy works but I want to read service_name and release_tag from the file as it is and render the output. How do I read from the file and dump it in this script?
def tier = 'p1'
service_tier_map = [
"p1": [
["service_name": "web1", "release_tag": "1.0.0" ],
["service_name": "finance_service", "release_tag": "2.2.0" ],
],
"p2": [
["service_name": "web2", "release_tag": "2.0.0" ],
["service_name": "web4", "release_tag": "2.0.0" ],
],
"p3": [
["service_name": "web3", "release_tag": "3.0.0" ],
],
]
html_to_be_rendered = "<table><tr>"
service_list = service_tier_map[tier]
service_list.each { service ->
html_to_be_rendered = """
${html_to_be_rendered}
<tr>
<td>
<input name=\"value\" alt=\"${service.service_name}\" json=\"${service.service_name}\" type=\"checkbox\" class=\" \">
<label title=\"${service.service_name}\" class=\" \">${service.service_name}</label>
</td>
<td>
<input type=\"text\" class=\" \" name=\"value\" value=\"${service.release_tag}\" size="50"> </br>
</td>
</tr>
"""
}
html_to_be_rendered = "${html_to_be_rendered}</tr></table>"
return html_to_be_rendered

Data files with html content

I'm making a nice simple html page using external data... here's the bit that's causing me grief:
<section class="faq_main">
{% for section in faq.sections %}
<h3>{{ section.heading }}</h3>
{% for question in section.questions %}
<article class="faq_question">
<a id="hide_{{ section.code }}_{{ question.code }}"
href="#hide_{{ section.code }}_{{ question.code }}"
class="hide"><span class="faq_toggler">+</span> {{ question.question }}</a>
<a id="show_{{ section.code }}_{{ question.code }}"
href="#show_{{ section.code }}_{{ question.code }}"
class="show"><span class="faq_toggler">-</span> {{ question.question }}</a>
<div class="details">
{{ question.answer }}
</div>
</article>
{% endfor %}
<p> </p>
{% endfor %}
</section>
... and the matching faq.json file:
{
"sections" : [
{ "heading" : "Section the first",
"code" : "gn",
"questions" : [
{
"question": "What do questions need?",
"code" : "1",
"answer": "An answer"
},
{
"question": "Is this also a question?",
"code" : "2",
"answer": "Yes, it is"
},
{
"question": "Is this junk data?",
"code" : "a",
"answer": "Yes"
},
]
},
{
"heading": "Another section",
"code" : "f",
"questions": [
{
"question": "Can I have html in my answer?",
"code" : "2",
"answer": "<ul>\n<li>First, json needs newlines escaped to be newlines</li>\\n<li>Eleventy seems to 'sanitize' the string</li>\\n</ul>"
},
{
"question": "question b",
"code" : "b",
"answer": "answer b"
},
{
"question": "question c",
"code" : "or",
"answer": "answer c"
},
]
}
]
}
.... and the rendered text for the answer in question is:
<ul> <li>First, json needs newlines escaped to be newlines</li>\n<li>Eleventy seems to 'sanitize' the string</li></ul>
Do I have any options here? Is there a way to allow [even a subset of] html elements into the page?
(and yes, the CSS does the clever show/hide descriptions using the '+'/'-' symbols - all that side of things works just lovely)
It should work by inserting the symbols directly into the quotes in the json. Use Non-breaking spaces for indentation, and unicode points for dots.
Otherwise, the framework is broken.
Change {{ question.answer }} to {{ question.answer | safe }}
(see https://www.11ty.dev/docs/layouts/#prevent-double-escaping-in-layouts - it's clear, once you understand what it's saying :) )

String interpolation in jenkins pipeline for evaluating a string received as argument

I'm a newbie to jenkins/groovy and I'm lost at string interpolation.
We're trying to read a list of steps from a configuration file (stored in json format) and execute some actions bases on it in jenkins pipeline script.
Configuration file:
{
"actions": [ {
"operation": "create",
"args": [
{ "path": "${env.SVNRoot}\\trunk\\ABC" },
{ "path": "${env.SVNRoot}\\trunk\\XYZ" }
]
}, {
"operation": "delete",
"args": [
{ "path": "${env.SVNRoot}\\trunk\\ABC" },
{ "path": "${env.SVNRoot}\\trunk\\XYZ" }
]
}
] }
Jenkins Pipeline code:
node('master') {
echo "${env.SVNRoot}" //String interpolation works here, giving the right value
stage('ReadConfig'){
cfg = readJSON file: 'Cfg.json'
}
stage('ExecuteConfigActions'){
cfg.fileActions.each() {
switch(it.operation) {
case 'create':
it.args.each() {
echo it.path //String interpolation doesnt work here
break;
default:
break;
}
}
}
}
}
How can I get string interpolation to work in such a scenario? Basically I want the environment variable value to be substituted in its placeholder and the path hence derived.
I've tried single, double, escaped quotes to no avail.
The closest I can suggest is formulating a sprintf statement stored in the Configuration file and evaluated in your pipeline. Use at your own risk of someone being able to use the configuration file and substitute whatever they want. If you need to specify which environment variable in the config file and evaluate an interpolation still, check out this answer: evaluating a groovy string expression at runtime
Configuration file:
{
"actions": [ {
"operation": "create",
"args": [
{ "path": "%s\\trunk\\ABC" },
{ "path": "%s\\trunk\\XYZ" }
]
}, {
"operation": "delete",
"args": [
{ "path": "%s\\trunk\\ABC" },
{ "path": "%s\\trunk\\XYZ" }
]
}
] }
Pipeline code:
node('master') {
echo "${env.SVNRoot}" //String interpolation works here, giving the right value
stage('ReadConfig'){
cfg = readJSON file: 'Cfg.json'
}
stage('ExecuteConfigActions'){
cfg.fileActions.each() {
switch(it.operation) {
case 'create':
it.args.each() {
echo sprintf(it.path,env.SVNRoot)
}
break;
default:
break;
}
}
}
}

Highcharts: Plot the errorbars behind the datapoints

Is there a possibility to plot the errorbars in highcharts behind the actual lines/datapoints?
I am usually plotting the data and the errorbars with a for loop, therefore it would be convenient to set an attribute for the errorbars.
series: [
{% for key in dataset %}
{
name: '{{key}}',
data : {{ dataset[key].data}}
},
{
name: ' error',
type: 'errorbar',
data : {{ dataset[key].error}}
},
{% endfor %}
],
This can be controlled by the zIndex, like this:
series: [
{% for key in dataset %}
{
name: '{{key}}',
data : {{ dataset[key].data}},
zIndex: 2
},
{
name: ' error',
type: 'errorbar',
data : {{ dataset[key].error}},
zIndex: 1
},
{% endfor %}
]
API on series.zIndex: https://api.highcharts.com/highcharts/series.errorbar.zIndex
Define the visual z index of the series.
Defaults to undefined.
Working example: http://jsfiddle.net/ewolden/vrdmdzmz/1/

Listing unique data from liquid objects

I need to be able take a list of objects in liquid and display them on the page in a specific format.
If I have an array of objects (pages), I need to be able to print them in the following way:
list category names (page.category.name)
list each subcategory name with a list of pages under each subcategory name (page.subcategory.name and page.title)
Typically in ruby I would simply group the pages but I can't do that in liquid. The other thing I tried was to capture unique lists of categories and subcategories for pages but I couldn't find a way to get a unique list of items from an array. Any suggest help would be great.
I'm a little late to answer your question, but maybe this will help someone else struggling with the same problem. It's a bit hacky, as Liquid logic tends to be, but it works (at least for me, on Shopify).
Assuming you have a 'pages' array that looks like this:
pages = [
{ name: 'Page 1', category: { name: 'pants' } },
{ name: 'Page 2', category: { name: 'pants' } },
{ name: 'Page 3', category: { name: 'shoes' } },
{ name: 'Page 4', category: { name: 'shirts' } },
{ name: 'Page 5', category: { name: 'shoes' } }
]
This code will return only unique category names:
{% assign delimiter = "," %}
{% assign names_str = "" %}
{% assign names = pages | map: 'category' | map: 'name' %}
{% for name in names %}
{% assign names_arr = names_str | split: delimiter %}
{% unless names_arr contains name %}
{% assign names_str = names_str | append: delimiter | append: name %}
{% endunless %}
{% endfor %}
{% assign names_uniq = names_str | remove_first: delimiter | split: delimiter %}
Result:
names_uniq => [ 'pants', 'shoes', 'shirts' ]

Resources