ERB and Builder template engines shouldn't be so heavily wir


#1

Problem:

  1. ERB and Builder template engines are heavily wired in
    ActionView::Base
  2. Should be optional. If we use different engine - why load all their
    stuff if not needed?
  3. There are template engines which expect files in their own locations
    and cache them in their own way. For instance a template engine may
    store templates in a database. These engines don’t need any central
    source loader of files which they don’t need, moreover of files which
    don’t exist. Files, which expects a file per an action.

Why is it problem for me?

I wrote a ViewController templating engine. ViewController is similar to
Controller - is just one file, a class, which controls views of all
actions.
It uses yaml data files from which loads data. It is real push-style
template engine.

app/views/foo/foo_view_controller.vcrb

class FooViewController < ActiveView::ViewController::Base

def index
return get( :body ) do |body|
body.title = ‘Homepage’
body.time = Time.now
body.table do |table|
@people.each do |person|
table << get( :row, :name=>person.name,
:surname=>person.sn )
end
end
end
end

def list
return get( :body, :title=>‘under construction’, :time=>Time.now )
end

end

Request:

More modularization. Template engines should be independent and
optional,
even ERB and Builder. Template engines should do source loading and
caching itself.

Solution:

  1. The ActionView::Base should work just like a register / dispatcher
    for
    template engines.

  2. Every template engine (including ERB and Builder) should be placed
    inside the vendor directory.

  3. Every template engine should have a base class
    ActionView::Engines::EngineName with these methods:

self::template_exists?( render_options={} )
self::type # return :rhtml, :rxml, :vcrb, etc.
initialize( action_view )
render( render_options={}, local_assigns={} )

  1. Only used template engines will be then registered in environment.rb:

ActionView::Base.register_template_handler( ‘erb’ )

does: require( “vendor/erb.rb” )

ActionView::Base.register_template_handler( ‘view_controller’ )

does: require( “vendor/view_controller.rb” )

  1. Each required file from vendor registers itself into
    @@template_handlers.

@@template_handlers[ActionView::Handlers::Erb.type] =
ActionView::Handlers::Erb

@@template_handlers[ActionView::Handlers::ViewController.type] =
ActionView::Handlers::ViewController

  1. If a request comes, the ActionView::Base will ask all registered
    template handlers (in @@template_handlers), if the template specified by
    render_options exists. If a handler responds true, the Base would create
    an instance of that handler and call it’s render method. That’s all.
    Every other stuff should be done by the handler.

How to do it:

  1. Modularize ERB and Builder.

  2. Don’t pick the handler by the file extension, instead pass the
    render_options to all registered handler’s template_exists? and
    check if some handler responds true.

  3. File rendering would be processed this way (from ActionView::Base):

def render_file( render_options={}, local_assigns={} )
@@template_handlers.each_value do |handler_class|
if handler_class::template_exists?( render_options )
return handler_class.new( render_options, local_assigns )
end
end
raise ‘no handler is able to render the file!’
end

Inline rendering would be processed this way (from ActionView::Base):

def render_inline( render_options={} )
handler = @@template_handlers[ render_options[:type] ]
return handler.render( render_options )
end

  1. layout.rb would pass the ‘content_for_layout’ variable to
    local_assigns of the render method (no special injecting into template).

  2. rescue.rb shouldn’t call render_file with a special file path.
    Instead it should call render() with an option :error=>anError. This
    would allow a handler to display the error. Then a handler which
    responds to true will be used to display the error. Not only ERB can do
    it.

  3. For backward compatibility reasons and reasons when no other template
    handler is registered, ERB will be loaded defaultly.


I will public my ViewController after testing it a bit, I realized it is
really good :slight_smile:

Now I can run it only by hacking the ActionView::Base class but I don’t
want to do it, I want ActionView to be more modularized to allow this
normal way.

What do you think about it? If you want, I can get more into the
ActionPack’s code and work out the separation of ERB (with backward
compatibility, of course)

jan molic