Citrus

A template generator which complex file structures can be defined in a single Yaml File.

How To Use

  1. Create template file.
  2. Execute command.

Template File(yaml)

# define symbols.
# These are user-defined symbols.
text: ['a', 'g']
flag: ['b']
object:
    c:
        # Data Type can only be specified as text, flag, or text_array
        x: 'text'
        y: 'flag'
        z: 'text_array'
text_array: ['d']
object_array:
    e:
        # Same as Object
        x: 'text'
        y: 'flag'
        # z: 'text_array' Object array is also possible, but it is more complex and therefore not a suitable example.
fragment:
    f: |
        Fragment is like a little template.
        You cannot call fragment within fragment.
        Other symbols can be called, just like template.
        {a}
        {b}
        {c.x}
        {#for i in d join g}{i}{#for}
        {#for i in e join g}{i.x.snake}{#for}

# constant user-defined symbols.
constant_text:
    k: 'k text'
constant_text_array:
    l: ['L', 'LL', 'LLL']
constant_flag:
    m: true
    q: false
constant_object:
    n:
        x: 'n.x text'
        y: ['Y', 'YY', 'YYY']
        z: true

# define template
template:
    # folder
    h:
        # file (path -> h/sample.txt)
        sample.txt: |
            Write the contents of the file.
            You can call the symbols defined above.

            {a}
            {a.snake}

            {b}
            {#true b}b flag is true{#true}

            {c.x}
            {c.x.pascal}
            {c.y}
            {#true c.y}c.y flag is true{#true}
            {#for i in c.z join g}{i.constant}{#for}

            {#for i in d join g}{i.camel}{#for}
            
            {#for object in e join g}{object.x}:{object.y}{#for}

            {f}

            {k}
            {#for i in l join g}{i}{#for}
            {#true m}m constant flag is true{#true}

            {n.x}
            {#for i in n.y join g}{i}{#for}
            {#true n.z}n.z is true{#true}

    # empty folder
    i:

    # empty folder
    j: null

    # Frame cannot be nested.
    # invalid example
    # x(for a in b):
    #     y(for c in d): 'some text'

    # for loop frame
    o_{i.snake}(for i in l):
        sample.txt: 'hello world {i}'

    # if switch frame
    p.txt(true m): 'm is true'
    r.txt(true q): 'q is true'

Generate Command

User Defined Symbol can be passed to generate command.
However, Fragment Symbol cannot be passed.

citrus generate --a 'a string' -b --c "object --x 'c x string' -y --z 'c z string 1' 'c z string 2' 'c z string 3'" --d 'd string 1' 'd string 2' 'd string 3' --e "object --x 'e x string 1' -y" "object --x 'e x string 2' -y" "object --x 'e x string 3'" --g ',' --generateLocation './example' --generateMode overwrite --templateFileLocation './example' --templateFileName example.yaml

--generateMode can be set to complement, overwrite, or synchronize.
complement は一番安全なモードで、出力先に既に file が存在する場合、その file は出力を行いません.
overwrite は次に安全なモードで、出力先に既に file が存在する場合、上書きします.
synchronize は、--generateLocation で指定した folder の配下を(すでにいくつかの file が存在していても)すべて削除し、出力します.

Result

Output to --generateLocation.

Folder Structure

+--- h
|      sample.txt
|
+--- i
|
+--- j
|
+--- o_l
|      sample.txt
|
+--- o_ll
|      sample.txt
|
+--- o_lll
|      sample.txt
|
+--- p.txt

h/sample.txt Content

Write the contents of the file.
You can call the symbols defined above.

a string
a_string

true
b flag is true

c x string
CXString
true
c.y flag is true
C_Z_STRING_1,C_Z_STRING_2,C_Z_STRING_3

dString1,dString2,dString3

e x string 1:true,e x string 2:true,e x string 3:false

Fragment is like a little template.
You cannot call fragment within fragment.
Other symbols can be called, just like template.
a string
true
c x string
d string 1,d string 2,d string 3
e_x_string_1,e_x_string_2,e_x_string_3


k text
L,LL,LLL
m constant flag is true

n.x text
Y,YY,YYY
n.z is true

Syntax

Please convert <Abstract Value> to concrete value at runtime.

Accesser

period で区切られた連続する Symbol の集まり.

a
object.b

Text Accesser

Accessor ending with text symbol.

Flag Accesser

Accessor ending with flag symbol.

Object Accesser

Accessor ending with object symbol.

Array Accesser

Accessor ending with array symbol.

Text Array Accesser

Accessor ending with text array symbol.

Object Array Accesser

Accessor ending with object array symbol.

Change Case

{<Text Accesser>.<Change Case Keyword>}

Not Case Syntax Sugar

{<Text Accesser>} equals to {<Text Accesser>.not}

text: ['a', 'b']
template:
    change_case.txt: |
        {a.pascal}
        {b}
        {b.not}
citrus generate --a 'sample text' --b 'sample text 2' ...
SampleText
sample text 2
sample text 2

For Loop

{#for <User Defined Symbol> in <Array Accesser> join <Text Accesser>}...{#for}

ここでの <User Defined Symbol> は ... の中でのみ参照される 一時的な symbol を新たに定義します。
この一時的な User Defined Symbol も他のものと同じように 名前が一意である必要があります。

<Array Accesser> の要素の数だけ ... を繰り返します.

<Text Accesser> は繰り返されるそれぞれの出力の境目に出力されます.

text_array: ['a']
fragment:
    commaAndSpace: ', '
template:
    for_loop.txt: |
        {#for i in a join commaAndSpace}{i}{#for}
citurs generate --a A AA AAA ...
A, AA, AAA

Define Text

{#define_text <User Defined Symbol>}...{#define_text}

Text Symbol is defined as having 「...」.
Usually used with For Loop syntax.

text_array: ['a']
template:
    define_text.txt: |
        {#define_text aNewLine}
        {#define_text}{#for i in a join aNewLine}{i}{#for}
citrus generate --a A AA AAA ...
A
AA
AAA

Equality Comparison

<Accesser> == <Accesser>

Usually used with If Branches syntax.

text: ['a', 'b']
template:
    equality_comparison.txt: |
        {#true a == b}a equal b{#true}
citrus generate --a x --b x ...
a equal b

If Branches

{#<Boolean Keyword> <Flag Accesser or Equality Comparison>}...{#<Boolean Keyword>}

flag: ['a', 'b']
text: ['x', 'y', 'z']
template:
    if_branches.txt: |
        {#true a}a flag is true{#true}
        {#true x == y}x equal y{#true}

        {#true b}b flag is true{#true}
        {#true x == z}x equal z{#true}

        {#false a}a flag is false{#false}
        {#false x == y}x not equal y{#false}

        {#false b}b flag is false{#false}
        {#false x == z}x not equal z{#false}

citrus generate -a --x X --y X --z Z ...
a flag is true
x equal y







b flag is false
x not equal z

Symbol

Symbol is variables and special word available in templates.

User Defined Symbol

Following, valid characters for user defined symbol. However, duplicate with Keyword is invalid.

  • a~z

  • A~Z

  • 0~9

    • However, invalid character as a prefix.
    • invalid example: 2abc, 012d,
    • valid example: a1c2, _01234,
  • _ (under bar)

Text Symbol

bind text.

Flag Symbol

bind boolean(true or false).

Object Symbol

bind text or text array or boolean at key value format.

Array Symbol

bind multiple data.

Text Array Symbol

bind multiple text.

Object Array Symbol

bind multiple object.

Fragment Symbol

bind text.

Keyword

keyword is built in symbol available in syntax.

  • in
  • join

Define Keyword

  • define_text
  • define_object

Block Type Keyword

  • for
  • protect
Boolean Keyword
  • true
  • false

Change Case Keyword

  • camel (test string -> testString)
  • capital (test string -> Test String)
  • constant (test string -> TEST_STRING)
  • dot (test string -> test.string)
  • header (test string -> Test-String)
  • no (TestString -> test string)
  • not (test string -> test string)
  • param (test string -> test-string)
  • pascal (test string -> TestString)
  • path (test string -> test/string)
  • sentence (test string -> Test string)
  • snake (test string -> test_string)
  • swap (test string -> TEST STRING)