kalekundert / stepwise

Modular, command-line scientific protocols
GNU General Public License v3.0
3 stars 0 forks source link

Refactor the internal protocol representation #58

Open kalekundert opened 2 years ago

kalekundert commented 2 years ago

Here are my goals for the refactoring:

I think the best way to do all of this is to take the following approach:

For what it's worth, I think of this architecture as being heavily inspired by the idea of multiple dispatch.

Some questions:

Some miscellaneous notes:

Here's some pseudocode:

# Example document
root = {
    type: 'pl',
    items: [
        {
            type: 'p',
            content: 'Lorem ipsum...',
        }, 
        {
            type: 'ul',
            items: [
                {
                    type: 'p',
                    content: 'Dolor sit amet...',
                },
            ],
        },
    ],
}

# Example plugin functions
def format_p_text(node):
    textwrap.wrap(node['contents'])

def format_pl_text(node):
    return '\n\n'.join(
            format(item, 'text')
            for item in node['items']
    )

def replace_p(node, pat, repl, count):
    node['content'], n = re.subn(pat, repl, count)
    return n

def replace_pl(node, pat, repl, count):
    for item in node['items']:
        n = replace(node, pat, repl, count)
        count -= n

# The actual registries:
FORMAT = {
        ('text', 'p'): format_p_text,
        ('text', 'pl'): format_p_text,
}
REPLACE = {
        'p': replace_p,
        'pl': replace_pl,
}

# The generic functions:
def format(node, format):
    try:
        node = node.__node__()
    except AttributeError:
        pass

    key = node['type'], format
    func = FORMAT[key]
    return func(node)

def replace(node, pat, repl, count):
    try:
        node = node.__node__()
    except AttributeError:
        pass

    # This works in-place, so no need to return anything.
    type = node['type']
    func = REPLACE[type]
    func(node)