YAML - Assigning alias to anchor alternatives - yaml

In YAML, we are not allowed to assign an alias to an anchor. How can I acheieve similar functionality so that I can use one generic key throughout the YAML file while only needing to make an update in one location?
t_shirt_sizes:
&t_shirt_xs EXTRA_SMALL
&t_shirt_sm SMALL
&t_shirt_md MEDIUM
&t_shirt_lg LARGE
&t_shirt_xl EXTRA_LARGE
t_shirt:
&t_shirt_size *t_shirt_md
# Use the *t_shirt_size further down the YAML file
store:
order_shirt_sizes: *t_shirt_size

This is possible:
t_shirt:
&t_shirt_size EXTRA_SMALL
It fulfils your requirement to only need a single change to change the size everywhere. If you need the indirection, the closest thing you can do is
t_shirt:
&t_shirt_size [ *t_shirt_md ]
Then you'd need to handle the size value as 1-value sequence during loading.
YAML serializes a graph of directed nodes. Using an alias makes another connection to the referenced node, therefore does not create a new node and thus it cannot be anchored. The purpose of anchors & aliases is to be able to serialize cyclic graphs.

Related

Selection script for maya

I'm noob in script but good in animation, I need some help to create a script selection.
I found an exemple :
import maya.cmds as cmds
# Get selected objects
curSel = maya.cmds.ls(sl=True)
# Or, you can also specify a type in the listRelatives command
nurbsNodes = maya.cmds.listRelatives(curSel, allDescendents=True, noIntermediate=True, fullPath=True, type="nurbsCurve", path=True)
cmds.select(nurbsNodes)
But It doesn't select all the character's controlers...
I would like If I select a character controler curve or locator and I run the script, the result is all controls who can be keyed should be selected. Without the referenced character name.
Thanks a lot for the one who can help
Currently the listRelatives command is being used to list all child nodes under the currently selected transforms, whose type is a NURBS Curve, e.g. type="nurbsCurve". Typically all nodes in Maya inherit from some other node type (It's worth checking the nodes in Maya help -> technical documents ->nodes). Luckily locator nodes and curves both inherit from 'geometryShape', so you should be able to replace "nurbsCurve" with "geometryShape", and that will probably get you most of the way there. You may need to ignore certain returned nodes though - i.e. polygonal meshes you are using for rendering.

How to Reference an aliased map value in YAML

I have a feeling this isn't possible, but I have a snippet of YAML that looks like the following:
.map_values: &my_map
a: 'D'
b: 'E'
a: 'F'
section:
stage: *my_map['b']
I would like stage to have the value of E.
Is this possible within YAML? I've tried just about every incarnation of substitution I can think of.
Since there is a duplicate key in your mapping, which is not allowed
in YAML 1.2 (and should at least throw a warning in YAML 1.1) this is
not going to work, but even if you correct that, you can't do that
with just anchors and aliases.
The only substitution like replacement that is available in YAML is the "Merge Key Language-Independent Type". That is indirectly referenced in the YAML spec, and not included in it, but available in most parsers.
The only thing that allows it to do is "update" a mapping with key value pairs of one or more other mappings, if the key doesn't already exist in the mapping. You use the special key << for that, which takes an alias, or a list of aliases.
There is no facility, specified in the YAML specification, to dereference particular keys.
There are some systems that use templates that generate YAML, but there are two main problems to apply these here:
the template languages themselves often are clashing with the indicators in the YAML syntax,
making the template not valid YAML
even if the template could be loaded as valid YAML, and the values extracted that are needed to
update other parts of the template, you would need to parse the input twice (once to get the
values to update the template, then to parse the updated template). Given the potential
complexity of YAML and the relative slow speed of its parsers, this can be prohibitive
What you can do is create some tag (e.g. !lookup) and have its constructor interpret that node.
Since the node has to be valid YAML again you have to decide on whether to use a sequence or a mapping.
You'll have to include some special syntax for the values in both cases, and also for the key
(like the << used in merges) in the case of mappings.
In the examples I left out the spurious single quotes, depending on
your real values you might of course need them.
Example using sequence :
.map_values: &my_map
a: D
b: E
c: F
section: !Lookup
- *my_map
- stage: <b>
Example using mapping:
.map_values: &my_map
a: D
b: E
c: F
section: !Lookup
<<: *my_map
stage: <b>
Both can be made to construct the data on the fly (i.e. no past
loading processing of your data structure necessary). E.g. using Python and
the sequence "style" in input.yaml:
import sys
import ruamel.yaml
from pathlib import Path
input = Path('input.yaml')
yaml = ruamel.yaml.YAML(typ='safe')
yaml.default_flow_style = False
#yaml.register_class
class Lookup:
#classmethod
def from_yaml(cls, constructor, node):
"""
this expects a two entry sequence, in which the first is a mapping X, typically using
an alias
the second entry should be an mapping, for which the values which have the form <key>
are looked up in X
non-existing keys will throw an error during loading.
"""
X, res = constructor.construct_sequence(node, deep=True)
yield res
for key, value in res.items():
try:
if value.startswith('<') and value.endswith('>'):
res[key] = X[value[1:-1]]
except AttributeError:
pass
return res
data = yaml.load(input)
yaml.dump(data, sys.stdout)
which gives:
.map_values:
a: D
b: E
c: F
section:
stage: E
There are a few things to note:
using <...> is arbitrary, you don't need a both beginning and an
end marker. I do recommend using some character(s) that has no
special meaning in YAML, so you don't need to quote your values. You can e.g. use some
well recognisable unicode point, but they tend to be a pain to type in an editor.
when from_yaml is called, the anchor is not yet fully constructed. So X is an empty dict
that gets filled later on. The constructed with yield implements a two step process: we first
give back res "as-is" back to the constructor, then later update it. The constructor stage of
the loader knows how to handle this automatically when it gets the generator instead a "normal" value.
the try .. except is there to handle mapping values that are not strings (i.e. numbers, dates, boolean).
you can do substitutions in keys as well, just make sure you delete the old key
Since tags are standard YAML, the above should be doable one way or another in any
YAML parser, independent of the language.

Correlating multiple dynamic values

How can I get the value of important id and ValueType?
I have tried using web_save_param_regexp (but unfortunately I don't fully understand how the function works).
I have also tried using web_save_param (with the help of offset and length).
unfortunately once again I cannot get the accurate value some values change in length specially when the total amount values dynamically changes per run.
<important id=\"insertsomevalueshere\" record=\"1\" nucTotal=\"NUC609.40\"><total amount=\"68.75\" currency=\"USD\"/><total amount=\"609.40\" currency=\"USD\"/><out avgsomecost=\"540.65\" ValueType=\"insertsomevalueshere\" containsawesomeness=\"1\" Score=\"-97961\" somedatatype=\"1\" typeofData=\"VAL\" web=\"1\">
Put these lines of code before the line of code which does your web request:
web_reg_save_param_regexp("ParamName=importantid","Regexp=<important id=\\\"(.*?)\\\"",LAST);
web_reg_save_param_regexp("ParamName=ValueType","Regexp= ValueType=\\\"(.*?)\\\"",LAST);
You will then have two stored parameters 'importantid' and 'ValueType'
Dynamic number of elements to correlate? Your path for resubmission is through web_custom_request(). You will need to build the string you need dynamically with the name:value pairs for all of the data which needs to be included.
This path will place a premium on your string manipulation skills in the language of the tool. The default path is through C, but you have other language options if your skills are more refined in another language.

SNMP OID with non-unique node names

I am writing an extension to my companies existing SNMP MIB. I have a whole list of objects, with the same properties on each. I want to be able to get and set these through SNMP.
So for example, consider my object has name, desc, arg0, arg1. What I want is to be able to refer to these as:
fullpath.objects.ObjectA.name
fullpath.objects.ObjectA.desc
fullpath.objects.ObjectA.arg0
fullpath.objects.ObjectB.name
fullpath.objects.ObjectB.desc
fullpath.objects.ObjectB.arg0
However the leaf nodes appear to have to have unique names, so I am unable to define this.
I can use a SNMP table to produce:
fullpath.objects.table.name.1
fullpath.objects.table.desc.1
fullpath.objects.table.arg0.1
fullpath.objects.table.name.2
fullpath.objects.table.desc.2
fullpath.objects.table.arg0.2
But there is nowhere to look up that 2 means ObjectB. This leaves it open to user error looking up the wrong value and setting the wrong thing.
At the moment the best solution I can see is:
fullpath.objects.ObjectAName
fullpath.objects.ObjectADesc
fullpath.objects.ObjectAArg0
fullpath.objects.ObjectBName
fullpath.objects.ObjectBDesc
fullpath.objects.ObjectBArg0
which involves defining name for every object (there are 20 or so of them). The set of objects is fixed, so this is ok...just not very tidy.
Is there some way to define names for index in the table?
Is there some way of defining a container type?
Is there some way of allowing leaf nodes to be non-unique?
Any other ideas?
You should definitely use SNMP tables to accomplish what is required. This is the only way.
MIB Object names must be unique within entire MIB file.
You can easily use object of OCTET STRING type as Table index. So each byte/symbol/char of OCTET STRING value will be translated to corresponding numeric ASCII code in OID.
I ended up just using a naming convention and adding each of the settings directly into the MIB.
Not really the answer I wanted, but it means that all of the settings show up in the MIB, and that reduces the chance of users setting the wrong setting.

Is there a way to alias/anchor an array in YAML?

I'm using Jammit to package assets up for a Rails application and I have a few asset files that I'd like to be included in each of a few groups. For example, I'd like Sammy and its plugins to be in both my mobile and screen JS packages.
I've tried this:
sammy: &SAMMY
- public/javascripts/vendor/sammy.js
- public/javascripts/vendor/sammy*.js
mobile:
<<: *SAMMY
- public/javascripts/something_else.js
and this:
mobile:
- *SAMMY
but both put the Sammy JS files in a nested Array, which Jammit can't understand. Is there a syntax for including the elements of an Array directly in another Array?
NB: I realize that in this case there are only two elements in the SAMMY Array, so it wouldn't be too bad to give each an alias and reference both in each package. That's fine for this case, but quickly gets unmaintainable when there are five or ten elements that have a specific load order.
Closest solution I know of is this one:
sammy:
- &SAMMY1
public/javascripts/vendor/sammy.js
- &SAMMY2
public/javascripts/vendor/sammy*.js
mobile:
- *SAMMY1
- *SAMMY2
- public/javascripts/something_else.js
Alternatively, as already suggested, flatten the nested lists in a code snippet.
Note: according to yaml-online-parser, your first suggestion is not a valid use of << (used to merge keys from two dictionaries. The anchor then has to point to another dictionary I believe.
If you want mobile to be equal to sammy, you can just do:
mobile: *SAMMY
However if you want mobile to contain other elements in addition to those in sammy, there's no way to do that in YAML to the best of my knowledge.
Your example is valid YAML (a convenient place to check is YPaste), but it's not defined what the merge does. Per the spec, a merge key can have a value:
A mapping, in which case it's merged into the parent mapping.
A sequence of mappings, in which case each is merged, one-by-one, into the parent mapping.
There's no way of merging sequences on YAML level.
You can, however, do this in code. Using the YAML from your second idea:
mobile:
- *SAMMY
you'll get nested sequences - so flatten them! Assuming you have a mapping of such nested sequences:
data = YAML::load(File.open('test.yaml'))
data.each_pair { |key, value| value.flatten! }
(Of course, if you have a more complicated YAML file, and you don't want every sequence flattened (or they're not all sequences), you'll have to do some filtering.)
This solution is for Symfony/PHP only (considerations for other languages, see below)
Note about array keys from the PHP array manual page:
Strings containing valid decimal ints, unless the number is preceded by a + sign, will be cast to the int type. E.g. the key "8" will actually be stored under 8. [...]
This means that if you actually index your anchor array with integer keys, you can simply add new keys by continuing the initial list. So your solution would look like this:
sammy: &SAMMY
1: public/javascripts/vendor/sammy.js
2: public/javascripts/vendor/sammy*.js
mobile:
<<: *SAMMY
3: public/javascripts/something_else.js
You can even overwrite keys and still add new ones:
laptop:
<<: *SAMMY
1: public/javascripts/sammy_laptop.js
3: public/javascripts/something_else.js
In both cases the end result is a perfectly valid indexed array, just like before.
Other programming languages
Depending on your YAML implementation and how you iterate over your array, this could conceivably also be used in other programming languages. Though with a caveat.
For instance, in JS you can access numerical string keys by their integer value as well:
const sammy = {"1": "public/javascripts/vendor/sammy.js"}
sammy["1"]; // "public/javascripts/vendor/sammy.js"
sammy[1]; // "public/javascripts/vendor/sammy.js"
But you'd need to keep in mind, that your initial array is now an object, and that you would need to iterate over it accordingly, e.g.:
Object.keys(sammy).forEach(key => console.log(sammy[key]))
As it has been suggested, when you need to flatten a list, at least in ruby, it is trivial to add a "!flatten" type specifier to mobile and implement a class that extends Array, adds the yaml_tag and flattens the coder seq on init_with.

Resources