tilt-2.0.1/0000755000004100000410000000000012322577445012531 5ustar www-datawww-datatilt-2.0.1/Rakefile0000644000004100000410000000515212322577445014201 0ustar www-datawww-datarequire 'bundler' Bundler.setup require 'rake/testtask' task :default => [:test] # SPECS ===================================================================== desc 'Run tests (default)' Rake::TestTask.new(:test) do |t| t.test_files = FileList['test/*_test.rb'] t.ruby_opts = ['-Itest'] t.ruby_opts << '-rubygems' if defined? Gem end # DOCUMENTATION ============================================================= require 'yard' YARD::Rake::YardocTask.new do |t| t.files = [ 'lib/tilt.rb', 'lib/tilt/mapping.rb', 'lib/tilt/template.rb', '-', '*.md', 'docs/*.md', ] t.options << '--no-private' << '--protected' << '-m' << 'markdown' << '--asset' << 'docs/common.css:css/common.css' end # PACKAGING ================================================================= begin require 'rubygems' rescue LoadError end if defined?(Gem) SPEC = eval(File.read('tilt.gemspec')) def package(ext='') "pkg/tilt-#{SPEC.version}" + ext end desc 'Build packages' task :package => %w[.gem .tar.gz].map {|e| package(e)} desc 'Build and install as local gem' task :install => package('.gem') do sh "gem install #{package('.gem')}" end directory 'pkg/' file package('.gem') => %w[pkg/ tilt.gemspec] + SPEC.files do |f| sh "gem build tilt.gemspec" mv File.basename(f.name), f.name end file package('.tar.gz') => %w[pkg/] + SPEC.files do |f| sh "git archive --format=tar HEAD | gzip > #{f.name}" end desc 'Upload gem and tar.gz distributables to rubyforge' task :release => [package('.gem'), package('.tar.gz')] do |t| sh <<-SH rubyforge add_release sinatra tilt #{SPEC.version} #{package('.gem')} && rubyforge add_file sinatra tilt #{SPEC.version} #{package('.tar.gz')} SH end end # GEMSPEC =================================================================== file 'tilt.gemspec' => FileList['{lib,test}/**','Rakefile'] do |f| # read version from tilt.rb version = File.read('lib/tilt.rb')[/VERSION = '(.*)'/] && $1 # read spec file and split out manifest section spec = File. read(f.name). sub(/s\.version\s*=\s*'.*'/, "s.version = '#{version}'") parts = spec.split(" # = MANIFEST =\n") # determine file list from git ls-files files = `git ls-files`. split("\n").sort.reject{ |file| file =~ /^\./ }. map{ |file| " #{file}" }.join("\n") # piece file back together and write... parts[1] = " s.files = %w[\n#{files}\n ]\n" spec = parts.join(" # = MANIFEST =\n") spec.sub!(/s.date = '.*'/, "s.date = '#{Time.now.strftime("%Y-%m-%d")}'") File.open(f.name, 'w') { |io| io.write(spec) } puts "updated #{f.name}" end tilt-2.0.1/bin/0000755000004100000410000000000012322577445013301 5ustar www-datawww-datatilt-2.0.1/bin/tilt0000755000004100000410000000563212322577445014211 0ustar www-datawww-data#!/usr/bin/env ruby require 'ostruct' require 'optparse' require 'tilt' usage = < Process template and write output to stdout. With no or when is '-', read template from stdin and use the --type option to determine the template's type. Options -l, --list List template engines + file patterns and exit -t, --type= Use this template engine; required if no -y, --layout= Use as a layout template -D= Define variable as --vars= Evaluate to Hash and use for variables -h, --help Show this help message Convert markdown to HTML: $ tilt foo.markdown > foo.html Process ERB template: $ echo "Answer: <%= 2 + 2 %>" | tilt -t erb Answer: 4 Define variables: $ echo "Answer: <%= 2 + n %>" | tilt -t erb --vars="{:n=>40}" Answer: 42 $ echo "Answer: <%= 2 + n.to_i %>" | tilt -t erb -Dn=40 Answer: 42 USAGE script_name = File.basename($0) pattern = nil layout = nil locals = {} ARGV.options do |o| o.program_name = script_name # list all available template engines o.on("-l", "--list") do groups = {} Tilt.lazy_map.each do |pattern,engines| engines.each do |engine| key = engine[0].split('::').last.sub(/Template$/, '') (groups[key] ||= []) << pattern end end groups.sort { |(k1,v1),(k2,v2)| k1 <=> k2 }.each do |engine,files| printf "%-15s %s\n", engine, files.sort.join(', ') end exit end # the template type / pattern o.on("-t", "--type=PATTERN", String) do |val| abort "unknown template type: #{val}" if Tilt[val].nil? pattern = val end # pass template output into the specified layout template o.on("-y", "--layout=FILE", String) do |file| paths = [file, "~/.tilt/#{file}", "/etc/tilt/#{file}"] layout = paths. map { |p| File.expand_path(p) }. find { |p| File.exist?(p) } abort "no such layout: #{file}" if layout.nil? end # define a local variable o.on("-D", "--define=PAIR", String) do |pair| key, value = pair.split(/[=:]/, 2) locals[key.to_sym] = value end # define local variables using a Ruby hash o.on("--vars=RUBY") do |ruby| hash = eval(ruby) abort "vars must be a Hash, not #{hash.inspect}" if !hash.is_a?(Hash) hash.each { |key, value| locals[key.to_sym] = value } end o.on_tail("-h", "--help") { puts usage; exit } o.parse! end file = ARGV.first || '-' pattern = file if pattern.nil? abort "template type not given. see: #{$0} --help" if ['-', ''].include?(pattern) engine = Tilt[pattern] abort "template engine not found for: #{pattern}" if engine.nil? template = engine.new(file) { if file == '-' $stdin.read else File.read(file) end } output = template.render(self, locals) # process layout output = Tilt.new(layout).render(self, locals) { output } if layout $stdout.write(output) tilt-2.0.1/tilt.gemspec0000644000004100000410000000567712322577445015071 0ustar www-datawww-dataGem::Specification.new do |s| s.specification_version = 2 if s.respond_to? :specification_version= s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version= s.name = 'tilt' s.version = '2.0.1' s.date = '2014-03-21' s.description = "Generic interface to multiple Ruby template engines" s.summary = s.description s.license = "MIT" s.authors = ["Ryan Tomayko"] s.email = "r@tomayko.com" # = MANIFEST = s.files = %w[ CHANGELOG.md COPYING Gemfile HACKING README.md Rakefile bin/tilt docs/TEMPLATES.md docs/common.css lib/tilt.rb lib/tilt/asciidoc.rb lib/tilt/bluecloth.rb lib/tilt/builder.rb lib/tilt/coffee.rb lib/tilt/creole.rb lib/tilt/csv.rb lib/tilt/erb.rb lib/tilt/erubis.rb lib/tilt/etanni.rb lib/tilt/haml.rb lib/tilt/kramdown.rb lib/tilt/less.rb lib/tilt/liquid.rb lib/tilt/mapping.rb lib/tilt/markaby.rb lib/tilt/maruku.rb lib/tilt/nokogiri.rb lib/tilt/plain.rb lib/tilt/radius.rb lib/tilt/rdiscount.rb lib/tilt/rdoc.rb lib/tilt/redcarpet.rb lib/tilt/redcloth.rb lib/tilt/sass.rb lib/tilt/string.rb lib/tilt/template.rb lib/tilt/wikicloth.rb lib/tilt/yajl.rb test/markaby/locals.mab test/markaby/markaby.mab test/markaby/markaby_other_static.mab test/markaby/render_twice.mab test/markaby/scope.mab test/markaby/yielding.mab test/test_helper.rb test/tilt_asciidoctor_test.rb test/tilt_blueclothtemplate_test.rb test/tilt_buildertemplate_test.rb test/tilt_cache_test.rb test/tilt_coffeescripttemplate_test.rb test/tilt_compilesite_test.rb test/tilt_creoletemplate_test.rb test/tilt_csv_test.rb test/tilt_erbtemplate_test.rb test/tilt_erubistemplate_test.rb test/tilt_etannitemplate_test.rb test/tilt_hamltemplate_test.rb test/tilt_kramdown_test.rb test/tilt_lesstemplate_test.less test/tilt_lesstemplate_test.rb test/tilt_liquidtemplate_test.rb test/tilt_mapping_test.rb test/tilt_markaby_test.rb test/tilt_markdown_test.rb test/tilt_marukutemplate_test.rb test/tilt_metadata_test.rb test/tilt_nokogiritemplate_test.rb test/tilt_radiustemplate_test.rb test/tilt_rdiscounttemplate_test.rb test/tilt_rdoctemplate_test.rb test/tilt_redcarpettemplate_test.rb test/tilt_redclothtemplate_test.rb test/tilt_sasstemplate_test.rb test/tilt_stringtemplate_test.rb test/tilt_template_test.rb test/tilt_test.rb test/tilt_wikiclothtemplate_test.rb test/tilt_yajltemplate_test.rb tilt.gemspec ] # = MANIFEST = s.executables = ['tilt'] s.test_files = s.files.select {|path| path =~ /^test\/.*_test.rb/} s.homepage = "http://github.com/rtomayko/tilt/" s.rdoc_options = ["--line-numbers", "--inline-source", "--title", "Tilt", "--main", "Tilt"] s.require_paths = %w[lib] s.rubygems_version = '1.1.1' end tilt-2.0.1/Gemfile0000644000004100000410000000144412322577445014027 0ustar www-datawww-datasource 'https://rubygems.org' gem 'yard', '~> 0.8.6' gem 'minitest', '~> 5.0' gem 'rake' group :engines do gem 'asciidoctor', '>= 0.1.0' gem 'builder' gem 'coffee-script' gem 'contest' gem 'creole' gem 'erubis' gem 'haml', '>= 2.2.11', '< 4' gem 'kramdown' gem 'less' gem 'liquid' gem 'markaby' gem 'maruku' gem 'nokogiri' if RUBY_VERSION > '1.9.2' gem 'radius' gem 'sass' gem 'rdoc', (ENV['RDOC_VERSION'] || '> 0') platform :ruby do gem 'wikicloth' gem 'yajl-ruby' gem 'redcarpet' if RUBY_VERSION > '1.8.7' gem 'rdiscount', '>= 2.1.6' if RUBY_VERSION != '1.9.2' gem 'RedCloth' end platform :mri do gem 'therubyracer' gem 'bluecloth' if ENV['BLUECLOTH'] end end ## WHY do I have to do this?!? platform :rbx do gem 'rubysl' end tilt-2.0.1/lib/0000755000004100000410000000000012322577445013277 5ustar www-datawww-datatilt-2.0.1/lib/tilt/0000755000004100000410000000000012322577445014253 5ustar www-datawww-datatilt-2.0.1/lib/tilt/markaby.rb0000644000004100000410000000171312322577445016230 0ustar www-datawww-datarequire 'tilt/template' require 'markaby' module Tilt # Markaby # http://github.com/markaby/markaby class MarkabyTemplate < Template def self.builder_class @builder_class ||= Class.new(Markaby::Builder) do def __capture_markaby_tilt__(&block) __run_markaby_tilt__ do text capture(&block) end end end end def prepare end def evaluate(scope, locals, &block) builder = self.class.builder_class.new({}, scope) builder.locals = locals if data.kind_of? Proc (class << builder; self end).send(:define_method, :__run_markaby_tilt__, &data) else builder.instance_eval <<-CODE, __FILE__, __LINE__ def __run_markaby_tilt__ #{data} end CODE end if block builder.__capture_markaby_tilt__(&block) else builder.__run_markaby_tilt__ end builder.to_s end end end tilt-2.0.1/lib/tilt/redcarpet.rb0000644000004100000410000000517612322577445016562 0ustar www-datawww-datarequire 'tilt/template' require 'redcarpet' module Tilt # Compatibility mode for Redcarpet 1.x class Redcarpet1Template < Template self.default_mime_type = 'text/html' ALIAS = { :escape_html => :filter_html, :smartypants => :smart } FLAGS = [:smart, :filter_html, :smartypants, :escape_html] def flags FLAGS.select { |flag| options[flag] }.map { |flag| ALIAS[flag] || flag } end def prepare @engine = RedcarpetCompat.new(data, *flags) @output = nil end def evaluate(scope, locals, &block) @output ||= @engine.to_html end def allows_script? false end end # Future proof mode for Redcarpet 2.x (not yet released) class Redcarpet2Template < Template self.default_mime_type = 'text/html' def self.engine_initialized? defined? ::Redcarpet::Render and defined? ::Redcarpet::Markdown end def generate_renderer renderer = options.delete(:renderer) || ::Redcarpet::Render::HTML return renderer unless options.delete(:smartypants) return renderer if renderer.is_a?(Class) && renderer <= ::Redcarpet::Render::SmartyPants if renderer == ::Redcarpet::Render::XHTML ::Redcarpet::Render::SmartyHTML.new(:xhtml => true) elsif renderer == ::Redcarpet::Render::HTML ::Redcarpet::Render::SmartyHTML elsif renderer.is_a? Class Class.new(renderer) { include ::Redcarpet::Render::SmartyPants } else renderer.extend ::Redcarpet::Render::SmartyPants end end def prepare # try to support the same aliases Redcarpet1Template::ALIAS.each do |opt, aka| next if options.key? opt or not options.key? aka options[opt] = options.delete(aka) end # only raise an exception if someone is trying to enable :escape_html options.delete(:escape_html) unless options[:escape_html] @engine = ::Redcarpet::Markdown.new(generate_renderer, options) @output = nil end def evaluate(scope, locals, &block) @output ||= @engine.render(data) end def allows_script? false end end # Upskirt Markdown implementation. See: # https://github.com/tanoku/redcarpet # # Supports both Redcarpet 1.x and 2.x class RedcarpetTemplate < Template Redcarpet1 = Redcarpet1Template Redcarpet2 = Redcarpet2Template def prepare klass = Redcarpet2.engine_initialized? ? Redcarpet2 : Redcarpet1 @engine = klass.new(file, line, options) { data } end def evaluate(scope, locals, &block) @engine.evaluate(scope, locals, &block) end def allows_script? false end end end tilt-2.0.1/lib/tilt/string.rb0000644000004100000410000000072712322577445016114 0ustar www-datawww-datarequire 'tilt/template' module Tilt # The template source is evaluated as a Ruby string. The #{} interpolation # syntax can be used to generated dynamic output. class StringTemplate < Template def prepare hash = "TILT#{data.hash.abs}" @code = "<<#{hash}.chomp\n#{data}\n#{hash}" end def precompiled_template(locals) @code end def precompiled(locals) source, offset = super [source, offset + 1] end end end tilt-2.0.1/lib/tilt/csv.rb0000644000004100000410000000233312322577445015374 0ustar www-datawww-datarequire 'tilt/template' if RUBY_VERSION >= '1.9.0' require 'csv' else require 'fastercsv' end module Tilt # CSV Template implementation. See: # http://ruby-doc.org/stdlib/libdoc/csv/rdoc/CSV.html # # == Example # # # Example of csv template # tpl = <<-EOS # # header # csv << ['NAME', 'ID'] # # # data rows # @people.each do |person| # csv << [person[:name], person[:id]] # end # EOS # # @people = [ # {:name => "Joshua Peek", :id => 1}, # {:name => "Ryan Tomayko", :id => 2}, # {:name => "Simone Carletti", :id => 3} # ] # # template = Tilt::CSVTemplate.new { tpl } # template.render(self) # class CSVTemplate < Template self.default_mime_type = 'text/csv' def self.engine if RUBY_VERSION >= '1.9.0' && defined? ::CSV ::CSV elsif defined? ::FasterCSV ::FasterCSV end end def prepare @code =<<-RUBY #{self.class.engine}.generate do |csv| #{data} end RUBY end def precompiled_template(locals) @code end def precompiled(locals) source, offset = super [source, offset + 1] end end end tilt-2.0.1/lib/tilt/rdiscount.rb0000644000004100000410000000161012322577445016610 0ustar www-datawww-datarequire 'tilt/template' require 'rdiscount' module Tilt # Discount Markdown implementation. See: # http://github.com/rtomayko/rdiscount # # RDiscount is a simple text filter. It does not support +scope+ or # +locals+. The +:smart+ and +:filter_html+ options may be set true # to enable those flags on the underlying RDiscount object. class RDiscountTemplate < Template self.default_mime_type = 'text/html' ALIAS = { :escape_html => :filter_html, :smartypants => :smart } FLAGS = [:smart, :filter_html, :smartypants, :escape_html] def flags FLAGS.select { |flag| options[flag] }.map { |flag| ALIAS[flag] || flag } end def prepare @engine = RDiscount.new(data, *flags) @output = nil end def evaluate(scope, locals, &block) @output ||= @engine.to_html end def allows_script? false end end end tilt-2.0.1/lib/tilt/less.rb0000644000004100000410000000144012322577445015545 0ustar www-datawww-datarequire 'tilt/template' require 'less' module Tilt # Lessscss template implementation. See: # http://lesscss.org/ # # Less templates do not support object scopes, locals, or yield. class LessTemplate < Template self.default_mime_type = 'text/css' def self.engine_initialized? defined? ::Less end def initialize_engine require_template_library 'less' end def prepare if ::Less.const_defined? :Engine @engine = ::Less::Engine.new(data) else parser = ::Less::Parser.new(options.merge :filename => eval_file, :line => line) @engine = parser.parse(data) end end def evaluate(scope, locals, &block) @output ||= @engine.to_css(options) end def allows_script? false end end end tilt-2.0.1/lib/tilt/bluecloth.rb0000644000004100000410000000070312322577445016561 0ustar www-datawww-datarequire 'tilt/template' require 'bluecloth' module Tilt # BlueCloth Markdown implementation. See: # http://deveiate.org/projects/BlueCloth/ class BlueClothTemplate < Template self.default_mime_type = 'text/html' def prepare @engine = BlueCloth.new(data, options) @output = nil end def evaluate(scope, locals, &block) @output ||= @engine.to_html end def allows_script? false end end end tilt-2.0.1/lib/tilt/redcloth.rb0000644000004100000410000000070412322577445016405 0ustar www-datawww-datarequire 'tilt/template' require 'redcloth' module Tilt # RedCloth implementation. See: # http://redcloth.org/ class RedClothTemplate < Template def prepare @engine = RedCloth.new(data) options.each {|k, v| @engine.send("#{k}=", v) if @engine.respond_to? "#{k}="} @output = nil end def evaluate(scope, locals, &block) @output ||= @engine.to_html end def allows_script? false end end end tilt-2.0.1/lib/tilt/sass.rb0000644000004100000410000000152712322577445015556 0ustar www-datawww-datarequire 'tilt/template' require 'sass' module Tilt # Sass template implementation. See: # http://haml.hamptoncatlin.com/ # # Sass templates do not support object scopes, locals, or yield. class SassTemplate < Template self.default_mime_type = 'text/css' def prepare @engine = ::Sass::Engine.new(data, sass_options) end def evaluate(scope, locals, &block) @output ||= @engine.render end def allows_script? false end private def sass_options options.merge(:filename => eval_file, :line => line, :syntax => :sass) end end # Sass's new .scss type template implementation. class ScssTemplate < SassTemplate self.default_mime_type = 'text/css' private def sass_options options.merge(:filename => eval_file, :line => line, :syntax => :scss) end end end tilt-2.0.1/lib/tilt/plain.rb0000644000004100000410000000047212322577445015706 0ustar www-datawww-datarequire 'tilt/template' module Tilt # Raw text (no template functionality). class PlainTemplate < Template self.default_mime_type = 'text/html' def self.engine_initialized? true end def prepare end def evaluate(scope, locals, &block) @output ||= data end end end tilt-2.0.1/lib/tilt/mapping.rb0000644000004100000410000002053712322577445016242 0ustar www-datawww-datamodule Tilt # Tilt::Mapping associates file extensions with template implementations. # # mapping = Tilt::Mapping.new # mapping.register(Tilt::RDocTemplate, 'rdoc') # mapping['index.rdoc'] # => Tilt::RDocTemplate # mapping.new('index.rdoc').render # # You can use {#register} to register a template class by file # extension, {#registered?} to see if a file extension is mapped, # {#[]} to lookup template classes, and {#new} to instantiate template # objects. # # Mapping also supports *lazy* template implementations. Note that regularly # registered template implementations *always* have preference over lazily # registered template implementations. You should use {#register} if you # depend on a specific template implementation and {#register_lazy} if there # are multiple alternatives. # # mapping = Tilt::Mapping.new # mapping.register_lazy('RDiscount::Template', 'rdiscount/template', 'md') # mapping['index.md'] # # => RDiscount::Template # # {#register_lazy} takes a class name, a filename, and a list of file # extensions. When you try to lookup a template name that matches the # file extension, Tilt will automatically try to require the filename and # constantize the class name. # # Unlike {#register}, there can be multiple template implementations # registered lazily to the same file extension. Tilt will attempt to load the # template implementations in order (registered *last* would be tried first), # returning the first which doesn't raise LoadError. # # If all of the registered template implementations fails, Tilt will raise # the exception of the first, since that was the most preferred one. # # mapping = Tilt::Mapping.new # mapping.register_lazy('Bluecloth::Template', 'bluecloth/template', 'md') # mapping.register_lazy('RDiscount::Template', 'rdiscount/template', 'md') # mapping['index.md'] # # => RDiscount::Template # # In the previous example we say that RDiscount has a *higher priority* than # BlueCloth. Tilt will first try to `require "rdiscount/template"`, falling # back to `require "bluecloth/template"`. If none of these are successful, # the first error will be raised. class Mapping # @private attr_reader :lazy_map, :template_map def initialize @template_map = Hash.new @lazy_map = Hash.new { |h, k| h[k] = [] } end # @private def initialize_copy(other) @template_map = other.template_map.dup @lazy_map = other.lazy_map.dup end # Registrers a lazy template implementation by file extension. You # can have multiple lazy template implementations defined on the # same file extension, in which case the template implementation # defined *last* will be attempted loaded *first*. # # @param class_name [String] Class name of a template class. # @param file [String] Filename where the template class is defined. # @param extensions [Array] List of extensions. # @return [void] # # @example # mapping.register_lazy 'MyEngine::Template', 'my_engine/template', 'mt' # # defined?(MyEngine::Template) # => false # mapping['index.mt'] # => MyEngine::Template # defined?(MyEngine::Template) # => true def register_lazy(class_name, file, *extensions) # Internal API if class_name.is_a?(Symbol) Tilt.autoload class_name, file class_name = "Tilt::#{class_name}" end extensions.each do |ext| @lazy_map[ext].unshift([class_name, file]) end end # Registers a template implementation by file extension. There can only be # one template implementation per file extension, and this method will # override any existing mapping. # # @param template_class # @param extensions [Array] List of extensions. # @return [void] # # @example # mapping.register MyEngine::Template, 'mt' # mapping['index.mt'] # => MyEngine::Template def register(template_class, *extensions) if template_class.respond_to?(:to_str) # Support register(ext, template_class) too extensions, template_class = [template_class], extensions[0] end extensions.each do |ext| @template_map[ext.to_s] = template_class end end # Checks if a file extension is registered (either eagerly or # lazily) in this mapping. # # @param ext [String] File extension. # # @example # mapping.registered?('erb') # => true # mapping.registered?('nope') # => false def registered?(ext) @template_map.has_key?(ext.downcase) or lazy?(ext) end # Instantiates a new template class based on the file. # # @raise [RuntimeError] if there is no template class registered for the # file name. # # @example # mapping.new('index.mt') # => instance of MyEngine::Template # # @see Tilt::Template.new def new(file, line=nil, options={}, &block) if template_class = self[file] template_class.new(file, line, options, &block) else fail "No template engine registered for #{File.basename(file)}" end end # Looks up a template class based on file name and/or extension. # # @example # mapping['views/hello.erb'] # => Tilt::ERBTemplate # mapping['hello.erb'] # => Tilt::ERBTemplate # mapping['erb'] # => Tilt::ERBTemplate # # @return [template class] def [](file) _, ext = split(file) ext && lookup(ext) end alias template_for [] # Looks up a list of template classes based on file name. If the file name # has multiple extensions, it will return all template classes matching the # extensions from the end. # # @example # mapping.templates_for('views/index.haml.erb') # # => [Tilt::ERBTemplate, Tilt::HamlTemplate] # # @return [Array