Using Handlebars Cookbook for example material...
Data:
{
"foo": {
"bar": {
"moo": "No"
}
},
"moo": "Yes!"
}
Template:
{{#foo.bar}}
{{../moo}}
{{/foo.bar}}
Expected Output:
Yes!
This just seems wrong to me, and I'm hoping someone can help me with the logic.
If Handlebars navigates context down the first lookup "foo.bar", the context inside the block should be bar, or {"moo":"No"}. In fact it seems to be. If I put {{moo}} in the block body I'd see "No" for output.
So it would seem logical that, ".." goes up 1 level to context foo, {"bar":{"moo","No"}}. There is no "moo" in the "foo" object. The logical/expected way to get "Yes!" would be to use {{../../moo}}, but that's not how it works.
What is the logic here?
I think I see. I'm assuming (wrongly) that Handlebars resolves each path component into a context: Context[foo] -> Context[bar]. That's not how it seems to work. Rather it creates Context[foo.bar]. So ".." from that is indeed root, so "../moo" is "Yes!".
It's not a path stack in the programming sense, but seemly rather a stack/history of block contexts.
Related
How do I create json path syntax\query that tries and find a child element, but if it can't find it falls back to the root element?
I've tried the following:
['$.form_response.definition'],$
'$.form_response.definition',$`
'$.form_response.definition','$'
'$.form_response.definition',`this`
['$.form_response.definition']|$
... (and probably a lot more that I've already forgotten about)
but unfortunately nothing seems to work correctly or it just throws errors.
I would expect that it will try and look for the form_response.definition element and it that can't be found, it will just return the root element.
Let's for example take the following piece of code. In one JSON the part I'm looking for is in the under response.definition, but in the other JSON the part I'm looking for is directly at the root.
from jsonpath_ng import parse
parse('$.response.definition, $').find({'id': '123', 'response': {'id': '987', 'definition': {'title': 'hi'}}})
result = parse('$.response.definition, $').find({ 'id': '123', 'title': 'hi'})
But running this gives the following error.
raise JsonPathParserError('Parse error at %s:%s near token %s (%s)'
% (t.lineno, t.col, t.value, t.type))
jsonpath_ng.exceptions.JsonPathParserError: Parse error at 1:23 near token $ ($)
I've tried so many things by now. Is there a way to do this?
I am in Terraform 14 and I am trying to add labels to my template file which should generate a YAML:
Template File:
labels:
${labels}
Code:
locals {
labels = merge(
var.labels,
map(
"module", basename(abspath(path.module)),
"module_version", var.module_version
)
)
prometheus_config = templatefile("${path.module}/prometheus.tmpl", {
labels = indent(8, yamlencode(local.labels))
})
When I try to add the labels indenting with 8 this outputs in the template file causing YAML errors:
Error Output:
labels:
"module": "my_module"
"module_version": "1.0"
As you can see the module_version has indent 8 which is correct but the module line is not indented.
I tried many things like moving ${labels} everywhere in the beginning, with multiple indentations but nothing seems to work.
It is for this reason that the templatefile documentation recommends using yamlencode for the entire data structure, rather than trying to concantenate bits of YAML together using just string templates. That way the yamlencode function can guarantee you a correctly-formatted result and you only have to produce a suitable data structure:
In your case, that would involve replacing the template contents with the following:
${yamlencode({
labels = labels
})}
...and then replacing the prometheus_config definition with the following:
locals {
prometheus_config = templatefile("${path.module}/prometheus.tmpl", {
labels = local.labels
})
}
Notice that the yamlencode call is now inside the template, and it covers the entire YAML document rather than just a fragment of it.
With a simple test configuration I put together with some hard-coded values for the variables you didn't show, I got the following value for local.prometheus_config:
"labels":
"module": "example"
"module_version": "1.0"
If this was a full example of the YAML you are aiming to generate then I might also consider simplifying but just inlining the yamlencode call directly inside the local value definition, and not have the separate template file at all:
locals {
prometheus_config = yamlencode({
labels = local.labels
})
}
If the real YAML is much larger or is likely to grow larger later then I'd probably still keep that templatefile call, but I just wanted to note this for completeness, since there's more than one way to get this done.
So using terraform 14 I was not able to transform lists or maps into yaml with yamlencode. Every option I tried using the suggested answer produced results with the wrong indentation. Maybe due to the many indentation levels in the file... I am not sure. So I dropped the use of yamlencode in the solution.
Solution:
I decided to use inline solution so for lists I transform then with string with join and for maps I use jsonencode so:
# var.list is a list in terraform
# local.abels is a map in terraform
thanos_config = templatefile("${path.module}/thanos.tmpl", {
urls = join(",", var.list),
labels = jsonencode(local.labels)
})
The resulting plan output is a bit ugly but it works.
I'm block into something silly.
I want to call another snippet into one snippet on Wordpress. This is the idea :
[ snippet01 param=[snippet02 param="awesomeParameter"]]
Badly, that is not working out of the box. I've trying with another bracket like "{", but this is also not working.
Do you have an answer ?
Thanks in advance,
Here is another approach for your case:
Instead of [ snippet01 param=[snippet02 param="awesomeParameter"]]
you can use this format:
[ snippet01 param="subsnippet-snippet02,param,awesomeParameter"]
Then easily parse and use it inside first shortcode:
function first_shortcode_function($args){
if (strpos($args["param"],"subsnippet-")===0){
$parts=explode("-",$args["param"]);
$snippe2_final=explode(",",$parts[1]);
do_shortcode("[".$snippe2_final[0]." ".$snippe2_final[1]."=".$snippe2_final[2]."]");
}
}
I'm trying to populate a list with a dataset and set the selected option with a helper function that compares the current data with another object's data (the 2 objects are linked)
I made the same type of list population with static variables:
Jade-
select(name='status')
option(value='Newly Acquired' selected='{{isCurrentState "Newly Acquired"}}') Newly Acquired
option(value='Currently In Use' selected='{{isCurrentState "Currently In Use"}}') Currently In Use
option(value='Not In Use' selected='{{isCurrentState "Not In Use"}}') Not In Use
option(value='In Storage' selected='{{isCurrentState "In Storage"}}') In Storage
Coffeescript-
"isCurrentState" : (state) ->
return #status == state
This uses a helper isCurrentState to match a given parameter to the same object that my other code is linked to so I know that part works
The code I'm trying to get to work is :
Jade-
select.loca(name='location')
each locations
option(value='#{siteName}' selected='{{isCurrentLocation {{siteName}} }}') #{siteName}
Coffeescript-
"isCurrentLocation": (location) ->
return #locate == location
All the other parts are functioning 100%, but the selected part is not
I've also tried changing the way I entered the selected='' part in a manner of ways such as:
selected='{{isCurrentLocation "#{siteName}" }}'
selected='{{isCurrentLocation "#{siteName} }}'
selected='{{isCurrentLocation {{siteName}} }}'
selected='#{isCurrentLocation "{{siteName}}" }'
selected='#{isCurrentLocation {{siteName}} }'
selected='#{isCurrentLocation #{siteName} }'
Is what I'm trying to do even possible?
Is there a better way of achieving this?
Any help would be greatly appreciated
UPDATE:
Thanks #david-weldon for the quick reply, i've tried this out a bit and realised that I wasn't exactly clear in what I was trying to accomplish in my question.
I have a template "update_building" created with a parameter( a buidling object) with a number of attributes, one of which is "locate".
Locations is another object with a number of attributes as well, one of which is "siteName". One of the siteName == locate and thus i need to pass in the siteName from locations to match it to the current building's locate attribute
Though it doesn't work in the context I want to use it definitely pointed me in a direction I didn't think of. I am looking into moving the parent template(The building) date context as a parameter into the locations template and using it from within the locations template. This is easily fixable in normal HTML spacebars with:
{{>locations parentDataContext/variable}}
Something like that in jade would easily solve this
Short answer
selected='{{isCurrentLocation siteName}}'
Long answer
You don't really need to pass the current location because the helper should know it's own context. Here's a simple (tested) example:
jade
template(name='myTemplate')
select.location(name='location')
each locations
option(value=this selected=isCurrentLocation) #{this}
coffee
LOCATIONS = [
'Newly Acquired'
'Currently In Use'
'Not In Use'
'In Storage'
]
Template.myTemplate.helpers
locations: LOCATIONS
isCurrentLocation: ->
#toString() is Template.instance().location.get()
Template.myTemplate.onCreated ->
#location = new ReactiveVar LOCATIONS[1]
I looked into the datacontexts some more and ended up making the options that populate the select into a different template and giving that template a helper, accessing the template's parent's data context and using that to determine which location the building had saved in it so that I could set that option to selected
Jade-
template(name="location_building_option")
option(value='#{siteName}' selected='{{isSelected}}') #{siteName}
Coffeescript -
Template.location_building_option.helpers
'isSelected': ->
parent = Template.parentData(1)
buildSite = parent.locate
return #siteName == buildSite
Thanks #david-weldon, Your answer helped me immensely to head in the right direction
So this is my .pro file content (AMZI PROLOG) :
room(kitchen).
room(office).
room(hall).
room('dining room').
room(cellar).
door(office, hall).
door(kitchen, office).
door(hall, 'dining room').
door(kitchen, cellar).
door('dining room', kitchen).
location(desk,office).
location(apple,kitchen).
location(flashlight,desk).
location('washing machine',cellar).
location(nani,'washing machine').
location(broccoli,kitchen).
location(crackers,kitchen).
location(computer,office).
location(envelope,desk).
location(stamp,envelope).
location(key,envelope).
edible(apple).
edible(crackers).
tastes_yucky(broccoli).
here(kitchen).
is_located_in(T1,T2):-location(X,T2),is_located_in(T1,X).
What I want to achieve is that if I use, for example, is_located_in(X,office), then the result will be :
X=desk,
X=flashlight,
X=computer,
X=envelope,
X=stamp,
X=key,
no
(in no particular order).
That way, the result will include things that basically located in / on the object in the office, instead of things that located directly in the office.
This is the source : http://www.amzi.com/AdventureInProlog/a8recurs.php
There is stated that the code are fine, but when I test it, it just returned :
no
Please help. Thanks.
Try this (in this order):
is_located_in(T1,T2):-location(T1,T2).
is_located_in(T1,T2):-location(X,T2),is_located_in(T1,X).