diff --git a/dr.syntax/README.md b/dr.syntax/README.md index 515b53e..64f2ada 100644 --- a/dr.syntax/README.md +++ b/dr.syntax/README.md @@ -9,64 +9,159 @@ Dr. Syntax (in America known as Syntax, M.D.) is an object model, and file layout for representing recipes, ingredients, and shopping lists. +Examples are shown in JSON format, and the `nosebag` project will continue to +use JSON, but Dr. Syntax is format agnostic as long as the object can be +serialised and deserialised intact. + ## Object model -### Recipes - -Each recipe is represented as a core object and optional additional media. -The central properties of each recipe are two lists: - -* recipe ingredients, which: - * reference an ingredient by name (which may not exist, - in which case it is treated as if an ingredient of that name exists - with no other defined properties) - * have an optional quantity which are either a naked - positive number, meaning an amount without unit, or contain: - * an amount - * a unit - * optional notes that provide advice on how to modify the amount - required (such as "more if they are small") - * an optional property of 'optional', meaning that the ingredient can be - omitted - * an optional prep instruction - * an optional note (distinct from the quantity note), which can be used - to express a preference; for instance, you could indicate a preferred - variety -* steps, each of which is a narrative of the task to be accomplished - -Recipes also have a name, an optional "serves" property to represent how many -people this recipe will feed, and zero or more attributes (such as "gluten -free"), which are used for searching and filtering. -Prep instructions for ingredients are implicit steps that all come before -the first recipe step. -### Ingredients +### The list of known ingredients — `ontology.json` + +Stored serialised as `ontology.json`, the ontology is an object containing +an abstraction of foodstuff used in recipes. + +```javascript +{ + "ingredients": [ + { + "name": "carrot", + "group": "vegetable", + "attributes": [ + "meat free", + ... + ] + }, + ... + ] +} +``` + +Each ingredient is an object, containing: + +* `name` — _required_, the unique, singular name of the foodstuff, by + convention lower cased (ie "carrot" not "Carrots") +* `group` — _optional_, the unique, singular name of the grouping of the + foodstuff, also by convention lower cased (ie "spice" not "Spices") +* `attributes` — _optional_, an array of strings which represents aspects of the + ingredient, such as "dairy" or "meat" that could be used for searching + and filtering + +Groups represent a phase of shopping where similar items are collected +together, such as an aisle or area in a supermarket, or visiting different +shops. -Ingredients are the abstraction of the food stuff used in recipes. So -"carrot" rather than "100g carrots". The names of ingredients are unique, -and by convention are singular and lower-cased. -Ingredients also have an optional group, referenced by name, and zero or -more attributes (such as "meat") which are used for searching and filtering -recipes. +### The list of recipes — `recipes.json` -### Groups +Stored serialised as `recipes.json`, the list of recipes is an array of +strings that represent the directory relative to the location storing both +`recipes.json` and `ontology.json` under which the recipe serialisation can be +found. -Groups represent a phase of your shopping, and may be thought of as aisles -of a supermarket, or different shopkeepers. They have a name, which like -ingredients are unique, singular, and lower-cased. For example, "vegetable", -or "spice". +```javascript +{ -## File layout + "recipes": [ + "bacon-hash", + "cauliflower-fritter-lime-sauce", + ... + ] +} +``` + + +### A recipe — `/recipe.json` The recipe core object is serialised as JSON, and stored as `recipe.json` alongside additional media files for that recipe. (Media files are referenced using either a relative URL, meaning their leaf filename, or an absolute URL if the media files are stored elsewhere such as on Wikipedia.) -Ingredients and groups are serialised as one JSON object, stored as -`ontology.json`. +```javascript +{ + "name": "Mashed potatoes", + "serves": "2", + "attributes": [ + "gluten free", + ... + ], + "ingredients": [ + { + "name": "large potato", + "quantity": 4, + "prep": "cut into 1-inch cubes", + "notes": "Preferably Maris Piper or other floury potato." + }, + ... + ], + "steps": [ + { + "task": "Heat water in a large pan until boiling.", + }, + ... + ], +} +``` + +The **recipe object** contains: + +* `name` — _required_, a string containing the name of the recipe (this does not + have to be unique within a collection of recipes) +* `ingredients` - _required_, an array of ingredient objects (see below) +* `steps` — _required_, an array of step objects (see below) +* `serves` — _optional_, a string representing how many people this recipe will feed +* `attributes` — _optional_, an array of strings which represent aspects of + this recipe (such as "gluten free") which can be used for searching and + filtering + + +The **ingredient object** contains: + +* `name` — _required_, a string containing the name of the ingredient to + reference from the ontology (which may not exist, in which case it is + treated as if an ingredient of that name exists with no other defined + properties) +* `quantity` — _optional_, an object which contains: + + ```javascript + { + "amount": 300, + "unit": "g", + } + ``` + + * `amount` — _required_, a positive integer + * `unit` — _optional_, a string representing the unit of which _amount_ is + needed + * `notes` — _optional_, a string containing advice on how to adjust the amount if + necessary (eg "more if they are small") + + If both `unit` and `notes` are not needed, the object can be collapsed to a + positive integer (eg requiring 2 onions has no new unit to be expressed). +* `prep` — _optional_, a string containing directions on how to prepare the + ingredient before making the recipe (eg "finely chopped") +* `notes` — _optional_, a string containing advice on the ingredient (such as + a preferred variety, acceptable substitutions, things to look out for when + purchasing, etc) +* `optional` — _optional_, a boolean value set to `true` if the ingredient is + not strictly necessary, such as a garnish or extra herbs/spices + +The **step object** contains: + +* `task` — _required_, a string containing the narrative description of a step + in making the recipe + + +When interpreting a recipe object, these are the keys Dr. Syntax has imbued +with meaning. Other keys can exist in the object for private use, but note +that this specification may be expanded later which could introduce +incompatibilities. There is as yet no explicit extension model. + +Prep instructions for ingredients are implicit steps that all come before +the first recipe step. + ## Doctor Syntax recommends that @@ -91,7 +186,5 @@ Ingredients and groups are serialised as one JSON object, stored as tools to suggest ways of scheduling the steps of multiple recipes you need to cook at once, such as for a dinner. -* group and ingredient names are singular and lower-cased. - * "large potato" as an ingredient can be more useful than "potato" with a quantity unit of "large".