Skip to content

JSON Inheritance

NebelFox edited this page Apr 2, 2022 · 9 revisions

Base Keyword

In both Box and Style objects the base property could be specified, which takes a string with the name of a Box or a Style to derive respectively.

The derived object is basically the copy of the base object, extended with properties, defined in derived object.

Note. It's not necessary for the base object to be defined in the same file or only above the derived one. The requirements are that both base and derived objects must be loaded by the same box/style deserializer before retrieving any of them and there is no circular inheritance.

Note. Similar with style for box - style may be defined in another file, but the box-serializer, that deserializes the box, must use the style-serializer, that deserialized the specified style.

Style Inheritance Example

{
    "styles": {
        "base-style": {
            "dialogue": {
                "greeting": "Hi there!",
                "farewell": "See ya!"
            }
        },
        "derived-style": {
            "base": "base-style",
            "dialogue.farewell": "Bye..."
        }
    }
}

In this case, the "derived-style" is equal to the next one:

{
    "style": {
        "dialogue": {
            "greeting": "Hi there!",
            "farewell": "Bye..."
        }
    }
}

Insert-commands Property of Box

Alternatively to the command property, an insert-commands property may be specified. It takes an array of command insert blocks. Each command insert block contains a commands property, which is absolutely identical to the same box property; and one of three position specifiers:

  • at - takes either "top" or "bottom" as a value, and inserts the commands at the beginning or at the end respectively.
  • above - takes the name of the executable to place the commands above.
  • below - takes the name of the executable to place the commands below.
    Example:
{
    "insert-commands": [
        {
            "at": "top",
            "commands": ["foo"]
        },
        {
            "above": "foo",
            "commands": ["bar"]
        },
        {
            "below": "bar",
            "commands": ["baz"]
        }
    ]
}

The order would be:

  • bar
  • baz
  • foo

Note. Inserts into nested namespaces currently are not supported.


Completing Base Box

Note. In this section, yaml is used instead of json for clarity. Check out this page for more info

Problem:

Let's say you have a base box chatter, and two derived boxes - joyful-chatter and sad-chatter:

chatter:
  commands:
    - greet
joyful-chatter:
  base: chatter
  commands:
    - cheer
sad-chatter:
  base: chatter
  commands:
    - upset

Both joyful-chatter & sad-chatter got greet command from chatter box. Now let's assume you want to have the same action appointed to the greet command for both derived boxes. But a box is deserialized into an instruction on how to construct the corresponding BoxBuilder, rather than BoxBuilders instance itself.
So changing the deserialized chatter won't affect the derived boxes And you would have to duplicate the action appointment for both joyful-chatter and sad-chatter like so:

// assume that `deserializer` is an Deserializer instance,
// fed with yaml specification above
Box joyful = deserializer.Boxes["joyful-chatter"]
                         .SetAction("greet", 
                                    context => Console.WriteLine("Hi there!"))
                         .Build();
Box sad = deserializer.Boxes["sad-chatter"]
                      .SetAction("greet", 
                                 context => Console.WriteLine("Hi there!"))
                      .Build();

Solution

BoxSerializer allows "extending" an instruction, i.e. append an extra step for BoxBuilder constructing process. Moreover, a derived box is just an instruction on what to add to the base box, which in turn is constructed with its own instruction. So extending the base box would affect the derived boxes as well. It could be done as follows:

deserializer.Boxes.Extend(
    "chatter",
    builder => builder.SetAction(
        "greet",
        context => Console.WriteLine("Hi there!")
    )
);

So after retrieving joyful-chatter or sad-chatter they would have the action for greet command already set!


Box Inheritance Example

("derived-style" from Inheritance)

{
    "boxes": {
        "common": {
            "style": "derived-style",
            "commands": [
                "main",
                "exit"
            ]
        },
        "derived": {
            "style": {
                "base": "derived-style",
                "dialogue.greeting": "Welcome!"
            },
            "insert-commands": [
                {
                    "above": "exit",
                    "commands": ["help"]
                }
            ]
        }
    }
}
Clone this wiki locally