interblah.net » conflagration over configuration
Vanilla.rb is the software powering this site. It's a sort-of wiki/bliki thing, based on vanilla.
Here's the introductory blog post: introducing-vanilla-rb.
It's developed on github, and has a lighthouse bug tracker. At the moment it's not very well documented, since I'm exploring how the concept might work and the internals are subject to change. However, please do play around with it.
Here's the tutorial (helpfully included from vanilla-rb-tutorial).
Basic Concepts
Every piece of information displayed here is stored as a snip. Snips, within their contents, can also reference other snips.
For example, consider the snip tutorial-basic-snip-inclusion:
This is a snip, which includes another {link_to snip}: {tutorial-another-snip}
is rendered into:
This is a snip, which includes another snip: this is another snip!
Notice the use of curly brackets to reference one snip from inside another. Vanilla.rb finds these references to snips, then renders that snip and replaces it in the first snip. Neat!
Renderers
The way that a snip is rendered depends on whether or not it has a render_as attribute set. For instance, the render_as property of this snip (vanilla-rb) is "Markdown". This means that the content of this snip will be passed through Vanilla::Renderers::Markdown before it is then rendered to the page. There are several different renders provided by Vanilla.rb at the moment:
- Markdown - as described above
- Textile - which performs similarly for Textile. This means that you can mix how you write the content of snips!
- Raw - which simply returns the content of the snip, as-is. If you attach a
.rawextension to this url, you'll see it in action - Bold - simply wraps the content in bold. It's a demo, essentially.
- Erb - passes the snip contents through Ruby's
Erblibrary. It also makes some information available for use by ruby code within the snip's contents - Ruby - parses the snips content as Ruby itself.
It's using this last renderer that a second concept of Vanilla is implemented - dynasnips.
Dynasnips
Because the curly braces simply cause a snip to be rendered, we can use this in conjunction with the Ruby renderer to run actual code. For instance, in the snip above:
This is a snip, which includes another {link_to snip}: {tutorial-another-snip}
we can see a reference to the link_to snip - {link_to snip}.
Lets look at the raw content of link_to:
LinkTo
As you can see, it simply refers to the Ruby class LinkTo, which is contained within the vanilla-rb codebase. When the Ruby renderer is called, expects the given code to evaulate to a Ruby class. It then instantiates the class, and calls a handle method on the instance, passing it any other arguments from the snip inclusion. So, in the case of {link_to snip}, the only argument is snip.
Vanilla.rb includes a number of dynasnips by default. Here are a couple:
rand, which generates a random number (a silly demo really); rand, or an example: 24link_to, to produce a link to another snipkind, which selects and renders sets of snips based on theirkindattribute (this is how the blog is currently implemented)raw, which displays the raw contents of a snipedit, which implements the editorindex, which shows all of the available snips: indexlighthouse_ticket, which links to an issue on lighthouseapp.com; example - Ticket 1- ... and several others.
While dynasnip classes can be provided as part of the vanilla codebase, it's envisioned that much of these will be created by end users in their own sites, either by refering to local classes, or defining the classes directly as the content. Here's an example of that, as the raw content of hello_world:
class HelloWorld
# although the name doesn't need to match the snip name,
# it's simple to follow that convention where appropriate
def handle(name=nil)
if name
"Hey #{name} - Hello World!"
else
"Hello World!"
end
end
# note that this code must evaluate to a class. One way of achieving that is by
# putting 'self' at the end of the class definition.
self
end
# Another way is by referring to the class at the end of the content. Either works fine.
HelloWorld
which, when rendered, gives:
Hello World!
Note that the handle method can take one (optional) argument. Lets try including it with {hello_world Dave}:
Hey Dave - Hello World!
Anyway - that should be enough to get you started.