Data is data. Code is logic. So the the thought process goes...
...what if I could store my configuration (data! right?!) in a way that is nicely separated from the logic?! No more scripting for me!
Oh wait. Some of the configuration can't be generalized about universally. Configurations fundamentally contain logic, I guess.
Oh, well then why don't I just represent the logic in the data?! That will be much better than representing the data in the logic!
....but now, you are back where you started, only instead of using something nice, standard, and powerful like Python, you have to use this... language... thing. This YAML convention you cooked up.
Separate the data from logic. Read the data into the logic. Make a nice organized place to call custom logic from... like, you know, a file directory full of scripts, which are called according to some scheme. It could be another data file. Stop there.
Like this:
$ ls -Ra
./config/do_something.yaml
./config/do_something_else.yaml
./config/config.yaml
./logs/ping.log
./scripts/do_something.py
./scripts/do_something_else.py
--- $ cat ./config/config.yaml
do_something:
target: my.stupid.server
exec_frequency: daily
...
do_something_else:
target: my.stupid.server
exec_frequency: monthly
...
--- $ cat ./config/do_something.yaml
ping: true
output:
directory: ./logs/ping.log
mode: append
--- $ cat ./config/do_something_else.yaml
delete: ./logs/ping.log
--- $ cat ./scripts/do_something.py
from stupid.library.task import Task, subscribe
class DoSomething(Task):
@subscribe
def ping(self, target):
return super().ping(target)
Then you code the program that runs collects all of the task methods, put them in an ordered list, and run them if the conditions in the config.yaml is met.Every other thing is done in a task method in python, or something like it. I don't think we need more abstraction than that.
The whole idea being that you don't want the story to be turing complete (there are no loops or conditionals with a story), but the code that executes it needs to be turing complete.