Skip to content

Commit

Permalink
Change provider api to do extension lookup on its own. Add benchmarks…
Browse files Browse the repository at this point in the history
… for provider caching vs. compile_at_init caching
  • Loading branch information
lsegal committed Jun 11, 2008
1 parent 2584af1 commit da95363
Show file tree
Hide file tree
Showing 11 changed files with 141 additions and 46 deletions.
20 changes: 20 additions & 0 deletions benchmarks/run-caching.rb
@@ -0,0 +1,20 @@
require "benchmark"
require File.dirname(__FILE__) + '/../lib/templater'

Templater.register_template_path File.dirname(__FILE__) + '/../examples/example2'

TESTS = 100

Benchmark.bmbm do |b|
b.report("no-cache") do
Templater.caching = false
t = Templater('treate/html/readme').new
TESTS.times { t.run }
end

b.report("cache ") do
Templater.caching = true
t = Templater('treate/html/readme').new
TESTS.times { t.run }
end
end
2 changes: 1 addition & 1 deletion examples/example2/run.rb
Expand Up @@ -2,4 +2,4 @@

Templater.register_template_path File.dirname(__FILE__)

puts Templater(:treate, ARGV[0]||'html').run
puts Templater(:treate, ARGV[0]||'html').run
6 changes: 6 additions & 0 deletions lib/templater.rb
@@ -1,13 +1,15 @@
require 'rubygems'

module Templater
Version = '0.1.0'
Root = File.dirname(__FILE__) + '/templater'

module SectionProviders
autoload :ERBProvider, Root + '/providers/erb'
autoload :FileProvider, Root + '/providers/file'
autoload :HamlProvider, Root + '/providers/haml'
autoload :MarkabyProvider, Root + '/providers/markaby'
autoload :TemplateProvider, Root + '/providers/template'
end

autoload :Template, Root + '/template'
Expand All @@ -18,4 +20,8 @@ module SectionProviders
require File.join(Templater::Root, path)
end

module Templater::SectionProviders
register_provider TemplateProvider, ERBProvider, HamlProvider, FileProvider
end


2 changes: 1 addition & 1 deletion lib/templater/main.rb
Expand Up @@ -102,7 +102,7 @@ def load_setup_rb(full_path, path, mod = nil)
end

def template_mod_name(full_path)
'Template_' + full_path.gsub(File::SEPARATOR, '_')
'Template_' + absolutize_path(full_path).gsub(File::SEPARATOR, '_')
end
end
end
Expand Down
19 changes: 9 additions & 10 deletions lib/templater/providers/erb.rb
@@ -1,20 +1,19 @@
module Templater
module SectionProviders
class ERBProvider < SectionProvider
def initialize(content, owner)
EXTENSIONS = ['.erb']

def initialize(full_path, owner)
super

require 'erb'
erb = ERB.new(content, nil, '<>')
instance_eval "def render(locals = nil); #{erb.src} end"
end

def method_missing(meth, *args, &block)
if owner.respond_to?(meth)
owner.send(meth, *args, &block)
else
super
end
instance_eval <<-eof
def render(locals = nil)
eval(locals.map {|k,v| "\#{k} = \#{v.inspect}" }.join(';')) if locals
#{erb.src}
end
eof
end
end
end
Expand Down
2 changes: 2 additions & 0 deletions lib/templater/providers/file.rb
@@ -1,6 +1,8 @@
module Templater
module SectionProviders
class FileProvider < SectionProvider
EXTENSIONS = ['.txt', '.html', '']

def render(locals = nil); content end
end
end
Expand Down
4 changes: 3 additions & 1 deletion lib/templater/providers/haml.rb
@@ -1,7 +1,9 @@
module Templater
module SectionProviders
class HamlProvider < SectionProvider
def initialize(content, owner)
EXTENSIONS = ['.haml']

def initialize(full_path, owner)
super

require 'haml'
Expand Down
2 changes: 1 addition & 1 deletion lib/templater/providers/markaby.rb
@@ -1,7 +1,7 @@
module Templater
module SectionProviders
class MarkabyProvider < SectionProvider

EXTENSIONS = ['.mab']
end
end
end
59 changes: 38 additions & 21 deletions lib/templater/providers/section_provider.rb
Expand Up @@ -2,42 +2,59 @@ module Templater
module SectionProviders
class << self
def providers
@providers ||= {}
@providers ||= []
end

def register_provider(prov)
prov.each do |k, v|
providers.update(k.to_sym => v)
end
end

def default_provider(provider = nil)
if provider
@default_provider = provider
else
@default_provider
end
def register_provider(*provs)
providers.push(*provs)
end
end

class SectionProvider
attr_accessor :owner, :content

EXTENSIONS = []

# You don't need to override this method unless
# you need custom functionality beyond checking
# if a file exists under one of the possible file
# extensions.
#
# @return [String, nil] The full pathname
def self.provides?(basename)
self.const_get("EXTENSIONS").any? do |ext|
path = basename + ext
return path if path_suitable?(path)
end
nil
end

# Override this if you want to provide another
# mechanism to detect that the path is suitable
# for use. Default just checks File.file?(full_path)
def self.path_suitable?(full_path)
File.file?(full_path)
end

# @abstract
def render(locals = {}, &block)
raise NotImplementedError, "abstract class"
end

def initialize(content, owner = nil)
def initialize(full_path, owner = nil)
self.owner = owner
self.content = content
self.content = File.read(full_path)
end

def inspect; "#<%s:0x%s>" % [self.class.to_s.split('::').last, object_id.to_s(16)] end

def method_missing(meth, *args, &block)
if owner.respond_to?(meth)
owner.send(meth, *args, &block)
else
super
end
end
end

register_provider :erb => ERBProvider,
:haml => HamlProvider,
:markaby => MarkabyProvider,
:txt => FileProvider
default_provider FileProvider
end
end
24 changes: 24 additions & 0 deletions lib/templater/providers/template.rb
@@ -0,0 +1,24 @@
module Templater
module SectionProviders
class TemplateProvider < SectionProvider
EXTENSIONS = ['']

def self.path_suitable?(full_path) File.directory?(full_path) end

def initialize(full_path, owner)
self.owner = owner
owner.template_paths.each do |template_path|
if full_path.index(template_path) == 0
path = full_path[template_path..-1]
@template = Templater(owner.path, path).new(owner.options)
end
end
raise ArgumentError, "no template at `#{full_path}'" unless @template
end

def render(locals = {}, &block)
@template.run(locals)
end
end
end
end
47 changes: 36 additions & 11 deletions lib/templater/template.rb
Expand Up @@ -14,6 +14,7 @@ class << obj; extend ClassMethods end
obj.options = opts
#obj.sections(*sections)
obj.init(&block)
obj.compile_sections if Templater.caching
obj
end
end
Expand Down Expand Up @@ -56,6 +57,28 @@ def sections(*new_sections)
end
end

def compile_sections(list = sections)
list.map! do |section|
case section
when Array
compile_sections(section)
when String
find_section_provider(section)
when Symbol
if respond_to?(section)
section
else
Templater(path, section).new(options)
end
when Module
section.new(options)
else
section
end
end
list
end

def init(&block); end

def run(opts = {}, &block)
Expand Down Expand Up @@ -114,12 +137,15 @@ def render(section, &block)
if respond_to? section
send(section, &block)
else
Templater(path, section).new(options).run(&block)
@providers[section.to_s] ||= Templater(path, section).new(options)
@providers[section.to_s].run(&block)
end
when Template
section.run(&block)
when Module
section.new(*args).run(&block)
section.new(options).run(&block)
when SectionProviders::SectionProvider
section.render(&block)
else
raise ArgumentError, "invalid section #{section.inspect}"
end
Expand All @@ -133,18 +159,17 @@ def find_section_provider(section)
@providers ||= {}
return @providers[section] if @providers[section]

filename, provider = section, nil
if find_template(section)
provider = SectionProviders.default_provider
else
SectionProviders.providers.each do |ext, prov|
filename = "#{section}.#{ext}"
break provider = prov if find_template(filename)
filename, provider = nil, nil
template_paths.each do |template_path|
SectionProviders.providers.each do |prov|
filename = prov.provides?(File.join(template_path, section))
break provider = prov if filename
end
break if provider && filename
end

raise ArgumentError, "missing section `#{section}'" if !provider
@providers[section] = provider.new(template_contents(filename), self)
raise ArgumentError, "missing section `#{section}'" if !provider
@providers[section.to_s] = provider.new(filename, self)
end

def find_template(filename)
Expand Down

0 comments on commit da95363

Please sign in to comment.