Dynamic Repeated Use of Same Snippet With Different Variables

I've figured out how to do something that's been bugging me for a while, and I thought I'd post it here for others to use or comment on -- is there a better way I could be doing this?

The problem I'm solving here is reusing (by importing) the same snippet repeatedly within another snippet, but each time with different "variables" set and used within the imported snippet. I have a few use cases for this, but in particular is the snippet I use for inserting links. Depending on the context, I need for links to be displayed differently; e.g. in an email, it needs to be a regular HTML link, but on reddit, I need for it to be in markdown format, etc.

First, some necessary contextual info: the following "/blaze_format" snippet sets the text/reddit/markup format and is imported at the top of most of my snippets; it automatically detects the reddit and facebook domains and chooses the correct format accordingly, elsewise it gives a dropdown to select it manually:

{note}{if:{site:domain}=="www.reddit.com"}{format="reddit"}{elseif:{site:domain}=="www.facebook.com"}{format="markup"}{else}{formmenu: name=format;default=text;reddit;markup}{endif}{endnote: trim=yes}

With that in place (in the "parent" snippet), then this "/blaze_link" snippet can generate a link based on the selected "format"; this snippet also depends on the "blaze_url" keyed list variable having been assigned before it's invoked, with the "url" and "title" keys set on it:

{if: format == "text"}{link: {=blaze_url["url"]}}{=blaze_url["title"]}{endlink}{elseif: format == "reddit"}{=blaze_url["title"]}{elseif: format == "markup"}{=blaze_url["title"]} (ref: {=blaze_url["url"]}){endif}

Now, one might think that you could import and use this snippet like this:

{import:/blaze_format}
One link: {blaze_url=["url"="https://linkone.com", "title"="Link One"]}{import:/blaze_link}
Another link: {blaze_url=["url"="https://linktwo.com", "title"="Link Two"]}{import:/blaze_link}

However, this results in two identical links, both of them to Link Two. This is because TextBlaze markup isn't evaluated in a serial fashion, but rather makes several passes; first all the variables are set, then the code using those variables are executed. Later settings of variables override previous ones, so the last-most setting of the "blaze_url" variable is used for all invocations of the imported "/blaze_link" snippet.

Getting around this requires that we get the "import" of the "/blaze_link" snippet to execute within its own scope. AFAIK, the only way to do that with the currently available TextBlaze function is by using the "repeat" function, which can be done like this:

{import:/blaze_format}
One link: {repeat: 1}{blaze_url=["url"="https://linkone.com", "title"="Link One"]}{import:/blaze_link}{endrepeat}
Another link: {repeat: 1}{blaze_url=["url"="https://linktwo.com", "title"="Link Two"]}{import:/blaze_link}{endrepeat}

This places each of the imports of "/blaze_link" in its own scope separate from the overall snippet execution, and results in a link to Link One and to Link Two.

Pretty cool, eh? With this in hand, I can now write snippets like the following, and it will work regardless of context:

{import:/blaze_format}I once visited the page at {repeat: 1}{blaze_url=["url"="https://linkone.com", "title"="Link One"]}{import:/blaze_link}{endrepeat}, but got board and tried out {repeat: 1}{blaze_url=["url"="https://linktwo.com", "title"="Link Two"]}{import:/blaze_link}{endrepeat} before deciding that I like {repeat: 1}{blaze_url=["url"="https://linkthree.com", "title"="Link Three"]}{import:/blaze_link}{endrepeat} the best.

But again, if there's a better way to achieve this result, I'd love to know it.

Of note, my actual implementation of the "/blaze_link" snippet is slightly more complicated, and looks like this:

{isemail=testregex(blaze_url["url"], "([-!#-'+/-9=?A-Z^-~]+(\.[-!#-'+/-9=?A-Z^-~]+)*|"([]!#-[^-~ \t]|(\\[\t -~]))+")@0-9A-Za-z?(\.0-9A-Za-z?)+", "i")}{bold={=catch(blaze_url["bold"], {="no" if format == "markup" else "yes"})}}{italic={=catch(blaze_url["italic"], "no")}}{variant={=catch(blaze_url["variant"], "paren")}}{bracket={=catch(blaze_url["bracket"], "paren")}}{suffix={=catch(concat(" ", blaze_url["suffix"]), "")}}{if: format == "text"}{if: isemail == "yes"}{=catch(concat(blaze_url["title"], ": "), "")}{=blaze_url["url"]}{else}{link: {=blaze_url["url"]}}{repeat: 1}{blaze_markup=["text"={=blaze_url["title"]}, "italic"={=italic}, "bold"={=bold}]}{import:/blaze_markup}{endrepeat}{endlink}{endif}{elseif: format == "reddit"}[{repeat: 1}{blaze_markup=["text"={=catch(blaze_url["title"], blaze_url["url"])}, "italic"={=italic}, "bold"={=bold}]}{import:/blaze_markup}{endrepeat}]({if: isemail == "yes"}mailto:{endif}{=blaze_url["url"]}){elseif: format == "markup"}{if: isemail == "yes"}{=catch(concat(blaze_url["title"], ": "), "")}{=blaze_url["url"]}{else}{if: variant=="colon"}{title=concat({=blaze_url["title"]}, {=suffix})}{suffix=""}{else}{title={=blaze_url["title"]}}{endif}{url_href={=extractregex(blaze_url["url"], "https?://w?w?w?[.]?(.+)")}}{repeat: 1}{blaze_markup=["text"={=title}, "italic"={=italic}, "bold"={=bold}]}{import:/blaze_markup}{endrepeat}{if: variant == "paren"} {if: bracket == "paren"}({else}[{endif}ref: {else}: {endif}{=url_href}{if: variant == "paren"}{if: bracket == "paren"}){else}]{endif}{endif}{endif}{endif}{=suffix}

This provides the "variant" and "bracket" options, allowing me to change the format for "markup" style formatted links; e.g.

{import:/blaze_format}
{repeat: 1}{blaze_url=["url"="https://emanaton.com", "title"="Emanaton Dot Com", "bracket"="square"]}{import:/blaze_link}{endrepeat}
{repeat: 1}{blaze_url=["url"="https://csmaccath.com", "title"="CSMacCath Dot Com", "variant"="colon"]}{import:/blaze_link}{endrepeat}
{repeat: 1}{blaze_url=["url"="https://www.youtube.com/watch?v=3HAMk_ZYO7g", "title"="This video", "variant"="colon", "suffix"="addresses that question nicely"]}{import:/blaze_link}{endrepeat}{if: format <> "markup"}.{endif}

Which outputs links like so (when "markup" is selected):
Emanaton Dot Com [ref: https://emanaton.com]
CSMacCath Dot Com: https://csmaccath.com
This video addresses that question nicely: youtube.com/watch?v=3HAMk_ZYO7g

2 Likes

Awesome Sean! Nice use of {repeat} to create a separate scope.

It's not available yet, but long term we expect your use case to be solved well by command packs (see, February Development Update). These are in an early stage currently and for now TB users can use but not develop them. Longer term though we want to open them up command pack development to everyone.

Technically, command pack commands are like a more powerful {import}. Each command pack command is just a snippet but it has its own scope and there is a well-defined interface to configure them and pass variables between the command and the enclosing snippet.

2 Likes

YES! This will be brilliant, and I look forward to them -- thanks for letting me know, @scott!

1 Like

@Sean_P_O_MacCath-Mor On the off-chance you notice an update on such an old thread, I wanted to thank you for taking the time to explain this in so much detail. I'm struggling to completely implement it as I'm new to Text Blaze and not a programmer, but it's shown me what could be possible as I progress through the knowledge curve.

@everyone: Is this still the only way of achieving this as I don't see any command packs for this and the thread is 3 years old? I was expecting that Text Blaze would have a format function I could access for use on Markup sites, not that we'd need to write our own :upside_down_face:

@Sandie - cam you tell me a bit more about what you're trying to achieve? Maybe there's a more straightforward solution.

OH - sorry @Sandie -- I just now noticed this.

For my part, I need to have bold and italics show up differently based on context; e.g. as markdown in reddit, or html in emails, or with CAPS or *stars around* in facebook. I accomplish this much as I have above with scoped instances of inclusions. I have a /blaze_markup snipped with the following (noting that this depends on the previously mentioned /blaze_format being included in the parent snippet):

{bold={=catch(blaze_markup["bold"], "no")}}{uppercase={=catch(blaze_markup["uppercase"], "yes")}}{italic={=catch(blaze_markup["italic"], "no")}}{if: format == "text"}{if: bold=="yes"}{if: italic=="yes"}{=blaze_markup["text"]}{else}{=blaze_markup["text"]}{endif}{elseif: italic}{=blaze_markup["text"]}{else}{=blaze_markup["text"]}{endif}{elseif: format == "reddit"}{if: bold}{if: italic}{=blaze_markup["text"]}{else}{=blaze_markup["text"]}{endif}{elseif: italic}{=blaze_markup["text"]}{else}{=blaze_markup["text"]}{endif}{elseif: format == "markup"}{blaze_text={=blaze_markup["text"]}}{if: uppercase=="yes"}{blaze_text={=upper(blaze_text)}}{endif}{if: bold}{if: italic}{=blaze_text}{else}{=blaze_text}{endif}{elseif: italic and len({=blaze_markup["text"]}) < 50}{=blaze_markup["text"]}{else}{=blaze_markup["text"]}{endif}{endif}

Which I call:

I love {repeat: 1}{blaze_markup=["text"="today", "italic"="yes"]}{import:/blaze_markup}{endrepeat} {repeat: 1}{blaze_markup=["text"="even more", "bold"="yes"]}{import:/blaze_markup}{endrepeat} than {repeat: 1}{blaze_markup=["yesterday"="even more", "italic"="yes"]}{import:/blaze_markup}{endrepeat}.

If that doesn't make sense, let me know and we can work on simplifying it down to your needs?

@Sean_P_O_MacCath-Mor - you could use the {site:domain} command together with an {if} command.

{if: contains({site:domain}, "facebook.com")}Insert the facebook formatting commands here
{elseif: contains({site:domain}, "othersite.com")}Insert the other site formatting commands here
{else}Formatting for regular text
{endif}

Let me know if anything is unclear :slight_smile:

Thanks for the note, @Cedric_Debono_Blaze! However, you can see in my OP here that I'm using
{site:domain} to check for that. The problem with using {site:url} is that it evaluates the entire URL of the page, which exposes possible misfires in the edge case that one of the checked for domains exists in that URL; e.g. https://example.com/posting-on-facebook.com.

Am I incorrect on this?

You are correct Sean. {site: domain} is better here than {site:url} for the reason you point out.

@Sean_P_O_MacCath-Mor - thanks for the observation. I've updated my response accordingly.