Convert string to integer in Shopify Liquid? - type-conversion

I just read this related answer:
How can I convert a number to a string? - Shopify Design — Ecommerce University
To convert a string to a number just add 0 to the variable:
{% assign variablename = variablename | plus:0 %}
Not super elegant but it works!
Inelegant or not, the answer given there isn't working for me. What's the right way to do this?
Are the Liquid docs really missing such basic answers or am I just not finding the right place to look?

Using assign with a math filter is correct. See this thread on GitHub, and this blog post.
Variables created through {% capture %} are strings. When using assign, either of these options should give you a number:
{% assign var1 = var1 | plus: 0 %}
{% assign var2 = var2 | times: 1 %}
If this doesn't work for you, can you post the relevant code?

In Shopify Liquid programming language, you can convert a string to an integer using the to_i filter.
For example, if you have a variable string_number that contains a string representation of a number, you can convert it to an integer using the following code:
{{ string_number | to_i }}
It will convert the string to integer and you can use it in mathematical calculations, comparisons and other operations that work with integers.
For example, you could use the to_i filter to add two numbers together:
{% assign number_1 = "5" %}
{% assign number_2 = "2" %}
{% assign result = number_1 | to_i + number_2 | to_i %}
{{ result }}
This will output: 7
Please note that this filter will return 0 if the string is not a valid number.
Source

Related

go template split string by the second to last character

I am trying to split a string only by the second to last character, for example:
Having this string xxx-xxx-xxx-xxx-xxx
I would like to get only this xxx-xxx-xxx and remove the last part after the third "-" or the second last "-", the string will always have 4 "-" and character or numbers in between.
At the moment I have something like this
{{ splitList "-" .Values.global.stackName | list ._0 ._1 ._2 | join "-" | quote }}
Does not work because I dont know how to pipe the array from the first split int the second one and join them again.
You may use the slice function to get only the first 3 elements of the splitted list:
{{ slice (splitList "-" .Values.global.stackName) 0 3 | join "-" | quote }}
Also note that if your input is guaranteed to be of fixed format (that is, 3 characters then - then 3 chars again then - then 3 chars again before -), you may use printf with the proper format string to keep only the first (at most) 11 characters:
{{ printf "%.11s" .Values.global.stackName | quote }}
If the input only contains ASCII characters (no multi-byte unicode characters), you may also slice the input string to retain only the first 11 characters (bytes):
{{ slice .Values.global.stackName 0 11 | quote }}
I suspect the piece you're missing is the initial template function, which takes a list as a parameter and returns new list without its last item.
{{ splitList "-" .Values.global.stackName | initial | join "-" | quote }}
(splitList and join aren't included in the Helm Template Function List page. But they come from a support library called Sprig which is mostly embedded into Helm as-is, and they're documented in its String Slice Functions page.)

Helm - comma-separated list of dynamic strings

Is it possible, within a helm chart to create a single string which is a comma-separated representation (similar to using the ",".join() command in Python) of strings with a common prefix and a variable suffix?
For example, I have a CLI application that requires an argument like so via the extraArgs parameter in a kubernetes pod definition:
extraArgs: >-
-M {{ $.Values.global.hostname }}/100
I now have to modify this value to be over a range (i.e. from {{$.Values.global.minval}} to {{$.Values.global.maxval}}, inclusive). So, for a minval=100 and maxval=105, my chart needs to now become (note the lack of a trailing comma, and no spaces other than the space after -M):
extraArgs: >-
-M {{ $.Values.global.hostname }}/100,{{ $.Values.global.hostname }}/101,{{ $.Values.global.hostname }}/102,{{ $.Values.global.hostname }}/103,{{ $.Values.global.hostname }}/104,{{ $.Values.global.hostname }}/105
Is there some way I can execute this in a range/loop in my chart? I have several instances of this chart that will use different min/max values, and I'd like to automate this tedious task as much as I can (additionally, I do not have access to the app's source, so I can't change the CLI interface to the application).
In Python, I could accomplish this roughly by:
minval = 100
minval = 105
s = "-M "
L = []
for i in range(minval, maxval+1):
L.append("{{{{ $.Values.global.hostname }}}}/{}".format(i))
s = s + ",".join(L)
# print(s)
I'm not sure where to begin doing this in a Helm template beyond starting with the range() function.
Helm includes the sprig library of template functions which contains untilStep and join.
There is no concept of a map or each operator in sprig yet so you can construct the list in a range loop to be joined later (from here)
{{- $minval := int .Values.minval -}}
{{- $maxval := int .Values.maxval | add1 | int -}}
{{- $args := list -}}
{{- range untilStep $minval $maxval 1 -}}
{{- $args = printf "%s/%d" $hostname . | append $args -}}
{{- end }}
extraArgs: '-M {{ $args | join "," }}'

twig to tpl conversion of condition operator

{% set i = 0 %}
{% set i = i + 1 %}
{% if i % 2 == 0 %}
i am trying to change this set and i operator to change this code .
this is the twig file code . how can we write this code in tpl file .I am facing problem to solve condition operators like this specially f i % in above three codes . mean how can i convert this line in tpl exactly. i am converting opencart 3.0.2.0 theme into opencart 2.3.0.2 . i tired my best to understand how to change this code in tpl but could't manage to solve it . thanks
You can write above code in .tpl like this
<?php
$i = 0;
$i++;
if($i%2==0){}
?>

For Loop not working in Jinja/Flask

In jinja template my code is something like this, I m trying to get values from my MongoDB database
{% for a in output %}
{{ a.product_name }}
{% else %}
<p> No product found </p>
{% endfor %}
Some HTML CODE
{% for b in output %}
{{ b.product_name }}
{% endfor %}
The problem is first loop is working fine, but second loop not at all working. But when I write the second loop before first loop, then second loop work but then not first loop ( it going inside else and printing "No Product Found").
I am not able to understand this problem.
You want to iterate over the mongodb cursor twice. So after first iteration, you need to call the rewind method on the output (cursor) somewhere between the two loops.
output.rewind()
I am not sure if you would be able to do this in the Jinja template itself.
So the better option would be to convert the pymongo cursor object into a list itself, so you can iterate multiple times.
output_as_list = list(output)
Now you should be able to use output_as_list in your code the way you expected.
Looks like the output is an iterator. Try to convert it to a list (or dict) inside a view function.
You can reproduce such behaviour by the next code:
output = (x for x in range(3))
# output = list(output) # if uncomment this line, the problem will be fixed
for x in output: # this loop will print values
print(x)
for x in output: # this loop won't
print(x)
UPD: Since the output is a mongodb cursor, you can rewind it by calling output.rewind() directly in the template.
{% for a in output %}
{{ a.product_name }}
{% else %}
<p> No product found </p>
{% endfor %}
Some HTML CODE
{% set _stub = output.rewind() %} {# use a stub to suppress undesired output #}
{% for b in output %}
{{ b.product_name }}
{% endfor %}

Convert Ansible variable from Unicode to ASCII

I'm getting the output of a command on the remote system and storing it in a variable. It is then used to fill in a file template which gets placed on the system.
- name: Retrieve Initiator Name
command: /usr/sbin/iscsi-iname
register: iscsiname
- name: Setup InitiatorName File
template: src=initiatorname.iscsi.template dest=/etc/iscsi/initiatorname.iscsi
The initiatorname.iscsi.template file contains:
InitiatorName={{ iscsiname.stdout_lines }}
When I run it however, I get a file with the following:
InitiatorName=[u'iqn.2005-03.org.open-iscsi:2bb08ec8f94']
What I want:
InitiatorName=iqn.2005-03.org.open-iscsi:2bb08ec8f94
What am I doing wrong?
I realize I could write this to the file with an "echo "InitiatorName=$(/usr/sbin/iscsi-iname)" > /etc/iscsi/initiatorname.iscsi" but that seems like an un-Ansible way of doing it.
Thanks in advance.
FWIW, if you really do have an array:
[u'string1', u'string2', u'string3']
And you want your template/whatever result to be NOT:
ABC=[u'string1', u'string2', u'string3']
But you prefer:
ABC=["string1", "string2", "string3"]
Then, this will do the trick:
ABC=["{{ iscsiname.stdout_lines | list | join("\", \"") }}"]
(extra backslashes due to my code being in a string originally.)
Use a filter to avoid unicode strings:
InitiatorName = {{ iscsiname.stdout_lines | to_yaml }}
Ansible Playbook Filters
To avoid the 80 symbol limit of PyYAML, just use the to_json filter instead:
InitiatorName = {{ iscsiname.stdout_lines | to_yaml }}
In my case, I'd like to create a python array from a comma seperated list. So a,b,c should become ["a", "b", "c"]. But without the 'u' prefix because I need string comparisations (without special chars) from WebSpher. Since they seems not to have the same encoding, comparisation fails. For this reason, I can't simply use var.split(',').
Since the strings contains no special chars, I just use to_json in combination with map(trim). This fixes the problem that a, b would become "a", " b".
restartApps = {{ apps.split(',') | map('trim') | list | to_json }}
Since JSON also knows arrays, I get the same result than python would generate, but without the u prefix.