«Tilde, a static blog generator

tilde

Huh?

Tilde uses Razor for templating, FSharp.Formatting for Markdown and F# highlighting and Prettify for highlighting other languages. The directory layout is quite similar to Jekyll check out my (quite hacked together!) blog source here.

Posts are written in Markdown and are post-processed as Razor templates. Heres an example of the top of this page

@{
  Layout = "Post";
  Title = "Tilde, a static blog generator";
  Description = "A Static blog generator using Razor and FSharp.Formatting";
  Tags = new string[] {"F#", "Blogging", "FSharp.Formatting", "Razor"};
  Meta["CustomEntry"] = "Woo";
}

![tilde](/content/images/tilde2.png)
## Huh?

Tilde uses [Razor](https://github.com/Antaris/RazorEngine) for templating, [FSharp.Formatting](https://github.com/tpetricek/FSharp.Formatting)

All the usual Markdown syntax should work, aswell as anything supported by RazorEngine for example typing @DateTime.Now would produce 11/07/2013 11:55:17 PM this allows for some pretty awesome compile time hackery for example the following chunk of code written anywhere in the blog post:

@{
  var client = new System.Net.WebClient();
  var tracks = client.DownloadString("http://ws.audioscrobbler.com/1.0/user/ike_x/recenttracks.rss");
  var rgx = new System.Text.RegularExpressions.Regex("<title>(.*?)</title>");
  @rgx.Matches(tracks)[1].Groups[1];
}

Alice Cooper – School's Out

Should print out the last song I was listening to when this blog was last compiled. (Hopefully above!).

Unfortunately at the moment the markdown will be interpreted inside @{ } so anything that would be interpreted as markdown will corrupt the code. Also since this evaluated every re-compile of the site depending on what you have this could increase page compile times rapidly.

FSharp.Formatting and Syntax highlighting

FSharp.Formatting, allows us to export F# snippets with syntax highlighting and tooltips, try hovering your mouse over the code below.

 1: 
 2: 
 3: 
 4: 
 5: 
 6: 
 7: 
 8: 
 9: 
10: 
11: 
12: 
13: 
14: 
15: 
16: 
17: 
18: 
19: 
20: 
21: 
/// Fibonacci Number formula
let rec fib n =
    match n with
    | 0 | 1 -> n
    | _ -> fib (n - 1) + fib (n - 2)

/// Another approach - a lazy infinite sequence of Fibonacci numbers
let fibSeq = Seq.unfold (fun (a,b) -> Some(a+b, (b, a+b))) (0,1)

// Print even fibs
[1 .. 10]
|> List.map     fib
|> List.filter  (fun n -> (n % 2) = 0)
|> printList

// Same thing, using a list expression
[ for i in 1..10 do
    let r = fib i
    if r % 2 = 0 then yield r ]
|> printList
// taken from: http://en.wikipedia.org/wiki/F_Sharp_(programming_language)#Examples
val fib : n:int -> int

Full name: Example.fib


 Fibonacci Number formula
val n : int
val fibSeq : seq<int>

Full name: Example.fibSeq


 Another approach - a lazy infinite sequence of Fibonacci numbers
module Seq

from Microsoft.FSharp.Collections
val unfold : generator:('State -> ('T * 'State) option) -> state:'State -> seq<'T>

Full name: Microsoft.FSharp.Collections.Seq.unfold
val a : int
val b : int
union case Option.Some: 'T -> Option<'T>
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of 'T * 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val map : mapping:('T -> 'U) -> list:'T list -> 'U list

Full name: Microsoft.FSharp.Collections.List.map
val filter : predicate:('T -> bool) -> list:'T list -> 'T list

Full name: Microsoft.FSharp.Collections.List.filter
val i : int
val r : int

F# Blocks begin with the normal markdown 4+ spaces in then a name field followed by the code, for example the code above.

[name=example.fsx]
/// Fibonacci Number formula
let rec fib n =
    match n with
    | 0 | 1 -> n
    | _ -> fib (n - 1) + fib (n - 2)

Unfortunately :( there is no tooltips for other languages.

require "sinatra"

class Example < Sinatra::Base
  get "/" do  
    "Why hello there!"
  end
end

Which was created with the following

[lang=ruby]
require "sinatra"

class Example < Sinatra::Base
  get "/" do  
    "Why hello there!"
  end
end

Site, Posts, Templating, Partials

Tilde uses templates from the layouts folder, for example my blog has [Post.cshtml](https://github.com/aktowns/blog.ashleytowns.id.au/blob/master/layouts/Post.cshtml) which references Default.cshtml and includes GA.cshtml as a partial so the render chain looks something like this:

[Markdown Post] -> (Post.cshtml -> GA.cshtml) -> Default.cshtml

Templates follow the same general Razor rules, and contain a @RenderBody to fill out the contents. @RenderPart is used to render partials, for my blog I have disqus and google analytics being included this way.

Variables are scoped per file for example a variable defined here cannot be seen by the template i specified at the top. Except for the ViewBag and the following Title, Description, Tags, Meta which are available from the template and from other pages under Site.Posts.

Meta is a dictionary which can include any custom variables you want the template to be able to access.

Site is available to templates and at the moment contains just Posts which is an array of all the rendered blog posts and the properties above. Site can be accessed from blog posts but depending on the current compile order can be unpredictable. An example of a page using this is index.cshtml from this blog.

Theres probably a lot more to write, but my head is killing me. This was hacked together over a friday night i'd imagine its filled with bugs and other nice things. Its available here at github. I'm using it to generate this blog!




comments powered by Disqus G+ Author linking