Skip to content

Hello Worlds!

The following is a collection of hello worlds ranging from simple to contrived that demonstrate the core aspects of writing tackle files.

Future hello worlds

  • Inheriting from schemas like openapi
  • Declarative CLI help screens

Running the Hello world! demo

Locally + Copy / Paste You can create a file hello.yaml and paste in the following or you can run some of these examples in tackle.

tackle robcxyz/tackle-hello-world

Single line print

Simply use the print hook.

hw->: print Hello world!

Anytime a key is suffixed with an arrow going to the right, it means the key is calling a hook, in this case a print hook.

Using jinja templating, the print hook can be called in three different ways using a variable.

words: Hello world!
expanded:
  ->: print
  objects: "{{words}}"
compact->: print {{words}}
jinja_extension->: "{{ print(words) }}"
# Or combinations of the above

Note that key with arrow without an explicit hook is simply rendered

Interactive prompts

There are several types of prompt hooks which can also be used.

name->: input
target:
  ->: select Say hi to who?
  choices:
    - world
    - universe
hello->: print My name is {{name}}. Hello {{target}}!

Which looks like this before printing.

? name >>> Rob
? Say hi to who?
❯ world
  universe

Loops and conditionals

Hooks can have loops, conditionals, and other base methods.

words:
  - Hello
  - cruel
  - world!
expanded:
  ->: print {{item}}
  for: words
  if: item != 'cruel'
compact->: print {{item}} --for words --if "item != 'cruel'"

Manipulating context

Hooks can manipulate the context with the context provider so using the preceding example, instead of doing a list comprehension we can instead remove the second element using the pop hook.

words:
  - Hello
  - cruel
  - world!
rm cruel->: pop words 1
expanded:
  ->: print {{item}}
  for: words
compact->: print {{item}} --for words

Blocks of context

Sometimes it is convenient to declare a group of logic that contains the base methods like in this case for.

words:
  - Hello
  - world!
a-block->:
  for: words
  h->: print {{item}} --if "index == 0"
  w->: print {{item}} --if "index == 1"

Blocks are simply any key ending with an -> with a map as the value. In this case we also see that within for loops, the iterand is also tracked via the index variable.

Public vs private hooks

Hooks can have both public and private access modifiers which inform whether the hooks value is exported outside of the tackle file / function.

For instance running with the --print or -p flags, (ie tackle hello.yaml -p), only the public context would be exported.

Input

words_>:
  - Hello
  - world!
output->: var {{item}} --for words
Output
output:
  - Hello
  - world!

You can still use the output of a private hook but only within the tackle file that it is being called. By default, the public context moves with the call between tackle files.

Python hooks

Hooks can be written in python. Simply add your code to a hooks directory and the hook will be available to be called from a tackle file.

from tackle import BaseHook

class Greeter(BaseHook):
    hook_type: str = "greeter"
    target: str
    args: list = ['target']
    def exec(self):
        print(f"Hello {self.target}")

Declarative hooks

Hooks can be declaratively created with tackle. Arrows going to the left are basically reusable functions / methods.

greeter<-:
  target: str
  args: ['target']
  exec<-:
    hi->: print Hello {{target}}

Both python and declarative hooks can be called in the same way.

hello: world!
compact->: greeter {{hello}}
expanded:
  ->: greeter
  target: "{{hello}}"
jinja_extension->: "{{ greeter(hello) }}"
jinja_filter->: "{{ hello | greeter }}"

Strongly typed declarative hooks

Declarative hooks are strongly typed objects with many declarative fields.

words<-:
  hi:
    type: str
    regex: ^(Bonjour|Hola|Hello)
  target: str

p->: print {{item}} --for values(words(hi="Hello",target="world!"))

Here we are also using the values hook which can also be daisy-chained with the pre-declared words hook.

Note an error would be thrown if the hi key did not satisfy the regex.

Declarative hook methods

Declarative hooks can have methods that extend the base.

words<-:
  hi: Wadup
  say<-:
    target: str
    exec:
      p->: print {{hi}} {{target}}

p->: words.say --hi Hello --target world!

Declarative hooks inheritance

Declarative hooks also support inheritance.

base<-:
  hi:
    default: Hello

words<-:
  extends: base
  say<-:
    target: str
    exec:
      p->: print {{hi}} {{target}}

p->: words.say --target world!

Which can also be called from the command line.

tackle hello-world.yaml

Calling other tackle files

Every hook can be imported / called remotely from github repos with the same options as you would from the command line.

import-hello_>: import robcxyz/tackle-hello-world
call->: greeter world!
# Or
local-call->: tackle hello-world.yaml
remote-call->: tackle robcxyz/tackle-hello-world --version v0.1.0

Self Documenting Declarative CLIs

Documentation can be embedded into the hooks.

tackle robcxyz/tackle-hello-world help

<-:
  help: This is the default hook
  target:
    type: str
    description: The thing to say hello to
  exec<-:
    greeting->: select Who to greet? --choices ['world','universe']
    hi->: greeter --target {{greeting}}
  greeting-method<-:
    help: A method that greets
    # ... Greeting options / logic
greeter<-:
  help: A reusable greeter object
  target: str
  exec<-:
    hi->: print Hello {{target}}

Which when running tackle hello.yaml help produces its own help screen.

usage: tackle hello.yaml [--target]

This is the default hook

options:
    --target [str] The thing to say hello to
methods:
    greeting-method     A method that greets
    greeter     A reusable greeter object

That [will] drive a help screen by running tackle hello-world.yaml --help -> Coming soon