Crystal lang: call macro in macro? - crystal-lang

I wonder a way to call a macro in another macro.
Like this:
macro parse(str)
{{ str.split "/" }}
end
macro do_sth(path)
{% pathes = parse path %}
{% for file in pathes %}
p {{file}}
{% end %}
end
do_sth "aa/bb/cc"
The code in parse may be really complicated.
The example code fails to compile with message undefined macro method: 'parse'.

As Vlad Faust said, it's may still not possible. Finally, I adopt some trick like Jonne Haß.
macro macro_return(*vals, &block)
\{% begin %}
\{%
{% for arg, ind in block.args %}
{{arg}} = {{vals[ind]}}
{% end %}
%}
{{ block.body }}
\{% end %}
end
macro parse(str, &block)
macro_return {{ str.split "/" }} {{block}}
end
macro do_sth(path)
parse({{path}}) do |pathes|
\{% for a in pathes %}
p \{{a}}
\{% end %}
end
end
do_sth "aa/bb/cc"
Hoping the native support.

It's impossible right now. You should not put a macro call inside another macro. If you really need to extract a compile-time functionality in an outer call, I'd suggest you to experiment with run - it puts the raw output right into the code.

Related

Django Template: Dynamic template variable inside another variable

I hope this makes sense... I am building a crypto asset list page (easy); however, in the {% for %} loop I would like to include a variable inside a variable. Showing the code will make more sense:
Tempalte.html
{% for crypto_asset in objects__list_cryptoAssets %}
<tr role="row" class="body-row">
<td role="cell">{{ api_external_prices.bitcoin.usd }}</td>
</tr>
{% endfor %}
So the {% for %} loop grabs all the crypto assets and then I can use Django template {{ asset_class.slug }} to grab all slugs... nothing exceptional here. This variable {{ api_external_prices.bitcoin.usd }} grabs external USD prices for Bitcoin, {{ api_external_prices.bitcoin.eur }} prices in EUR, and so forth... nothing exceptional here either.
Here is where the question comes :: the idea would be to have something like {{ api_external_prices.{{ asset_class.slug }}.usd }}... so each crypto would have its own price FX fetched correctly. Is it possible to have a variable inside a variable?
They are several ways you can implement this:
Template filters
You can create a template filter api_external_prices that takes asset_class and the crypto type as parameters and returns the value.
The syntax would be something link this, where api_external_prices is the name of the template filter:
{{ asset_class|api_external_prices:"usd" }}
See here for more info about this feature: https://docs.djangoproject.com/en/4.0/howto/custom-template-tags/#writing-custom-template-filters
Methods
Another approach would be to have api_external_prices as method on your asset_class object, which returns an object that has a usd property. api_external_prices here can just be a wrapper that calls a central module/function, but this would make it much easier to use it in templates.
{{ asset_class.api_external_prices.usd }}
The first approach is similar to what you are asking, but personally I would prefer to use the 2nd approach, because it saves you from introducing as template filter.

Use function in Django Include Tag?

I'm trying to pass a value into a template via an include tab, like so:
{% include "shared/page_title.html" with text=local_time_format(job.date, user.timezone, "M j P") %}
So basically, i want the text value to be the result of calling local_time_format (a filter function) with job.date (context object value) and a user property and the final argument.
Getting Could not parse the remainder error-- how to fix?
You can prep values for an include like so:
{% with text=today|date:"D d M Y" %}
{% include "shared/page\_title.html" with text=text%}
{% endwith %}

Is it possible for a Crystal macro to determine if it's being called inside a block?

Is it possible for a Crystal macro to determine if it is rendering inside a block vs. outside of it?
macro my_macro
{% if inside_a_block? %}
break if do_something
{% else %}
return if do_something
{% end %}
end
my_func do
my_macro
end
class A
def a
my_macro
end
end

How to remove line break after a tag

I use Django template system to do code generation (not only for HTML). I'm somehow troubled by redundant line breaks in django templates.
Here is an example. The template is as below:
// something
{% for element in elements %}
Element: {{ element.name }},
{% endfor %}
// something else
The rendered output will be:
// something
Element: foo
Element: bar
// something else
Expected rendered output should be:
// something
Element: foo
Element: bar
// something else
After googled a bit, I know I can use {% spaceless %} to remove any white spaces in rendered output. It is quite useful for HTML, but will not work for other languages. My current solution is to add a special string after a tag and replace them with empty string in output.
Is there any better solution to remove line break after a tag?
For your production environment you might consider minifying your html to get that little bit more performance. For example using https://pypi.python.org/pypi/django-htmlmin.
If you are only interested in the esthetics, then the .strip function as noted by e-nouri is probably your best answer.
You can use .strip on your attributes to strip/trim.
// something
{% for element in elements %}
Element: {{ element.name.strip }},
{% endfor %}
// something else
The line breaks in code shouldn't matter, but you can avoid them when you put everything in one line, which doesn't look that good anymore:
{% for element in elements %}Element: {{ element.name.strip }},{% endfor %}

if... !true conditional rendering in nunjucks

if...true conditionals work like a charm as outlined here in the docs.
but if I try to do something like:
{% if !posts.length %}
<i>No project posts yet!</i>
{% endif %}
I get an error:
Template render error: (/home/nak/clones/mf3/views/project.html) [Line 10, Column 9]
unexpected token: !
I've worked around this by doing:
{% if posts.length %}
{% else %}
<i>No project posts yet!</i>
{% endif %}
Is there a better (correct) way to do this?
I see you've got a bit of a bobby dazzler here.
Try using not instead of !.
In other words, use not, not !!
Give 'er a go mate and notice that in the raw section here they highlight not as if it's a keyword.
https://mozilla.github.io/nunjucks/templating.html#raw
Best of luck to ye.
You can use the syntax:
<% '' if posts.length else 'No project posts yet!' %>
https://mozilla.github.io/nunjucks/templating.html#if-expression