小さなissueを作ってはcloseを繰り返してた

github.com

細々としたaction(関数)を追加する作業。小さなissueを作ってはcloseを繰り返してた。

例えば以下のようなaction(関数)が追加された

  • counter
  • format
  • get (with default value)

追加されたものたち

counter

$let:
  c0: {$counter: 3}
  c1: {$counter: 0}
body:
  - {$c0: "item{:04}"}
  - {$c1}
  - {$c0: "item{:04}"}
  - {$c1}

output:
  - item0003
  - 0
  - item0004
  - 1

counter的な何かは欲しくなりそうな感じ。例えばアプリの設定のport番号などを割り振る際に利用したくなる。

format

- $format: "{prefix}{number:04}"
  prefix: foo
  number: 0
- $format: "{prefix}{number:04}"
  prefix: foo
  number: 1
- $format: "{prefix}{number:04}"
  prefix: bar
  number: 0

output:
  - foo0000
  - foo0001
  - bar0000

formatもたぶん同様に欲しくなる。特定のprefixと組み合わせたアプリケーション名だったり、アクセス先のホスト名/ドメイン名などを作る機会は結構ありそう。このactionの実装はすごい簡単なので載せておく。

def format(fmt, **kwargs):
    return fmt.format(**kwargs)

かんたん。

get (with default value)

元々$get自体はあったのだけれど、デフォルト値を取る事ができなかったので取れるようにした。dict.getとも対応が取れる様になったので良い名前になった(ただしdefault値を渡さない場合はkeyerrorが出る。Noneではない)。

$let:
  person:
    name: foo
body:
  - {$get: person}
  - {$get: "person#/name"}
  - {$get: "person#/age", default: 0}


output:
  - name: foo
  - foo
  - 0

$importをするのはすごいお手軽

繰り返しになるけれど$importをするのはけっこう手軽。なので組み込みのactionに無いものは自由に作ってimportしてしまえる。例えば、上のformatの例だと。

fmt.py

def format(fmt, **kwargs):
    return fmt.format(**kwargs)

こういうものを書いてあげれば、こういう風に使える。

code:
  - {$from: "./fmt.py", import: format}

items:
  - $format: "{prefix}{number:04}"
    prefix: foo
    number: 0
  - $format: "{prefix}{number:04}"
    prefix: foo
    number: 1
  - $format: "{prefix}{number:04}"
    prefix: bar
    number: 0

importには物理的なファイル名を指定出来るのでけっこう便利だと思う。(文法上の制約でitemsが必要みたいな話はあったり。出力がcodeを使った形状(dict)になっているので)

今後のこと

今週はとりあえず消費者的な立ち位置から足りないものをあれこれと補っていこうかなという感じ。あと、ドキュメントを書かないととは思うもののやる気が不足している。ところであるコンテキスト上のdoctestみたいな物がほしい。

例えば、上のそれぞれのyamlの実行例をサンプルとしてドキュメントとして利用しつつテストにも使いたいみたいな感じ。

現状のテストは以下の様な感じ。

class ActionsTests(DiffTestCase):
    def test_get(self):
        class m:
            from zenmai.actions import get  # NOQA

        source = textwrap.dedent("""
        $let:
          person:
            name: foo
        body:
          - {$get: person}
          - {$get: "person#/name"}
          - {$get: "person#/age", default: 0}
        """)

        d = self._callFUT(source, m)
        actual = loading.dumps(d)
        expected = textwrap.dedent("""
        - name: foo
        - foo
        - 0
        """)
        self.assertDiff(actual.strip(), expected.strip())