Skip to content

Instantly share code, notes, and snippets.

@Zolomon
Last active February 10, 2016 10:21
Show Gist options
  • Save Zolomon/724d5ad1e9427036258d to your computer and use it in GitHub Desktop.
Save Zolomon/724d5ad1e9427036258d to your computer and use it in GitHub Desktop.
Newsletter Generator
namespace MailGenerator
module Generator =
open System.IO
open System.Text.RegularExpressions
open FSharp.Data
open FSharp.Data.JsonExtensions
type Template = string * string -> string
type State =
{ mutable BasePath : string
mutable CssPath : string
mutable PostPath : string
mutable TemplatePath : string
mutable LayoutPath : string
mutable BuildPath : string }
let SetupPaths basePath =
{ BasePath = basePath
CssPath = Path.Combine(basePath, "css\\")
TemplatePath = Path.Combine(basePath, "templates\\")
PostPath = Path.Combine(basePath, "posts\\")
LayoutPath = Path.Combine(basePath, "layout\\")
BuildPath = Path.Combine(basePath, "build\\") }
let mutable Context = SetupPaths(Directory.GetCurrentDirectory())
let CreateBuildDir() =
if not (File.Exists(Context.BuildPath)) then Directory.CreateDirectory(Context.BuildPath) |> ignore
let LoadTemplate path = File.ReadAllLines(path) |> String.concat "\n"
let RenderPost(post : JsonValue) =
let mutable html = LoadTemplate(Path.Combine(Context.TemplatePath, post?template.AsString()))
post?content.Properties
|> Array.toList
|> List.map (fun (key, value) -> html <- html.Replace("{{content " + key + "}}", value.AsString()))
|> ignore
html
let GeneratePosts _ =
let json =
JsonValue.Parse(File.ReadAllLines(Path.Combine(Context.PostPath, "posts.json")) |> String.concat "\n")
json?posts.AsArray()
|> Array.toList
|> List.map (fun (post : JsonValue) -> RenderPost post)
|> String.concat "\n"
let Templates =
[ ("{{css (.+)}}", LoadTemplate)
("{{template (.+)}}", LoadTemplate)
("{{posts}}", GeneratePosts) ]
let ExpandTemplate (pattern, template) line =
if Regex.IsMatch(line, pattern) then
let path = Regex.Match(line, pattern).Groups.[1].Value
Some(template (Path.Combine(Context.TemplatePath, path)))
else None
let TemplateIdentity (result : Option<string>) line =
if result.IsNone then line
else (result.Value)
let rec RecursiveTemplateConstructor line =
let result =
Templates
|> List.map (fun pt -> ExpandTemplate pt line)
|> List.choose id
if result.Length = 0 then line
else
result.Head.Split([| '\n' |])
|> Array.toList
|> List.map (fun x -> RecursiveTemplateConstructor x)
|> String.concat "\n"
let CreateNewsletter layoutFile =
File.ReadAllLines(Path.Combine(Context.LayoutPath, layoutFile))
|> Seq.map RecursiveTemplateConstructor
|> String.concat "\n"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment