Git Product home page Git Product logo

jefferson's Introduction

Jefferson

Jefferson is a tiny little "variable replacer" or more often called a "template engine".

Jefferson is mainly intended to process configuration files, particular in scenarios where various components must be configured independently to enable a single feature it is useful to be able to switch this on/off with a single config change.

$$#define ENABLE_FEATURE_FOO=true /$$
...
<component name="foo" active="$$ENABLE_FEATURE_FOO$$" />

$$#if ENABLE_FEATURE_FOO$$
<component name="foo_support" ... />
...
$$/if$$

It can also be useful to parameterize some configuration to avoid repeating it.

$$#define location(url)$$
   <location url="$$url$$" ... />
$$/define

$$location('www.example.com')$$
$$location('www.google.com')$$

Jefferson can also be used for more general template processing, e.g.

$$#if Today = Monday$$
   Hello $$#each Users['active']$$, how is $$Name.Capitalize()$$ on this fine Monday$$/each$$?
$$/if$$

Strings in between $$ signs are compiled to Linq expression trees, and the entire template itself is compiled as an expression tree, preserving type safety. Expressions are compiled relative to a context value, often called a model. Names are resolved by first looking for properties and fields of this context and otherwise seeing if these are dynamically declared (e.g. using a dictionary). Internally this uses an IVariableBinder which can be used to customize variable binding.

Further, as in other template engines, there is support for directives and the ability to define new directives. Provided directives are e.g.

$$#if …$$, $$#each …$$, $$#define .. /$$ and $$#let …$$.

We use this in configuration files for things like

  • $$if(IS_PROD) IncludeFile('foobar')$$
  • <plugin active='$$IS_DEV and Blah()$$' />
  • etc.

As output is abstracted through an IOutputWriter (and one that implements this using a TextWriter is provided) it is very easy to use this to output, say, directly to an HTTP output stream.

Documentation

See the wiki.

Project Overview

  • Jefferson.Core implements the core expression and replacement logic
  • Jefferson.Build provides some services for using Jefferson during build (needs documentation)
  • Jefferson.Tests hosts unit tests for all projects, currently
  • Jefferson.FileProcessing provides some out-of the box support for working with files and per-file scopes (needs documentation and tests)

Design philosophy:

  • directives are limited and kept simple to avoid e.g. config files becoming code (separation of concerns) - use e.g. Razor otherwise
  • expressions are simple (but powerful), so we stop at assignment, in fact = is an alias for ==
  • expression syntax follows C# but extends this, e.g. it adds a Perl like regex match =~, "overloads" && with and (as this is much nicer to use from xml) and more
  • if anything more complex is required, add a method to the context class (aka the model)
  • expressions are type safe
  • errors are descriptive, helpful and provide accurate source location information
  • the focus is runtime performance not compile performance

FAQ

Why did you create this?

I'm not a believer in creationism, this evolved from more humble beginnings and then just ... grew.

Is it fast?

It's fast as in things are compiled using Linq expression trees. Whether it's actually fast I don't know as I have not done performance tests just yet. Also, the focus is on runtime performance, not parsing peformance. With regards to parsing the focus has been to keep the parser relatively simple vs as performant as possible.

Is the API stable?

No. This is just an initial version and the API may change. In particular the area of how names are resolved is likely to be updated. So I don't guarantee any backwards compatibility at the moment.

Is it type safe?

Yes in the sense that values are typed and ultimately converted to string before emission to output.

Is there documentation?

Yes, see the wiki. There is some documentation in code and this will be improved over time.

What's with all the $$

The $$ was initially chosen as it conflicts least with existing file formats, in our use case. I don't think other syntaxes like {{...}} are necessarily any better.

Could this be used to run other syntaxes?

Not as it stands currently, but the actual template syntax parser could be extracted in theory, however, I have no interest in doing so at the moment.

What's the license?

Apache v2, see license.txt. Copyright Marcus van Houdt © 2015

jefferson's People

Contributors

mjvh80 avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.