changeset 17:0214b1b5f5eb draft

added amber and gcss compilers
author zaitsev.serge
date Sat, 29 Aug 2015 15:47:16 +0000
parents be58ace6edae
children ae3116ea938b
files testdata/sugar/.test/index.html testdata/sugar/.test/styles.css testdata/sugar/index.amber testdata/sugar/styles.gcss zs.go zs_test.go
diffstat 6 files changed, 103 insertions(+), 22 deletions(-) [+]
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testdata/sugar/.test/index.html	Sat Aug 29 15:47:16 2015 +0000
@@ -0,0 +1,5 @@
+<html>
+	<body>
+		<p>Hello world</p>
+	</body>
+</html>
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testdata/sugar/.test/styles.css	Sat Aug 29 15:47:16 2015 +0000
@@ -0,0 +1,1 @@
+body{font:100% Helvetica, sans-serif;color:blue;}
\ No newline at end of file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testdata/sugar/index.amber	Sat Aug 29 15:47:16 2015 +0000
@@ -0,0 +1,3 @@
+html
+	body
+		p Hello world
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/testdata/sugar/styles.gcss	Sat Aug 29 15:47:16 2015 +0000
@@ -0,0 +1,6 @@
+$base-font: Helvetica, sans-serif
+$main-color: blue
+
+body
+  font: 100% $base-font
+  color: $main-color
--- a/zs.go	Sat Aug 29 13:28:15 2015 +0000
+++ b/zs.go	Sat Aug 29 15:47:16 2015 +0000
@@ -13,7 +13,9 @@
 	"strings"
 	"time"
 
+	"github.com/eknkc/amber"
 	"github.com/russross/blackfriday"
+	"github.com/yosssi/gcss"
 )
 
 const (
@@ -21,8 +23,12 @@
 	PUBDIR = ".pub"
 )
 
-type EvalFn func(args []string, vars map[string]string) (string, error)
+type Vars map[string]string
 
+type EvalFn func(args []string, vars Vars) (string, error)
+
+// Splits a string in exactly two parts by delimiter
+// If no delimiter is found - the second string is be empty
 func split2(s, delim string) (string, string) {
 	parts := strings.SplitN(s, delim, 2)
 	if len(parts) == 2 {
@@ -32,16 +38,22 @@
 	}
 }
 
-func md(path, s string) (map[string]string, string) {
+// Parses markdown content. Returns parsed header variables and content
+func md(path string) (Vars, string, error) {
+	b, err := ioutil.ReadFile(path)
+	if err != nil {
+		return nil, "", err
+	}
+	s := string(b)
 	url := path[:len(path)-len(filepath.Ext(path))] + ".html"
-	v := map[string]string{
+	v := Vars{
 		"file":   path,
 		"url":    url,
 		"output": filepath.Join(PUBDIR, url),
 		"layout": "index.html",
 	}
 	if strings.Index(s, "\n\n") == -1 {
-		return map[string]string{}, s
+		return Vars{}, s, nil
 	}
 	header, body := split2(s, "\n\n")
 	for _, line := range strings.Split(header, "\n") {
@@ -51,10 +63,10 @@
 	if strings.HasPrefix(v["url"], "./") {
 		v["url"] = v["url"][2:]
 	}
-	return v, body
+	return v, body, nil
 }
 
-func render(s string, vars map[string]string, eval EvalFn) (string, error) {
+func render(s string, vars Vars, eval EvalFn) (string, error) {
 	delim_open := "{{"
 	delim_close := "}}"
 
@@ -87,7 +99,8 @@
 	}
 }
 
-func env(vars map[string]string) []string {
+// Converts zs markdown variables into environment variables
+func env(vars Vars) []string {
 	env := []string{"ZS=" + os.Args[0], "ZS_OUTDIR=" + PUBDIR}
 	env = append(env, os.Environ()...)
 	if vars != nil {
@@ -98,7 +111,9 @@
 	return env
 }
 
-func run(cmd string, args []string, vars map[string]string, output io.Writer) error {
+// Runs command with given arguments and variables, intercepts stderr and
+// redirects stdout into the given writer
+func run(cmd string, args []string, vars Vars, output io.Writer) error {
 	var errbuf bytes.Buffer
 	c := exec.Command(cmd, args...)
 	c.Env = env(vars)
@@ -117,7 +132,7 @@
 	return nil
 }
 
-func eval(cmd []string, vars map[string]string) (string, error) {
+func eval(cmd []string, vars Vars) (string, error) {
 	outbuf := bytes.NewBuffer(nil)
 	err := run(path.Join(ZSDIR, cmd[0]), cmd[1:], vars, outbuf)
 	if err != nil {
@@ -135,11 +150,10 @@
 }
 
 func buildMarkdown(path string) error {
-	b, err := ioutil.ReadFile(path)
+	v, body, err := md(path)
 	if err != nil {
 		return err
 	}
-	v, body := md(path, string(b))
 	content, err := render(body, v, eval)
 	if err != nil {
 		return err
@@ -148,7 +162,7 @@
 	return buildPlain(filepath.Join(ZSDIR, v["layout"]), v)
 }
 
-func buildPlain(path string, vars map[string]string) error {
+func buildPlain(path string, vars Vars) error {
 	b, err := ioutil.ReadFile(path)
 	if err != nil {
 		return err
@@ -168,6 +182,45 @@
 	return nil
 }
 
+func buildGCSS(path string) error {
+	f, err := os.Open(path)
+	if err != nil {
+		return err
+	}
+	s := strings.TrimSuffix(path, ".gcss") + ".css"
+	log.Println(s)
+	css, err := os.Create(filepath.Join(PUBDIR, s))
+	if err != nil {
+		return err
+	}
+
+	defer f.Close()
+	defer css.Close()
+
+	_, err = gcss.Compile(css, f)
+	return err
+}
+
+func buildAmber(path string, vars Vars) error {
+	a := amber.New()
+	err := a.ParseFile(path)
+	if err != nil {
+		return err
+	}
+	t, err := a.Compile()
+	if err != nil {
+		return err
+	}
+	//amber.FuncMap = amber.FuncMap
+	s := strings.TrimSuffix(path, ".amber") + ".html"
+	f, err := os.Create(filepath.Join(PUBDIR, s))
+	if err != nil {
+		return err
+	}
+	defer f.Close()
+	return t.Execute(f, vars)
+}
+
 func copyFile(path string) (err error) {
 	var in, out *os.File
 	if in, err = os.Open(path); err == nil {
@@ -202,10 +255,17 @@
 				}
 				ext := filepath.Ext(path)
 				if ext == ".md" || ext == ".mkd" {
-					log.Println("mkd: ", path)
+					log.Println("md: ", path)
 					return buildMarkdown(path)
 				} else if ext == ".html" || ext == ".xml" {
-					return buildPlain(path, map[string]string{})
+					log.Println("html: ", path)
+					return buildPlain(path, Vars{})
+				} else if ext == ".amber" {
+					log.Println("html: ", path)
+					return buildAmber(path, Vars{})
+				} else if ext == ".gcss" {
+					log.Println("css: ", path)
+					return buildGCSS(path)
 				} else {
 					log.Println("raw: ", path)
 					return copyFile(path)
@@ -246,8 +306,7 @@
 			log.Println("ERROR: filename expected")
 			return
 		}
-		if b, err := ioutil.ReadFile(args[0]); err == nil {
-			vars, _ := md(args[0], string(b))
+		if vars, _, err := md(args[0]); err == nil {
 			if len(args) > 1 {
 				for _, a := range args[1:] {
 					fmt.Println(vars[a])
@@ -261,7 +320,7 @@
 			log.Println(err)
 		}
 	default:
-		err := run(path.Join(ZSDIR, cmd), args, map[string]string{}, os.Stdout)
+		err := run(path.Join(ZSDIR, cmd), args, Vars{}, os.Stdout)
 		if err != nil {
 			log.Println(err)
 		}
--- a/zs_test.go	Sat Aug 29 13:28:15 2015 +0000
+++ b/zs_test.go	Sat Aug 29 15:47:16 2015 +0000
@@ -3,6 +3,7 @@
 import (
 	"bytes"
 	"fmt"
+	"io/ioutil"
 	"log"
 	"os"
 	"os/exec"
@@ -31,14 +32,20 @@
 	}
 }
 
+func tmpfile(path, s string) string {
+	ioutil.WriteFile(path, []byte(s), 0644)
+	return path
+}
+
 func TestMD(t *testing.T) {
-	v, body := md("foo.md", `
+	defer os.Remove("foo.md")
+	v, body, _ := md(tmpfile("foo.md", `
 	title: Hello, world!
 	keywords: foo, bar, baz
 	empty:
 	bayan: [:|||:]
 
-this: is a content`)
+this: is a content`))
 	if v["title"] != "Hello, world!" {
 		t.Error()
 	}
@@ -56,20 +63,20 @@
 	}
 
 	// Test empty md
-	v, body = md("foo.md", "")
+	v, body, _ = md(tmpfile("foo.md", ""))
 	if len(v) != 0 || len(body) != 0 {
 		t.Error(v, body)
 	}
 
 	// Test empty header
-	v, body = md("foo.md", "Hello")
+	v, body, _ = md(tmpfile("foo.md", "Hello"))
 	if len(v) != 0 || body != "Hello" {
 		t.Error(v, body)
 	}
 }
 
 func TestRender(t *testing.T) {
-	eval := func(a []string, vars map[string]string) (string, error) {
+	eval := func(a []string, vars Vars) (string, error) {
 		return "hello", nil
 	}
 	vars := map[string]string{"foo": "bar"}