rtomayko/tilt — pull request #187 by judofyr (2013-05-01 20:44:36+00:00)
Title: Lazy require, Tilt::Mapping, metadata and more

**NOTE**: Please don't merge this yet. I'm just putting it out here for code review.

There's various changes that I want to add to Tilt 2.0:

**Tilt::Mapping**: There's now an object representing the mapping. `Tilt.new` (and friends) are now just shortcuts for `Tilt.default_mapping.new` (and similar). This functionality will also now replace Tilt.prefer. Instead of globally defining which template classes you want, you should just create your own mapping-object:

```ruby
mapping = Tilt::Mapping.new
mapping.register(Tilt::RedcarpetTemplate, 'md')
```

I hope that users of Tilt (e.g. web frameworks) will allow the end user to set mapping-object, and also use the Mapping-API if they need their own mapping-logic.

**Lazy registering**: I've completely removed `initialize_template_engine` in favor of `register_lazy`:

```ruby
# tilt.rb
module Tilt
register_lazy :ERBTemplate, 'tilt/erb', 'erb', 'rhtml'
end

# tilt/erb.rb
require 'tilt/template'
require 'erb'

module Tilt
# ERB template implementation. See:
# http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html
class ERBTemplate < Template
...
end
end
```

Notice that it's now impossible to get a Tilt::*Template-class without the proper dependencies are actually present. The lazy registering will store the class name and the path, and calling `Tilt['erb']` will require the path and then constantize the class name.

Pros:

* Less code (removed the whole engine_initialized-thingie)
* Template-classes are always ready to be used
* We can now define (external) template engines in the same way

Cons:

* We can't share code between Template-classes that has separate dependencies

**metadata**:

I've added Template.metadata and Template#metadata. This is just a Hash the template class can use to pass information to the caller (like default_mime_type and allows_script).

**Refactored the precompiling**:

I've introduced three new methods:

```ruby
def precompile_template
raise NotImplementedError
end

def precompile_preamble
''
end

def precompile_postamble
''
end
```

These works just like the previous precompile**d** one, but they don't take an argument. The local variable-preamble is now always added, regardless of whether you call super in precompile_preamble or not. This simplifies the code for template classes.

**Minimal changes to existing template classes**:

To help with the chicken-egg-problem I'm going to make it *very* easy to create template classes that are compatible with both Tilt 1.4 and 2.0. The goal is that template engines can support both 1.4 and 2.0 with a single template class (I'm going to document this). That way it's easier for users of Tilt to go over to Tilt 2.0. When no-one are using Tilt 1.4 anymore, template engines can drop support for it.

**Known issues**:

* We need better tests for Mapping (I want to switch to MiniTest before I do this)
* We need to add the thread-warning again
* The lazy loader is very ugly now (eval)

**Thoughts?**

/cc @rkh @rtomayko @josh @ujifgc