Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to represent value + units in YAML?

Tags:

yaml

config

I'm designing a new config/data format, which will be in YAML. Many of the inputs are int/float values, with associated units (e.g. liter, quart, pint, second, minute, ...).

I've been searching and reading, but still can't figure out: What is the best way to associate a value and unit to a config item in YAML?

Example: Say I have a list of several beverages, and (among other things), I want to input their volume. I can think of a few ways, but (at least in my opinion) none of them are really ideal:

  1. Require all volume values to be input in the same units.

    Forces the user to do the unit conversion him/herself, which is tedious, error-prone, and difficult to verify later, because now the quantity input differs from the original quantity listed for the beverage. (Beverages come from several different sources, each potentially using a different unit of measure.)

  2. Represent the value with a sequence of volume and units. Example:

    volume: [ 0.5, Gallons ]
    

    (A mapping would work as well, although more verbose) The sequence might be OK, but I'm not sure if I'm comfortable with it.

  3. Use two "volume" values, one for value, the other for units. Example:

    volume_value: 0.5
    volume_units: Gallons
    

    I think this is a non-starter. Verbose, very loose association, error-prone.

  4. Use a string instead, and parse it in the application. Example:

    volume: 0.5 Gallons
    

    Simplest to enter, and is very easy to write a robust parser. Seems perhaps like a bit of a hack, though...

  5. Application tags:

    volume: !gallons 0.5
    

    Not sure about this one, as I am new to YAML and don't yet have a good understanding of tags. Syntax is a little more fragile, perhaps.


So, the question is: per the YAML spec, or defacto best practice/convention, is there a specific way of representing values + units? Whether it's one of the five I listed or something else, I do hope there is a "right answer", to stay within the site Question guidelines.

like image 242
Luk232 Avatar asked Dec 27 '13 00:12

Luk232


1 Answers

You should seriously look into using the tag version, as this will allow you to immediately create a Gallons instance, which could be a derivative of a generic Volume class on which you can do normalized calculations. You're code working with the config would become more flexible.

If you do, extend the safe loader your library provides especially if you don't have full control over the creation of the config file. If you don't and load this using an interpreted language (perl, python, ruby) you run the risk of a specially crafter config running any code on the computer.

If tags are not the way you want to go, there is another alternative you haven't offered, that of nested mappings:

volume:
  Gallons: 0.5

or as one-liner:

volume: {Gallons: 0.5} 

or if you prefer:

volume: {0.5: Gallons}

The above would require interpretation after loading, just like your options 2, 3 and 4.


As @denian comment about the use of strings instead of floats has a point, you could, if you want to go for calculations using Fractions use !decimalfraction "0.5". In Python (PyYAML, ruamel.yaml) you can tweak the YAML loader so you don't need to provide the quotes around 0.5 but that will result in all floats in the file to be loaded as strings (which can then be interpreted without rounding errors by the decimalfraction instance creation).

like image 81
Anthon Avatar answered Sep 18 '22 14:09

Anthon