From 8f5aa17109dbb0b6168b9cf1b0c4e78c5a6d95b1 Mon Sep 17 00:00:00 2001 From: sadbeast Date: Tue, 12 Sep 2023 17:38:53 -0700 Subject: [PATCH] Add MustacheLoad to support loading from file According to the facil.io docs (http://facil.io/0.7.x/fiobj_mustache#fiobj_mustache_new): > By setting the filename argument even when the data argument exists, > it will allow path resolution for partial templates. Otherwise, there > is no way to know where to find the partial templates. This will allow partial templates to work. However, this also introduces a breaking change to the existing MustacheNew function. This change makes it mirror the C version where it accepts a MustacheLoadArgs struct instead of just the data. That's also a handy method to have, so I renamed that to MustacheData...maybe there's a better name? --- build.zig | 18 ++++++++++++++ examples/mustache/mustache.zig | 2 +- src/mustache.zig | 35 ++++++++++++++++++++------- src/tests/test_mustache.zig | 44 ++++++++++++++++++++++++++++++++++ src/tests/testpartial.html | 1 + src/tests/testtemplate.html | 4 ++++ 6 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 src/tests/test_mustache.zig create mode 100644 src/tests/testpartial.html create mode 100644 src/tests/testtemplate.html diff --git a/build.zig b/build.zig index a368cbb..39d3dc4 100644 --- a/build.zig +++ b/build.zig @@ -128,6 +128,19 @@ pub fn build(b: *std.build.Builder) !void { const run_auth_tests = b.addRunArtifact(auth_tests); const install_auth_tests = b.addInstallArtifact(auth_tests, .{}); + // mustache tests + const mustache_tests = b.addTest(.{ + .name = "mustache_tests", + .root_source_file = .{ .path = "src/tests/test_mustache.zig" }, + .target = target, + .optimize = optimize, + }); + mustache_tests.linkLibrary(facil_dep.artifact("facil.io")); + mustache_tests.addModule("zap", zap_module); + + const run_mustache_tests = b.addRunArtifact(mustache_tests); + const install_mustache_tests = b.addInstallArtifact(mustache_tests, .{}); + // http paramters (qyery, body) tests const httpparams_tests = b.addTest(.{ .name = "http_params_tests", @@ -163,6 +176,10 @@ pub fn build(b: *std.build.Builder) !void { run_auth_test_step.dependOn(&run_auth_tests.step); run_auth_test_step.dependOn(&install_auth_tests.step); + const run_mustache_test_step = b.step("test-mustache", "Run mustache unit tests [REMOVE zig-cache!]"); + run_mustache_test_step.dependOn(&run_mustache_tests.step); + run_mustache_test_step.dependOn(&install_mustache_tests.step); + const run_httpparams_test_step = b.step("test-httpparams", "Run http param unit tests [REMOVE zig-cache!]"); run_httpparams_test_step.dependOn(&run_httpparams_tests.step); run_httpparams_test_step.dependOn(&install_httpparams_tests.step); @@ -176,6 +193,7 @@ pub fn build(b: *std.build.Builder) !void { // running the unit tests. const test_step = b.step("test", "Run unit tests"); test_step.dependOn(&run_auth_tests.step); + test_step.dependOn(&run_mustache_tests.step); test_step.dependOn(&run_httpparams_tests.step); test_step.dependOn(&run_sendfile_tests.step); diff --git a/examples/mustache/mustache.zig b/examples/mustache/mustache.zig index f28f92a..f60c8d8 100644 --- a/examples/mustache/mustache.zig +++ b/examples/mustache/mustache.zig @@ -3,7 +3,7 @@ const zap = @import("zap"); fn on_request(r: zap.SimpleRequest) void { const template = "{{=<< >>=}}* Users:\r\n<<#users>><>. <<& name>> (<>)\r\n<>\r\nNested: <<& nested.item >>."; - const p = zap.MustacheNew(template) catch return; + const p = zap.MustacheData(template) catch return; defer zap.MustacheFree(p); const User = struct { name: []const u8, diff --git a/src/mustache.zig b/src/mustache.zig index ea1f448..f285841 100644 --- a/src/mustache.zig +++ b/src/mustache.zig @@ -42,18 +42,14 @@ pub const MustacheError = error{ MUSTACHE_ERR_USER_ERROR, }; -// pub extern fn fiobj_mustache_load(filename: fio_str_info_s) ?*mustache_s; // pub extern fn fiobj_mustache_build2(dest: FIOBJ, mustache: ?*mustache_s, data: FIOBJ) FIOBJ; -pub fn MustacheNew(data: []const u8) MustacheError!*Mustache { +pub fn MustacheNew(load_args: MustacheLoadArgs) MustacheError!*Mustache { var err: mustache_error_en = undefined; - var args: MustacheLoadArgs = .{ - .filename = null, - .filename_len = 0, - .data = data.ptr, - .data_len = data.len, - .err = &err, - }; + + var args = load_args; + args.err = &err; + var ret = fiobj_mustache_new(args); switch (err) { 0 => return ret.?, @@ -70,6 +66,27 @@ pub fn MustacheNew(data: []const u8) MustacheError!*Mustache { 11 => return MustacheError.MUSTACHE_ERR_USER_ERROR, else => return MustacheError.MUSTACHE_ERR_UNKNOWN, } + return MustacheError.MUSTACHE_ERR_UNKNOWN; +} + +pub fn MustacheData(data: []const u8) MustacheError!*Mustache { + var err: mustache_error_en = undefined; + var args: MustacheLoadArgs = .{ .filename = null, .filename_len = 0, .data = data.ptr, .data_len = data.len, .err = &err }; + + return MustacheNew(args); +} + +pub fn MustacheLoad(filename: []const u8) MustacheError!*Mustache { + var err: mustache_error_en = undefined; + var args: MustacheLoadArgs = .{ + .filename = filename.ptr, + .filename_len = filename.len, + .data = null, + .data_len = 0, + .err = &err, + }; + + return MustacheNew(args); } // implement these: fiobj_mustache.c diff --git a/src/tests/test_mustache.zig b/src/tests/test_mustache.zig new file mode 100644 index 0000000..d5c9b6e --- /dev/null +++ b/src/tests/test_mustache.zig @@ -0,0 +1,44 @@ +const std = @import("std"); +const zap = @import("zap"); + +const User = struct { + name: []const u8, + id: isize, +}; + +const data = .{ + .users = [_]User{ + .{ + .name = "Rene", + .id = 1, + }, + .{ + .name = "Caro", + .id = 6, + }, + }, + .nested = .{ + .item = "nesting works", + }, +}; + +test "MustacheData" { + const template = "{{=<< >>=}}* Users:\n<<#users>><>. <<& name>> (<>)\n<>\nNested: <<& nested.item >>."; + const p = try zap.MustacheData(template); + defer zap.MustacheFree(p); + + const ret = zap.MustacheBuild(p, data); + defer ret.deinit(); + + try std.testing.expectEqualSlices(u8, "* Users:\n1. Rene (Rene)\n6. Caro (Caro)\nNested: nesting works.", ret.str().?); +} + +test "MustacheLoad" { + const p = try zap.MustacheLoad("./src/tests/testtemplate.html"); + defer zap.MustacheFree(p); + + const ret = zap.MustacheBuild(p, data); + defer ret.deinit(); + + try std.testing.expectEqualSlices(u8, "* Users:\n1. Rene (Rene)\n6. Caro (Caro)\nNested: nesting works.\n", ret.str().?); +} diff --git a/src/tests/testpartial.html b/src/tests/testpartial.html new file mode 100644 index 0000000..f52325c --- /dev/null +++ b/src/tests/testpartial.html @@ -0,0 +1 @@ +Nested: {{& nested.item }}. diff --git a/src/tests/testtemplate.html b/src/tests/testtemplate.html new file mode 100644 index 0000000..e44531c --- /dev/null +++ b/src/tests/testtemplate.html @@ -0,0 +1,4 @@ +{{=<< >>=}}* Users: +<<#users>><>. <<& name>> (<>) +<> +<<>testpartial.html>>