Skip to content

Commit 9cf055a

Browse files
authored
Merge pull request #48 from soranoba/bbmustache-cmd
command-line script
2 parents 636815b + bb8700f commit 9cf055a

25 files changed

+393
-9
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,3 +19,4 @@ _build
1919
.rebar3
2020
_checkouts
2121
benchmarks/.tmp
22+
/bbmustache

Makefile

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,19 @@
1+
CWD=$(shell pwd)
2+
13
.PHONY: ct
2-
all: compile eunit ct xref dialyze edoc
4+
all: compile escriptize eunit ct xref dialyze edoc
35

46
compile:
57
@./rebar3 as dev compile
68

79
xref:
8-
@./rebar3 xref
10+
@./rebar3 as dev xref
911

1012
clean:
1113
@./rebar3 clean
1214

13-
ct:
14-
@./rebar3 ct
15+
ct: escriptize
16+
@CMD_TOOL=$(CWD)/bbmustache ./rebar3 ct
1517

1618
cover:
1719
@./rebar3 cover
@@ -20,15 +22,22 @@ eunit:
2022
@./rebar3 eunit
2123

2224
edoc:
23-
@./rebar3 as dev edoc
25+
@./rebar3 as doc edoc
2426

2527
start:
2628
@./rebar3 as dev shell
2729

2830
dialyze:
29-
@./rebar3 dialyzer
31+
@./rebar3 as dev dialyzer
3032

3133
bench:
3234
@./rebar3 as test compile
3335
@./rebar3 as bench compile
3436
@./benchmarks/bench.escript
37+
38+
escriptize:
39+
@./rebar3 as dev escriptize
40+
@cp _build/dev/bin/bbmustache .
41+
42+
install: escriptize
43+
cp bbmustache /usr/local/bin

README.md

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,19 @@ Associative array
8181
<<"hoge">>
8282
```
8383
84+
### Use as a command-line tool
85+
86+
```bash
87+
make escriptize
88+
echo '{"name", "hoge"}.' > vars.config
89+
echo '{{name}}' > template.mustache
90+
./bbmustache -d vars.config template.mustache
91+
hoge
92+
```
93+
94+
Data files (-d) support a single assoc list, a single map, and [consult](https://erlang.org/doc/man/file.html#consult-1) format.<br>
95+
Note: the behind term has a high priority in all cases. it is a result of supporting to allow for embedding relative file paths as in [config](http://erlang.org/doc/man/config.html).
96+
8497
### More information
8598
- For the alias of mustache, Please refer to [ManPage](http://mustache.github.io/mustache.5.html) and [Specification](https://github.com/mustache/spec)
8699
- For the options of this library, please see [doc](doc)
@@ -144,11 +157,10 @@ ok
144157
3> bbmustache:render(<<"<h1>{{{title}}}</h1>">>, #{<<"title">> => #{<<"nested">> => <<"value">>}}, [{key_type, binary}, {value_serializer, fun(X) -> jsone:encode(X) end}]).
145158
<<"<h1>{\"nested\": \"value\"}</h1>">>
146159
147-
4> bbmustache:render(<<"<h1>{{title}}</h1>">>, #{<<"title">> => #{<<"nested">> => <<"value">>}}, [{key_type, binary}, {value_serializer, fun(X) -> jsone:encode(X) end}]).
160+
4> bbmustache:render(<<"<h1>{{title}}</h1>">>, #{<<"title">> => #{<<"nested">> => <<"value">>}}, [{key_type, binary}, {value_serializer, fun(X) -> jsone:encode(X) end}]).
148161
<<"<h1>{&quot;nested&quot;:&quot;value&quot;}</h1>">>
149162
```
150163
151-
152164
## Attention
153165
- Lambda expression is included wasted processing.
154166
- Because it is optimized to `parse_binary/1` + `compile/2`.

ct/bbmustache_escript_SUITE.erl

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
%% @copyright 2020 Hinagiku Soranoba All Rights Reserved.
2+
3+
-module(bbmustache_escript_SUITE).
4+
-include_lib("common_test/include/ct.hrl").
5+
-include_lib("eunit/include/eunit.hrl").
6+
7+
%%----------------------------------------------------------------------------------------------------------------------
8+
%% 'common_test' Callback API
9+
%%----------------------------------------------------------------------------------------------------------------------
10+
11+
all() ->
12+
[
13+
{group, long},
14+
{group, short},
15+
{group, with_args},
16+
17+
help, all_key_and_format_type, multiple_data_files, enoent
18+
].
19+
20+
groups() ->
21+
[
22+
{long, [version, help, key_type]},
23+
{short, [version, help, key_type]},
24+
{with_args, [version, help]}
25+
].
26+
27+
init_per_suite(Config) ->
28+
Escript = case os:getenv("CMD_TOOL") of
29+
Path when is_list(Path) -> Path
30+
end,
31+
[{escript, Escript} | Config].
32+
33+
end_per_suite(_) ->
34+
ok.
35+
36+
init_per_testcase(TestCase, Config) ->
37+
Args = case {group_name(Config), TestCase} of
38+
{long, version} -> ["--version"];
39+
{short, version} -> ["-v"];
40+
{with_args, version} -> ["-v", "file"];
41+
42+
{long, help} -> ["--help"];
43+
{short, help} -> ["-h"];
44+
{with_args, help} -> ["-h", "file"];
45+
{undefined, help} -> [];
46+
47+
{long, key_type} -> ["--key-type", "atom",
48+
"--data-file", data_file_name(atom, basic, Config),
49+
?config(data_dir, Config) ++ "template.mustache"];
50+
{short, key_type} -> ["-k", "atom",
51+
"-d", data_file_name(atom, basic, Config),
52+
?config(data_dir, Config) ++ "template.mustache"];
53+
_ -> []
54+
end,
55+
[{args, Args} | Config].
56+
57+
end_per_testcase(_, _) ->
58+
ok.
59+
60+
%%----------------------------------------------------------------------------------------------------------------------
61+
%% Common Test Functions
62+
%%----------------------------------------------------------------------------------------------------------------------
63+
64+
version(Config) ->
65+
Got = run(Config),
66+
?assertMatch({match, _}, re:run(Got, "bbmustache v[0-9]\.[0-9]\.[0-9].*")).
67+
68+
help(Config) ->
69+
Got = run(Config),
70+
?assertMatch({match, _}, re:run(Got, "Usage: .*")).
71+
72+
key_type(Config) ->
73+
Got = run(Config),
74+
Expect = read_file("template.result", Config),
75+
?assertEqual(Expect, Got).
76+
77+
all_key_and_format_type(Config) ->
78+
KeyTypes = [atom, string, binary, undefined],
79+
FormatTypes = [basic, assoc, maps],
80+
Expect = read_file("template.result", Config),
81+
TempalteFile = ?config(data_dir, Config) ++ "template.mustache",
82+
ok = lists:foreach(fun({KeyType, FormatType}) ->
83+
ct:log("KeyType = ~p, FormatType = ~p", [KeyType, FormatType]),
84+
Got = run(Config, options(KeyType, FormatType, Config) ++ [TempalteFile]),
85+
?assertEqual(Expect, Got)
86+
end, [{K, F} || K <- KeyTypes, F <- FormatTypes]).
87+
88+
multiple_data_files(Config) ->
89+
KeyTypes = [atom, string, binary, undefined],
90+
FormatTypes = [basic, assoc, maps],
91+
Expect = read_file("template.overlay.result", Config),
92+
TempalteFile = ?config(data_dir, Config) ++ "template.mustache",
93+
ok = lists:foreach(fun({KeyType, FormatType}) ->
94+
ct:log("KeyType = ~p, FormatType = ~p", [KeyType, FormatType]),
95+
Got = run(Config, options(KeyType, FormatType, Config)
96+
++ ["-d", data_file_name(KeyType, overlays, Config)] ++ [TempalteFile]),
97+
?assertEqual(Expect, Got)
98+
end, [{K, F} || K <- KeyTypes, F <- FormatTypes]).
99+
100+
enoent(Config) ->
101+
Got0 = run(Config, ["-d", "no_file", ?config(data_dir, Config) ++ "template.mustache"]),
102+
?assertEqual(<<"ERROR: no_file is unable to read. (enoent)\n">>, Got0),
103+
104+
Got1 = run(Config, ["no_file"]),
105+
?assertEqual(<<"ERROR: no_file is unable to read.\n">>, Got1).
106+
107+
%%----------------------------------------------------------------------------------------------------------------------
108+
%% Internal Functions
109+
%%----------------------------------------------------------------------------------------------------------------------
110+
111+
-spec group_name([term()]) -> atom().
112+
group_name(Config) ->
113+
proplists:get_value(name, ?config(tc_group_properties, Config)).
114+
115+
-spec run([term()]) -> binary().
116+
run(Config) ->
117+
run(Config, []).
118+
119+
-spec run([term()], [string()]) -> binary().
120+
run(Config, Args) ->
121+
Cmd = ?config(escript, Config) ++ " " ++ string:join(?config(args, Config) ++ Args, " "),
122+
ct:log("$ ~s", [Cmd]),
123+
Ret = os:cmd(Cmd),
124+
ct:log("~s", [Ret]),
125+
list_to_binary(Ret).
126+
127+
-spec read_file(file:filename_all(), [term()]) -> binary().
128+
read_file(FileName, Config) ->
129+
{ok, File} = file:read_file(filename:join([?config(data_dir, Config), FileName])),
130+
File.
131+
132+
-spec data_file_name(atom(), atom(), [term()]) -> string().
133+
data_file_name(undefined, FormatType, Config) ->
134+
data_file_name(string, FormatType, Config);
135+
data_file_name(KeyType, FormatType, Config) ->
136+
?config(data_dir, Config) ++ atom_to_list(KeyType) ++ "." ++ atom_to_list(FormatType).
137+
138+
-spec options(atom(), atom(), [term()]) -> [string()].
139+
options(undefined, FormatType, Config) ->
140+
["-d", data_file_name(string, FormatType, Config)];
141+
options(KeyType, FormatType, Config) ->
142+
["-k", atom_to_list(KeyType),
143+
"-d", data_file_name(KeyType, FormatType, Config)].
144+
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{name, "mustache"},
3+
"atom.include",
4+
{data, [
5+
"a",
6+
"b"
7+
]}
8+
].
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{name, "mustache"}.
2+
3+
"atom.include".
4+
5+
{data, [
6+
"a",
7+
"b"
8+
]}.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{name, "bbmustache"}.
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
#{
2+
name => "bbmustache",
3+
data => [
4+
"a",
5+
"b"
6+
]
7+
}.
Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
{name, "overlays"}.
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
[
2+
{<<"name">>, "mustache"},
3+
"binary.include",
4+
{<<"data">>, [
5+
"a",
6+
"b"
7+
]}
8+
].

0 commit comments

Comments
 (0)