├── lib ├── malt.yml ├── malt │ ├── markup.rb │ ├── engines.rb │ ├── formats.rb │ ├── template.rb │ ├── formats │ │ ├── pdf.rb │ │ ├── html.rb │ │ ├── javascript.rb │ │ ├── xml.rb │ │ ├── css.rb │ │ ├── mustache.rb │ │ ├── latex.rb │ │ ├── ruby.rb │ │ ├── rdoc.rb │ │ ├── textile.rb │ │ ├── scss.rb │ │ ├── yaml.rb │ │ ├── radius.rb │ │ ├── less.rb │ │ ├── haml.rb │ │ ├── tenjin.rb │ │ ├── coffee.rb │ │ ├── ragtag.rb │ │ ├── sass.rb │ │ ├── text.rb │ │ ├── rbhtml.rb │ │ ├── rhtml.rb │ │ ├── liquid.rb │ │ ├── abstract_template.rb │ │ ├── mediawiki.rb │ │ ├── string.rb │ │ ├── erb.rb │ │ ├── markdown.rb │ │ └── builder.rb │ ├── version.rb │ ├── kernel.rb │ ├── engines │ │ ├── ruby.rb │ │ ├── string.rb │ │ ├── haml.rb │ │ ├── redcloth.rb │ │ ├── coffee.rb │ │ ├── bluecloth.rb │ │ ├── wikicloth.rb │ │ ├── less.rb │ │ ├── liquid.rb │ │ ├── mustache.rb │ │ ├── creole.rb │ │ ├── ragtag.rb │ │ ├── rdiscount.rb │ │ ├── sass.rb │ │ ├── erubis.rb │ │ ├── markaby.rb │ │ ├── kramdown.rb │ │ ├── maruku.rb │ │ ├── rdoc.rb │ │ ├── nokogiri.rb │ │ ├── erector.rb │ │ ├── tenjin.rb │ │ ├── erb.rb │ │ ├── radius.rb │ │ └── builder.rb │ ├── conversions.rb │ └── core_ext.rb └── malt.rb ├── demo ├── samples │ ├── output-erb.txt │ ├── output-liquid.txt │ ├── output-mustache.txt │ ├── output-radius.txt │ ├── sample.erb │ ├── sample.liquid │ ├── sample.radius │ ├── data.yml │ ├── sample.mustache │ ├── consistent │ │ ├── sample.rbhtml │ │ ├── sample.str │ │ ├── sample.erb │ │ ├── sample.liquid │ │ ├── sample.mustache │ │ ├── sample.erubis │ │ ├── sample.haml │ │ ├── sample.radius │ │ ├── sample.builder │ │ ├── sample.erector │ │ ├── sample.markaby │ │ ├── sample.nokogiri │ │ └── sample.ragtag │ └── sample.rdoc ├── 01general │ ├── 09_core_ext │ │ ├── 02_object.rdoc │ │ └── 01_binding.rdoc │ ├── 01_overview.rdoc │ ├── 05_machine │ │ ├── 02_prioritized_engines.rdoc │ │ └── 01_limited_formats.rdoc │ └── 03_formats.rdoc ├── applique │ ├── sample_class.rb │ ├── malt.rb │ └── consitent.rb ├── 04sgml │ ├── 02builder │ │ ├── scope.rdoc │ │ ├── prefix.rdoc │ │ └── format_builder.rdoc │ ├── 06ragtag │ │ └── 08_ragtag.rdoc │ ├── 01haml │ │ └── format_haml.rdoc │ ├── consistent.rdoc │ ├── 05erector │ │ └── format_erector.rdoc │ ├── 03nokogiri │ │ └── nokogiri.rdoc │ ├── scope.rdoc │ └── 04markaby │ │ └── format_markaby.rdoc ├── 02markup │ ├── 02markdown │ │ ├── bluecloth │ │ │ └── bluecloth.rdoc │ │ ├── rdiscount │ │ │ └── rdiscount.rdoc │ │ └── kramdown │ │ │ └── kramdown.rdoc │ ├── 03textile │ │ └── redcloth │ │ │ └── format_redcloth.rdoc │ └── 01rdoc │ │ └── rdoc │ │ └── format_rdoc.rdoc ├── 03template │ ├── 01erb │ │ └── format_erb.rdoc │ ├── 07radius │ │ └── 09_radius.rdoc │ ├── consistent.rdoc │ ├── 08ruby │ │ └── ruby_example.rdoc │ ├── 09string │ │ └── string_exmple.rdoc │ ├── 03tenjin │ │ ├── 11_tenjin.rdoc │ │ └── 12_rbhtml.rdoc │ ├── 04liquid │ │ └── 06_liquid.rdoc │ ├── 05mustache │ │ └── 20_mustache.rdoc │ └── 02erubis │ │ └── format_erubis.rdoc ├── 06source │ ├── 21_coffee.rdoc │ └── 16_ruby.rdoc └── 05css │ ├── 01sass │ ├── 13_sass.rdoc │ └── 14_scss.rdoc │ └── 02less │ └── 15_less.rdoc ├── work ├── sandbox │ ├── test.rdoc │ ├── test.erb │ ├── test.md │ ├── test.haml │ ├── test.rdoc.erb │ ├── tryme2.rb │ └── tryme.rb ├── trash │ ├── config.rb │ └── render.rb ├── research │ ├── rbx_test.rb │ ├── binding_addition.rb │ └── binding.rb ├── defunct │ ├── meta │ │ └── data.rb │ ├── erector.rb │ └── markaby.rb ├── consider │ ├── 06_tilted.rdoc │ └── slim │ │ ├── lib │ │ └── malt │ │ │ ├── formats │ │ │ └── slim.rb │ │ │ └── engines │ │ │ └── slim.rb │ │ └── qed │ │ └── 03_formats │ │ └── 10_slim.rdoc └── notes │ └── 2010-06-22-markup-vs-template.rdoc ├── bin └── malt ├── Rakefile ├── .gitignore ├── test ├── fixtures │ ├── sample.rdoc │ └── sample.erb ├── unit │ ├── malt.rb │ ├── engines │ │ ├── case_engine_markaby.rb │ │ ├── case_engine_wikicloth.rb │ │ ├── case_engine_erb.rb │ │ ├── case_engine_tenjin.rb │ │ ├── case_engine_liquid.rb │ │ ├── case_engine_erubis.rb │ │ ├── case_engine_mustache.rb │ │ ├── case_engine_ruby.rb │ │ ├── case_engine_string.rb │ │ ├── case_engine_maruku.rb │ │ ├── case_engine_haml.rb │ │ ├── case_engine_rdiscount.rb │ │ ├── case_engine_redcarpet.rb │ │ ├── case_engine_kramdown.rb │ │ ├── case_engine_redcloth.rb │ │ ├── case_engine_builder.rb │ │ ├── case_engine_nokogiri.rb │ │ ├── case_engine_radius.rb │ │ ├── case_engine_rdoc.rb │ │ ├── case_engine_coffee.rb │ │ ├── case_engine_creole.rb │ │ ├── case_engine_erector.rb │ │ ├── case_engine_sass.rb │ │ ├── case_engine_bluecloth.rb │ │ ├── case_engine_less.rb │ │ └── case_engine_ragtag.rb │ └── machine.rb ├── helper.rb └── benchmarks │ └── malt_vs_tilt.rb ├── .confile ├── .travis.yml ├── Assembly ├── INDEX.yml ├── Gemfile ├── LICENSE.txt ├── README.md ├── MANIFEST ├── .index └── HISTORY.md /lib/malt.yml: -------------------------------------------------------------------------------- 1 | ../.index -------------------------------------------------------------------------------- /demo/samples/output-erb.txt: -------------------------------------------------------------------------------- 1 | Tom lives in Florida 2 | -------------------------------------------------------------------------------- /demo/samples/output-liquid.txt: -------------------------------------------------------------------------------- 1 | Tom lives in Florida 2 | -------------------------------------------------------------------------------- /demo/samples/output-mustache.txt: -------------------------------------------------------------------------------- 1 | Tom lives in Florida 2 | -------------------------------------------------------------------------------- /demo/samples/output-radius.txt: -------------------------------------------------------------------------------- 1 | Tom lives in Florida 2 | -------------------------------------------------------------------------------- /demo/samples/sample.erb: -------------------------------------------------------------------------------- 1 | <%= name %> lives in <%= state %> 2 | -------------------------------------------------------------------------------- /demo/samples/sample.liquid: -------------------------------------------------------------------------------- 1 | {{ name }} lives in {{ state }} 2 | -------------------------------------------------------------------------------- /demo/samples/sample.radius: -------------------------------------------------------------------------------- 1 | lives in 2 | -------------------------------------------------------------------------------- /demo/samples/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name : Tom 3 | state: Florida 4 | 5 | -------------------------------------------------------------------------------- /demo/samples/sample.mustache: -------------------------------------------------------------------------------- 1 | {{ name }} lives in {{ state }} 2 | -------------------------------------------------------------------------------- /work/sandbox/test.rdoc: -------------------------------------------------------------------------------- 1 | = Title 2 | 3 | This is a test. 4 | 5 | -------------------------------------------------------------------------------- /bin/malt: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | require 'malt' 3 | Malt.cli(*ARGV) 4 | 5 | -------------------------------------------------------------------------------- /work/sandbox/test.erb: -------------------------------------------------------------------------------- 1 | This is a test. 2 | 3 | <%= five %> 4 | 5 | Okay. 6 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.rbhtml: -------------------------------------------------------------------------------- 1 | #{name} lives in #{state} 2 | #{content} 3 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.str: -------------------------------------------------------------------------------- 1 | #{ name } lives in #{ state } 2 | #{ content } 3 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.erb: -------------------------------------------------------------------------------- 1 | <%= name %> lives in <%= state %> 2 | <%= content %> 3 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.liquid: -------------------------------------------------------------------------------- 1 | {{ name }} lives in {{ state }} 2 | {{ content }} 3 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.mustache: -------------------------------------------------------------------------------- 1 | {{ name }} lives in {{ state }} 2 | {{ content }} 3 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.erubis: -------------------------------------------------------------------------------- 1 | <%= name %> lives in <%= state %> 2 | <%= content %> 3 | -------------------------------------------------------------------------------- /work/sandbox/test.md: -------------------------------------------------------------------------------- 1 | # Title 2 | 3 | This is a test. 4 | 5 | * one 6 | * two 7 | * three 8 | 9 | -------------------------------------------------------------------------------- /Rakefile: -------------------------------------------------------------------------------- 1 | desc "ruby unit tests" 2 | task :test do 3 | sh "ruby-test -r./test/helper.rb test/" 4 | end 5 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.haml: -------------------------------------------------------------------------------- 1 | %div 2 | %h1= name 3 | #state= state 4 | #yield= content 5 | 6 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.radius: -------------------------------------------------------------------------------- 1 | lives in 2 | 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .rbx 2 | .reap/digest 3 | .yardoc 4 | doc 5 | log 6 | pkg 7 | tmp 8 | site 9 | web 10 | pages 11 | -------------------------------------------------------------------------------- /work/sandbox/test.haml: -------------------------------------------------------------------------------- 1 | #profile 2 | .left.column 3 | #date= date 4 | .right.column 5 | #name= name 6 | 7 | -------------------------------------------------------------------------------- /demo/samples/sample.rdoc: -------------------------------------------------------------------------------- 1 | = RDoc Format 2 | 3 | This is RDoc formatted markup. 4 | 5 | * one 6 | * two 7 | * three 8 | 9 | -------------------------------------------------------------------------------- /test/fixtures/sample.rdoc: -------------------------------------------------------------------------------- 1 | = RDoc Format 2 | 3 | This is RDoc formatted markup. 4 | 5 | * one 6 | * two 7 | * three 8 | 9 | -------------------------------------------------------------------------------- /lib/malt/markup.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | 3 | # Markup base class. 4 | # 5 | class Markup 6 | 7 | end 8 | 9 | end 10 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.builder: -------------------------------------------------------------------------------- 1 | div do 2 | h1 @name 3 | div @state, :id=>'state' 4 | div @content, :id=>'yield' 5 | end 6 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.erector: -------------------------------------------------------------------------------- 1 | div do 2 | h1 @name 3 | div @state, :id=>'state' 4 | div @content, :id=>'yield' 5 | end 6 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.markaby: -------------------------------------------------------------------------------- 1 | div do 2 | h1 @name 3 | div @state, :id=>'state' 4 | div @content, :id=>'yield' 5 | end 6 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.nokogiri: -------------------------------------------------------------------------------- 1 | div do 2 | h1 @name 3 | div @state, :id=>'state' 4 | div @content, :id=>'yield' 5 | end 6 | -------------------------------------------------------------------------------- /work/sandbox/test.rdoc.erb: -------------------------------------------------------------------------------- 1 | = <%= title %> 2 | 3 | This is a test. 4 | 5 | It will say the <%= word %>. 6 | 7 | * 1st 8 | * 2nd 9 | * 3rd 10 | 11 | -------------------------------------------------------------------------------- /work/trash/config.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | 3 | class Config 4 | 5 | # 6 | def engine 7 | @engine ||= {} 8 | end 9 | 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /demo/samples/consistent/sample.ragtag: -------------------------------------------------------------------------------- 1 |
2 |

3 |
4 |
5 |
6 | -------------------------------------------------------------------------------- /lib/malt/engines.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | # 3 | module Engine 4 | end 5 | end 6 | 7 | Dir[File.dirname(__FILE__) + '/engines/*.rb'].each do |file| 8 | require file 9 | end 10 | 11 | -------------------------------------------------------------------------------- /lib/malt/formats.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | # 3 | module Format 4 | end 5 | end 6 | 7 | Dir[File.dirname(__FILE__) + '/formats/*.rb'].each do |file| 8 | require file 9 | end 10 | 11 | -------------------------------------------------------------------------------- /lib/malt/template.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | 3 | # Template base case. 4 | # 5 | class Template < Markup 6 | 7 | def compile(db, &yld) 8 | end 9 | 10 | end 11 | 12 | end 13 | -------------------------------------------------------------------------------- /demo/01general/09_core_ext/02_object.rdoc: -------------------------------------------------------------------------------- 1 | == Object Extensions 2 | 3 | === to_binding 4 | 5 | o = Object.new 6 | 7 | b = o.to_binding 8 | 9 | b.eval('self') #=> o 10 | 11 | -------------------------------------------------------------------------------- /test/fixtures/sample.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | <%= page_title %> 4 | 5 | 6 |

<%= salutation %>

7 |

This is an example of how ERb fills out a template.

8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /work/sandbox/tryme2.rb: -------------------------------------------------------------------------------- 1 | require 'malt' 2 | 3 | file = Malt.file('test.rdoc.erb') #, :recompile=>true) 4 | html = file.html(:title=>"THE TITLE", :word=>"WORD") 5 | 6 | p html.class 7 | p html.file 8 | 9 | puts 10 | puts html 11 | 12 | -------------------------------------------------------------------------------- /demo/applique/sample_class.rb: -------------------------------------------------------------------------------- 1 | 2 | # TODO: Had to use `::` b/c of QED limitation. Report issue. 3 | 4 | class ::SampleObject 5 | attr :name 6 | attr :state 7 | def initialize(name,state) 8 | @name = name 9 | @state = state 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /.confile: -------------------------------------------------------------------------------- 1 | qed do 2 | profile :cov do 3 | require 'simplecov' 4 | SimpleCov.start do 5 | coverage_dir 'log/coverage' 6 | add_group "Formats", "lib/malt/formats" 7 | add_group "Engines", "lib/malt/engines" 8 | end 9 | end 10 | end 11 | 12 | 13 | -------------------------------------------------------------------------------- /test/unit/malt.rb: -------------------------------------------------------------------------------- 1 | testcase Malt do 2 | 3 | class_method :render do 4 | 5 | test "corrent engine is used when specified" do 6 | Malt.render(:text=>"<%= title %>", :type=>:erb, :engine=>:erubis, :data=>{:title=>'Testing'}) 7 | end 8 | 9 | end 10 | 11 | 12 | end 13 | -------------------------------------------------------------------------------- /work/research/rbx_test.rb: -------------------------------------------------------------------------------- 1 | #class Binding 2 | # def self 3 | # eval('self') 4 | # end 5 | #end 6 | 7 | #p binding.self 8 | 9 | 10 | class Binding 11 | def self_of_binding 12 | Kernel.eval('self', self) 13 | end 14 | end 15 | p binding.self_of_binding 16 | 17 | -------------------------------------------------------------------------------- /test/helper.rb: -------------------------------------------------------------------------------- 1 | $:.unshift File.dirname(__FILE__) + '/../lib' 2 | 3 | require 'lemon' 4 | require 'ae' 5 | require 'ae/pry' 6 | 7 | require 'malt' 8 | 9 | # lets try this for now 10 | #require 'rr' 11 | 12 | #class Lemon::World 13 | # include RR::Adapters::RRMethods 14 | #end 15 | 16 | -------------------------------------------------------------------------------- /lib/malt/formats/pdf.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | 3 | module Malt::Format 4 | 5 | # 6 | class PDF < Abstract 7 | 8 | file_extension 'pdf' 9 | 10 | # 11 | def pdf(*) 12 | text 13 | end 14 | 15 | # 16 | def to_pdf(*) 17 | self 18 | end 19 | 20 | end 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /work/research/binding_addition.rb: -------------------------------------------------------------------------------- 1 | def binding1 2 | a = 1 3 | binding 4 | end 5 | 6 | def binding2 7 | b = 2 8 | binding 9 | end 10 | 11 | p eval('a', binding1) #=> 1 12 | p eval('b', binding2) #=> 2 13 | 14 | #p eval('a + b', binding1 + binding2) #=> 3 15 | 16 | p eval('a+b', eval('binding2',binding1)) 17 | 18 | -------------------------------------------------------------------------------- /work/research/binding.rb: -------------------------------------------------------------------------------- 1 | require File.dirname(__FILE__) + '/../../lib/malt/core_ext' 2 | 3 | class X 4 | def a 5 | a = 1 6 | binding 7 | end 8 | 9 | def b(&b) 10 | a.with(:b=>2, &b) 11 | end 12 | end 13 | 14 | x = X.new 15 | 16 | r = x.b{ 1+1+1+1 } 17 | 18 | p r.eval('a') 19 | 20 | p r.eval('b') 21 | 22 | p r.eval('yield') 23 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | --- 2 | language: ruby 3 | script: "bundle exec $testcmd" 4 | rvm: 5 | - 2.1.0 6 | - 2.0.0 7 | - 1.9.3 8 | - 1.8.7 9 | - rbx 10 | - jruby 11 | env: 12 | - testcmd="qed -Ilib" 13 | - testcmd="rubytest -Ilib -r./test/helper.rb test/unit" 14 | matrix: 15 | allow_failures: 16 | - rvm: rbx 17 | - rvm: jruby 18 | cache: bundler 19 | 20 | -------------------------------------------------------------------------------- /lib/malt/formats/html.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | 3 | module Malt::Format 4 | 5 | # 6 | class HTML < Abstract 7 | 8 | file_extension 'html' #, 'xhtml' ? 9 | 10 | # 11 | def html(*) 12 | text 13 | end 14 | 15 | # HTML is HTML ;) 16 | def to_html(*) 17 | self 18 | end 19 | 20 | end 21 | 22 | end 23 | 24 | -------------------------------------------------------------------------------- /lib/malt/formats/javascript.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | 3 | module Malt::Format 4 | 5 | # 6 | class Javascript < Abstract 7 | 8 | file_extension 'js' 9 | 10 | # 11 | def js(*) 12 | text 13 | end 14 | 15 | alias_method :javascript, :js 16 | 17 | # 18 | def to_js(*) 19 | self 20 | end 21 | 22 | alias_method :to_javascript, :to_js 23 | 24 | end 25 | 26 | end 27 | 28 | -------------------------------------------------------------------------------- /lib/malt/formats/xml.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | 3 | module Malt::Format 4 | 5 | # TODO: Add conversion to_html. 6 | class XML < Abstract 7 | 8 | register 'xml' 9 | 10 | # 11 | def xml(*) 12 | text 13 | end 14 | 15 | # XML is XML ;) 16 | def to_xml(*) 17 | self 18 | end 19 | 20 | private 21 | 22 | # 23 | def render_engine 24 | end 25 | 26 | end 27 | 28 | end 29 | 30 | -------------------------------------------------------------------------------- /demo/01general/09_core_ext/01_binding.rdoc: -------------------------------------------------------------------------------- 1 | == Binding Extensions 2 | 3 | === to_binding 4 | 5 | b = binding 6 | 7 | b.to_binding #=> b 8 | 9 | === itself 10 | 11 | b = binding 12 | 13 | b.itself #=> self 14 | 15 | === with 16 | 17 | b1 = binding 18 | 19 | b2 = b1.with(:a=>1,:b=>2) 20 | 21 | b2.eval('a') #=> 1 22 | b2.eval('b') #=> 2 23 | 24 | Kernel.eval('a', b2) #=> 1 25 | Kernel.eval('b', b2) #=> 2 26 | 27 | -------------------------------------------------------------------------------- /Assembly: -------------------------------------------------------------------------------- 1 | --- 2 | gem: 3 | active: true 4 | 5 | github: 6 | gh_pages: web 7 | 8 | dnote: 9 | labels: ~ 10 | output: log/notes.html 11 | 12 | qedoc: 13 | title: Malt Demonstrandum 14 | output: web/demo.html 15 | 16 | email: 17 | mailto: 18 | - ruby-talk@ruby-lang.org 19 | - rubyworks-mailinglist@googlegroups.com 20 | 21 | locat: 22 | output: log/locat.html 23 | 24 | vclog: 25 | output: 26 | - log/changes.html 27 | - log/history.html 28 | 29 | -------------------------------------------------------------------------------- /lib/malt/version.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | 3 | # Access to project metadata. 4 | def self.metadata 5 | @metadata ||= ( 6 | require 'yaml' 7 | YAML.load(File.new(File.dirname(__FILE__) + '/../malt.yml')) 8 | ) 9 | end 10 | 11 | # Access to project metadata via constants. 12 | def self.const_missing(name) 13 | key = name.to_s.downcase 14 | metadata[key] || super(name) 15 | end 16 | 17 | # TODO: Here until bug in 1.8 is fixed. 18 | VERSION = metadata['version'] 19 | 20 | end 21 | 22 | -------------------------------------------------------------------------------- /lib/malt/formats/css.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | 3 | module Malt::Format 4 | 5 | # 6 | class CSS < Abstract 7 | 8 | file_extension 'css' 9 | 10 | # 11 | def css(*) 12 | text 13 | end 14 | 15 | # CSS is CSS ;) 16 | def to_css(*) 17 | self 18 | end 19 | 20 | private 21 | 22 | # 23 | #def render_engine 24 | #end 25 | 26 | # CSS default output type is itself. 27 | def default 28 | :css 29 | end 30 | 31 | end 32 | 33 | end 34 | 35 | -------------------------------------------------------------------------------- /demo/04sgml/02builder/scope.rdoc: -------------------------------------------------------------------------------- 1 | == Scope Mode 2 | 3 | Say we have the following @template: 4 | 5 | html do 6 | h1 "Example #{@title}" 7 | p "This is an example of a Markaby template." 8 | end 9 | 10 | Using a Struct object for the scope, 11 | 12 | data = Struct.new(:title).new("Document") 13 | 14 | html = Malt.render(:text=>@template, :type=>:builder, :data=>data, :engine=>:builder) 15 | 16 | html.assert.include?('

Example Document

') 17 | html.assert.include?('

This is an example of a Markaby template.

') 18 | 19 | 20 | -------------------------------------------------------------------------------- /demo/04sgml/02builder/prefix.rdoc: -------------------------------------------------------------------------------- 1 | == Prefix Mode 2 | 3 | Say we have the following @template: 4 | 5 | bld.html do |html| 6 | html.h1 "Example #{title}" 7 | html.p "This is an example of a Markaby template." 8 | end 9 | 10 | Then 11 | 12 | data = Struct.new(:title).new("Document") 13 | 14 | html = Malt.render(:text=>@template, :type=>:builder, :data=>data, :engine=>:builder, :prefix=>:bld) 15 | 16 | html.assert.include?('

Example Document

') 17 | html.assert.include?('

This is an example of a Markaby template.

') 18 | 19 | 20 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_markaby.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Markaby do 2 | 3 | method :render do 4 | 5 | test "convert Markaby DSL to XML by default" do 6 | e = Malt::Engine::Markaby.new(:text=>%[h1 "Testing"]) 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Markaby.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>%[h1 "Testing"]) 15 | end 16 | end 17 | 18 | end 19 | 20 | end 21 | -------------------------------------------------------------------------------- /lib/malt/kernel.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | 3 | # Common methods that can be used through-out Malt classes. 4 | module Kernel 5 | private 6 | 7 | # 8 | def make_ostruct(hash) 9 | case hash 10 | when OpenStruct 11 | hash 12 | else 13 | OpenStruct.new(hash) 14 | end 15 | end 16 | 17 | # 18 | def ext_to_type(ext) 19 | ext = ext.to_s.downcase 20 | return nil if ext.empty? 21 | if ext[0,1] == '.' 22 | ext[1..-1].to_sym 23 | else 24 | ext.to_sym 25 | end 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /lib/malt/formats/mustache.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract_template' 2 | require 'malt/engines/mustache' 3 | 4 | module Malt::Format 5 | 6 | # Mustache templates 7 | # 8 | # http://github.com/defunkt/mustache 9 | # 10 | class Mustache < AbstractTemplate 11 | 12 | file_extension 'mustache' 13 | 14 | # 15 | def mustache(*) 16 | text 17 | end 18 | 19 | # 20 | def to_mustache(*) 21 | self 22 | end 23 | 24 | #private 25 | 26 | # 27 | #def render_engine 28 | # @render_engine ||= Malt::Engine::Mustache.new(options) 29 | #end 30 | 31 | end 32 | 33 | end 34 | 35 | -------------------------------------------------------------------------------- /work/defunct/meta/data.rb: -------------------------------------------------------------------------------- 1 | Object.__send__(:remove_const, :VERSION) if Object.const_defined?(:VERSION) # becuase Ruby 1.8~ gets in the way 2 | 3 | module Malt 4 | 5 | DIRECTORY = File.dirname(__FILE__) 6 | 7 | def self.package 8 | @package ||= ( 9 | require 'yaml' 10 | YAML.load(File.new(DIRECTORY + '/package')) 11 | ) 12 | end 13 | 14 | def self.profile 15 | @profile ||= ( 16 | require 'yaml' 17 | YAML.load(File.new(DIRECTORY + '/profile')) 18 | ) 19 | end 20 | 21 | def self.const_missing(name) 22 | key = name.to_s.downcase 23 | package[key] || profile[key] || super(name) 24 | end 25 | 26 | end 27 | -------------------------------------------------------------------------------- /work/sandbox/tryme.rb: -------------------------------------------------------------------------------- 1 | require 'malt' 2 | 3 | puts 4 | puts "---- erb ----" 5 | puts 6 | puts Malt.file('test.erb').html(:five=>"Hello") 7 | puts 8 | 9 | puts "---- haml ----" 10 | puts 11 | puts Malt.file('test.haml').html(:date=>Time.now,:name=>"Hello") 12 | puts 13 | 14 | puts "---- rdoc ----" 15 | puts 16 | puts Malt.file('test.rdoc').html 17 | puts 18 | 19 | puts "---- rdiscount ----" 20 | puts 21 | puts Malt.file('test.md').html 22 | puts 23 | 24 | puts "---- rdoc.erb ----" 25 | puts 26 | puts Malt.file('test.rdoc.erb').html(:title=>"Hello", :word=>"Yes!") 27 | puts 28 | 29 | 30 | puts "---- rdoc.erb ----" 31 | puts 32 | puts Malt.file('test.rdoc').markdown 33 | puts 34 | 35 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_wikicloth.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::WikiCloth do 2 | 3 | method :render do 4 | 5 | test "render media wiki text to HTML by default" do 6 | e = Malt::Engine::WikiCloth.new(:text=>"== Testing ==") 7 | h = e.render 8 | h.assert.index "

" # so complicated that we're lucky to find it ;) 9 | h.assert.index "Testing" 10 | end 11 | 12 | end 13 | 14 | method :prepare_engine do 15 | 16 | test "returns a WikiCloth instance" do 17 | e = Malt::Engine::WikiCloth.new 18 | r = e.prepare_engine(:text=>"== Testing ==") 19 | r.assert.is_a? ::WikiCloth::WikiCloth 20 | end 21 | 22 | end 23 | 24 | end 25 | 26 | -------------------------------------------------------------------------------- /demo/01general/01_overview.rdoc: -------------------------------------------------------------------------------- 1 | = Introduction 2 | 3 | Malt is a multi-template rendering framework. It provides two convenient 4 | interfaces for working with backend template systems. The first is 5 | a functional interface via `Malt.render` method. And the second is an 6 | object-oriented interface that can be easily constructed via the 7 | `Malt.file` or `Malt.text` methods. 8 | 9 | = Formats 10 | 11 | Malt support a wide variety of markup and template systems. 12 | 13 | Malt provides two distinct APIs for rendering each format --a single-point-of-entry 14 | functional interface, `Malt.render`, and an object-oriented interface where by 15 | each format is represented by a document class. 16 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_erb.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Erb do 2 | 3 | method :render do 4 | 5 | test "convert ERB text" do 6 | e = Malt::Engine::Erb.new(:text=>"

<%= title %>

") 7 | h = e.render(:locals=>{:title=>'Testing'}) 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "Erb is converstion format agnostic" do 12 | e = Malt::Engine::Erb.new 13 | e.render(:to=>:DNE, :text=>"

Testing

") 14 | end 15 | 16 | end 17 | 18 | method :prepare_engine do 19 | 20 | test "returns an ERB instance" do 21 | e = Malt::Engine::Erb.new 22 | r = e.prepare_engine(:text=>"=

<%= title %>

") 23 | r.assert.is_a? ::ERB 24 | end 25 | 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /lib/malt/engines/ruby.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Ruby return reuslt as template engine. 6 | # 7 | # @todo deprecate ? 8 | # 9 | # @see http://ruby-lang.org 10 | # 11 | class Ruby < Abstract 12 | 13 | default :rb 14 | 15 | # 16 | def render(params={}, &content) 17 | text, file, scope, locals = parameters(params, :text, :file, :scope, :locals) 18 | 19 | bind = make_binding(scope, locals, &content) 20 | eval(text, bind, file || 'eval') 21 | end 22 | 23 | # Ruby compiles to Ruby. How odd. ;) 24 | def compile(params) 25 | params[:text] #file 26 | end 27 | 28 | private 29 | 30 | # 31 | def require_engine 32 | end 33 | 34 | end 35 | 36 | end 37 | 38 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_tenjin.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Tenjin do 2 | 3 | method :render do 4 | 5 | test "render text" do 6 | e = Malt::Engine::Tenjin.new(:text=>'

#{title}

') 7 | h = e.render(:locals=>{:title=>'Testing'}) 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "Tenjin is converstion format agnostic" do 12 | e = Malt::Engine::Tenjin.new 13 | e.render(:to=>:DNE, :text=>'

#{@title}

') 14 | end 15 | 16 | end 17 | 18 | method :prepare_engine do 19 | 20 | test "returns a Tenjin instance" do 21 | e = Malt::Engine::Tenjin.new 22 | r = e.prepare_engine(:text=>'

#{@title}

') 23 | #r.assert.is_a? ::Tenjin::Template 24 | end 25 | 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /lib/malt/engines/string.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Ruby strings as template engine. 6 | # 7 | # @see http://ruby-lang.org 8 | # 9 | class String < Abstract 10 | 11 | default :str 12 | 13 | # 14 | def render(params={}, &content) 15 | text, file, scope, locals = parameters(params, :text, :file, :scope, :locals) 16 | 17 | bind = make_binding(scope, locals, &content) 18 | eval("%{#{text}}", bind, file || '(eval)') 19 | end 20 | 21 | # Ruby compiles to Ruby. How odd. ;) 22 | def compile(params) 23 | text = parameters(params, :text) 24 | "%{#{text}}" 25 | end 26 | 27 | private 28 | 29 | # 30 | def require_engine 31 | end 32 | 33 | end 34 | 35 | end 36 | 37 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_liquid.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Liquid do 2 | 3 | method :render do 4 | 5 | test "convert ERB text" do 6 | e = Malt::Engine::Liquid.new(:text=>"

{{ title }}

") 7 | h = e.render(:locals=>{:title=>'Testing'}) 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "Liquid is converstion format agnostic" do 12 | e = Malt::Engine::Liquid.new 13 | e.render(:to=>:DNE, :text=>"

{{ title }}

") 14 | end 15 | 16 | end 17 | 18 | method :prepare_engine do 19 | 20 | test "returns a Liquid instance" do 21 | e = Malt::Engine::Liquid.new 22 | r = e.prepare_engine(:text=>"

{{ title }}

") 23 | r.assert.is_a? ::Liquid::Template 24 | end 25 | 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_erubis.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Erubis do 2 | 3 | method :render do 4 | 5 | test "convert ERB text" do 6 | e = Malt::Engine::Erubis.new(:text=>"

<%= title %>

") 7 | h = e.render(:locals=>{:title=>'Testing'}) 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "Erubis is converstion format agnostic" do 12 | e = Malt::Engine::Erubis.new 13 | e.render(:to=>:DNE, :text=>"

Testing

") 14 | end 15 | 16 | end 17 | 18 | method :prepare_engine do 19 | 20 | test "returns a Erubius::Eruby instance" do 21 | e = Malt::Engine::Erubis.new 22 | r = e.prepare_engine(:text=>"

<%= title %>

") 23 | r.assert.is_a? ::Erubis::Eruby 24 | end 25 | 26 | end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_mustache.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Mustache do 2 | 3 | method :render do 4 | 5 | test "render text" do 6 | e = Malt::Engine::Mustache.new(:text=>"

{{ title }}

") 7 | h = e.render(:locals=>{:title=>'Testing'}) 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "Mustache is converstion format agnostic" do 12 | e = Malt::Engine::Mustache.new 13 | e.render(:to=>:DNE, :text=>"

{{ title }}

") 14 | end 15 | 16 | end 17 | 18 | #method :prepare_engine do 19 | # 20 | # test "returns a Mustache instance" do 21 | # e = Malt::Engine::Mustache.new 22 | # r = e.iprepare_engine(:text=>"

{{ title }}

") 23 | # r.assert.is_a? ::Mustache 24 | # end 25 | # 26 | #end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_ruby.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Ruby do 2 | 3 | method :render do 4 | 5 | test "convert Ruby Ruby text" do 6 | e = Malt::Engine::Ruby.new(:text=>%q{"Hello " + title}) 7 | h = e.render(:locals=>{:title=>'World!'}) 8 | h.assert.index "Hello World!" 9 | end 10 | 11 | test "Ruby is converstion format agnostic" do 12 | e = Malt::Engine::Ruby.new 13 | e.render(:to=>:DNE, :text=>%q{"Hello " + title}, :locals=>{:title=>'World!'}) 14 | end 15 | 16 | end 17 | 18 | #method :prepare_engine do 19 | # 20 | # test "returns an ::Ruby instance" do 21 | # e = Malt::Engine::Ruby.new 22 | # r = e.prepare_engine(:text=>%q{"Hello #{title}") 23 | # r.assert.is_a? ::Ruby 24 | # end 25 | # 26 | #end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_string.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::String do 2 | 3 | method :render do 4 | 5 | test "render text" do 6 | e = Malt::Engine::String.new(:text=>%q{"Hello #{title}"}) 7 | h = e.render(:locals=>{:title=>'World!'}) 8 | h.assert.index "Hello World!" 9 | end 10 | 11 | test "String is converstion format agnostic" do 12 | e = Malt::Engine::String.new 13 | e.render(:to=>:DNE, :text=>%q{"Hello #{title}"}, :locals=>{:title=>'World!'}) 14 | end 15 | 16 | end 17 | 18 | #method :prepare_engine do 19 | # 20 | # test "returns an ::String instance" do 21 | # e = Malt::Engine::String.new 22 | # r = e.prepare_engine(:text=>%q{"Hello #{title}") 23 | # r.assert.is_a? ::String 24 | # end 25 | # 26 | #end 27 | 28 | end 29 | -------------------------------------------------------------------------------- /test/unit/machine.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Machine do 2 | 3 | method :engine do 4 | 5 | test "corrent engine is used when specified" do 6 | machine = Malt::Machine.new 7 | engine = machine.pry.engine(:erb,:erubis) 8 | engine.assert == Malt::Engine::Erubis 9 | #machine.render(:text=>"<%= title %>", :type=>:erb, :engine=>:erubis, :data=>{:title=>'Testing'}) 10 | #RR.verify 11 | end 12 | 13 | end 14 | 15 | method :render do 16 | 17 | test "corrent engine is used when specified" do 18 | machine = Malt::Machine.new 19 | #mock(machine).engine(:erb,:erubis){ Malt::Engine::Erubis } 20 | machine.render(:text=>"<%= title %>", :type=>:erb, :engine=>:erubis, :data=>{:title=>'Testing'}) 21 | #RR.verify 22 | end 23 | 24 | end 25 | 26 | 27 | end 28 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_maruku.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Maruku do 2 | 3 | method :render do 4 | 5 | test "convert Maruku text" do 6 | e = Malt::Engine::Maruku.new(:text=>"# Testing") 7 | h = e.render 8 | h.assert.index '

Testing

' 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Maruku.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"# Testing") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an ::Maruku instance" do 23 | e = Malt::Engine::Maruku.new 24 | r = e.prepare_engine(:text=>"# Testing") 25 | r.assert.is_a? ::Maruku 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_haml.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Haml do 2 | 3 | method :render do 4 | 5 | test "convert Haml DSL to XML by default" do 6 | e = Malt::Engine::Haml.new(:text=>"%h1 Testing") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Haml.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"%h1 Testing") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an ::Haml::Engine instance" do 23 | e = Malt::Engine::Haml.new 24 | r = e.prepare_engine(:text=>"%h1 Testing") 25 | r.assert.is_a? ::Haml::Engine 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_rdiscount.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::RDiscount do 2 | 3 | method :render do 4 | 5 | test "convert RDiscount text" do 6 | e = Malt::Engine::RDiscount.new(:text=>"# Testing") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::RDiscount.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"# Testing") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an ::RDiscount instance" do 23 | e = Malt::Engine::RDiscount.new 24 | r = e.prepare_engine(:text=>"# Testing") 25 | r.assert.is_a? ::RDiscount 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_redcarpet.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Redcarpet do 2 | 3 | method :render do 4 | 5 | test "render text" do 6 | e = Malt::Engine::Redcarpet.new(:text=>"# Testing") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Redcarpet.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"# Testing") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an ::Redcarpet instance" do 23 | e = Malt::Engine::Redcarpet.new 24 | r = e.prepare_engine(:text=>"# Testing") 25 | r.assert.is_a? ::Redcarpet::Markdown 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /lib/malt/formats/latex.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/pdf' 3 | 4 | module Malt::Format 5 | 6 | # 7 | class Latex < Abstract 8 | 9 | file_extension 'latex' 10 | 11 | # 12 | def latex(*) 13 | text 14 | end 15 | 16 | # 17 | def to_latex(*) 18 | self 19 | end 20 | 21 | # TODO 22 | def pdf(*) 23 | raise "not implemented yet" 24 | end 25 | 26 | # TODO 27 | def to_pdf(*) 28 | text = pdf 29 | opts = options.merge(:text=>text, :file=>refile(:pdf), :type=>:pdf) 30 | PDF.new(opts) 31 | end 32 | 33 | private 34 | 35 | # 36 | def render_engine 37 | end 38 | 39 | # Latext default output type is PDF. 40 | def default 41 | :pdf 42 | end 43 | 44 | end 45 | 46 | end 47 | 48 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_kramdown.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Kramdown do 2 | 3 | method :render do 4 | 5 | test "convert Kramdown text" do 6 | e = Malt::Engine::Kramdown.new(:text=>"# Testing") 7 | h = e.render 8 | h.assert.index %{

Testing

} 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Kramdown.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"# Testing") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an ::Kramdown instance" do 23 | e = Malt::Engine::Kramdown.new 24 | r = e.prepare_engine(:text=>"# Testing") 25 | r.assert.is_a? ::Kramdown::Document 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_redcloth.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::RedCloth do 2 | 3 | method :render do 4 | 5 | test "render text" do 6 | e = Malt::Engine::RedCloth.new(:text=>"h1. Testing") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::RedCloth.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"h1. Testing") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an ::RedCloth instance" do 23 | e = Malt::Engine::RedCloth.new 24 | r = e.prepare_engine(:text=>"h1. Testing") 25 | #RedCloth.assert === r 26 | String.assert === r 27 | end 28 | 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /INDEX.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: 3 | malt 4 | 5 | version: 6 | 0.4.1 7 | 8 | title: 9 | Malt 10 | 11 | summary: 12 | Multi-template/multi-markup rendering engine. 13 | 14 | description: 15 | Malt provides a factory framework for rendering a variety 16 | of template and markup document formats. 17 | 18 | resources: 19 | home: http://rubyworks.github.com/malt 20 | code: http://github.com/rubyworks/malt 21 | wiki: http://wiki.github.com/rubyworks/malt 22 | docs: http://rubyworks.github.com/malt/docs/api 23 | bugs: http://github.com/rubyworks/malt/issues 24 | 25 | respositories: 26 | upstream: git@github.com:rubyworks/malt.git 27 | 28 | authors: 29 | - trans 30 | 31 | organizations: 32 | - Rubyworks 33 | 34 | created: 35 | 2010-06-22 36 | 37 | copyrights: 38 | - (c) 2010 Rubyworks (BSD-2-Clause) 39 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_builder.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Builder do 2 | 3 | method :render do 4 | 5 | test "convert Builder DSL to XML by default" do 6 | e = Malt::Engine::Builder.new(:text=>%[h1 "Testing"]) 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Builder.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>%[h1 "Testing"]) 15 | end 16 | end 17 | 18 | end 19 | 20 | method :create_engine do 21 | 22 | test "returns an ::Builder::XmlMarkup instance" do 23 | e = Malt::Engine::Builder.new 24 | r = e.create_engine(:text=>%[h1 "Testing"]) 25 | r.assert.is_a? ::Builder::XmlMarkup 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /lib/malt/formats/ruby.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/engines/erb' 3 | 4 | module Malt::Format 5 | 6 | # Yes, pure Ruby as a template format. 7 | # 8 | # The ruby code is run through eval and whatever it returns is given 9 | # as the rendering. 10 | # 11 | # The Ruby format is a *polyglot* format --it accepts all conversion 12 | # types and assumes the end-user knows it will be the result. 13 | # 14 | # In the future, the Ruby type might also used for "precompiling" other 15 | # formats such as ERB. 16 | # 17 | class Ruby < AbstractTemplate 18 | 19 | file_extension 'rb' 20 | 21 | # 22 | def rb(*) 23 | text 24 | end 25 | 26 | alias_method :ruby, :rb 27 | 28 | # 29 | def to_rb(*) 30 | self 31 | end 32 | 33 | alias_method :to_ruby, :to_rb 34 | 35 | end 36 | 37 | end 38 | -------------------------------------------------------------------------------- /test/benchmarks/malt_vs_tilt.rb: -------------------------------------------------------------------------------- 1 | require 'benchmark' 2 | require 'malt' 3 | require 'tilt' 4 | 5 | dir = File.dirname(__FILE__) 6 | 7 | file = dir + '/../fixtures/sample.erb' 8 | rdoc = dir + '/../fixtures/sample.rdoc' 9 | 10 | data = { 11 | :page_title => "Demonstration of ERb", 12 | :salutation => "Dear programmer," 13 | } 14 | 15 | count = 1000 16 | 17 | puts "#{count} Times" 18 | puts 19 | puts "Tilt" 20 | 21 | Benchmark.bmbm do |bm| 22 | bm.report("Tilt ERB") { count.times{ Tilt.new(file).render(nil, data) } } 23 | bm.report("Tilt RDoc") { count.times{ Tilt.new(rdoc).render(nil, data) } } 24 | end 25 | 26 | puts 27 | puts "Malt" 28 | 29 | Benchmark.bmbm do |bm| 30 | bm.report("Malt ERB") { count.times{ Malt.render(:file=>file, :locals=>data) } } 31 | bm.report("Malt RDoc") { count.times{ Malt.render(:file=>rdoc, :locals=>data) } } 32 | end 33 | 34 | -------------------------------------------------------------------------------- /lib/malt/conversions.rb: -------------------------------------------------------------------------------- 1 | module Malt 2 | 3 | module Conversions 4 | 5 | module Binding 6 | extend self 7 | 8 | # 9 | def to_binding(binding) 10 | binding 11 | end 12 | 13 | # 14 | def to_hash(binding) 15 | Hash.new{ |h,k| h[k] = binding.eval(k) } 16 | end 17 | 18 | # 19 | def to_object(binding) 20 | obj = binding.eval("self") 21 | 22 | vars = binding.eval("local_variables") 23 | vals = binding.eval("[#{vars.join(',')}]") 24 | data = Hash[*vars.zip(vals).flatten] 25 | 26 | adhoc = (class << obj; self; end) 27 | data.each do |name,value| 28 | adhoc.__send__(:define_method, name){ value } 29 | end 30 | 31 | obj 32 | end 33 | 34 | end 35 | 36 | module Object 37 | 38 | end 39 | 40 | end 41 | 42 | end 43 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_nokogiri.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Nokogiri do 2 | 3 | method :render do 4 | 5 | test "convert Nokogiri DSL to XML by default" do 6 | e = Malt::Engine::Nokogiri.new(:text=>%[h1 "Testing"]) 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Nokogiri.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>%[h1 "Testing"]) 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns a ::Nokogiri::XML::Builder instance" do 23 | e = Malt::Engine::Nokogiri.new 24 | r = e.prepare_engine(:text=>%[h1 "Testing"]) 25 | r.assert.is_a? ::Nokogiri::XML::Builder 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_radius.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Radius do 2 | 3 | method :render do 4 | 5 | test "convert Radius DSL to XML by default" do 6 | e = Malt::Engine::Radius.new(:text=>"

Testing

") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Radius.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"

Testing

") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an instance of a subclass of ::Radius::Context" do 23 | e = Malt::Engine::Radius.new 24 | r = e.prepare_engine(:text=>"

Testing

") 25 | r.assert.is_a? ::Radius::Context 26 | end 27 | 28 | end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_rdoc.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::RDoc do 2 | 3 | method :render do 4 | 5 | test "render text" do 6 | e = Malt::Engine::RDoc.new(:text=>"= Testing") 7 | h = e.render 8 | #h.assert.index '

Testing

' 9 | h.assert.index 'Testing' 10 | end 11 | 12 | test "raises NotImplementedError if converstion format not supported" do 13 | e = Malt::Engine::RDoc.new 14 | expect NotImplementedError do 15 | e.render(:to=>:DNE, :text=>"= Testing") 16 | end 17 | end 18 | 19 | end 20 | 21 | method :prepare_engine do 22 | 23 | test "returns an ::RDoc::Markup::ToHtml instance" do 24 | e = Malt::Engine::RDoc.new 25 | r = e.prepare_engine(:text=>"= Testing") 26 | r.assert.is_a? ::RDoc::Markup::ToHtml 27 | end 28 | 29 | end 30 | 31 | end 32 | -------------------------------------------------------------------------------- /lib/malt/formats/rdoc.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/rdoc' 4 | 5 | module Malt::Format 6 | 7 | # 8 | class RDoc < Abstract 9 | 10 | file_extension 'rdoc' 11 | 12 | # 13 | def rdoc(*) 14 | text 15 | end 16 | 17 | # 18 | def to_rdoc(*) 19 | self 20 | end 21 | 22 | # 23 | def html(*data, &content) 24 | render_into(:html, *data, &content) 25 | #render_engine.render(:format=>:html, :text=>text, :file=>file) 26 | end 27 | 28 | # 29 | def to_html(*) 30 | opts = options.merge(:type=>:html, :text=>html, :file=>refile(:html)) 31 | HTML.new(opts) 32 | end 33 | 34 | private 35 | 36 | # 37 | def render_engine 38 | @render_engine ||= Malt::Engine::RDoc.new(options) 39 | end 40 | 41 | end 42 | 43 | end 44 | 45 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_coffee.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Coffee do 2 | 3 | method :render do 4 | 5 | test "convert Coffee text" do 6 | e = Malt::Engine::Coffee.new(:text=>"square = (x) -> x * x") 7 | h = e.render 8 | h.assert.index "square = function(x) {\n return x * x;\n };" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Coffee.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"square = (x) -> x * x") 15 | end 16 | end 17 | 18 | end 19 | 20 | #method :intermediate do 21 | # 22 | # test "returns an ::Coffee instance" do 23 | # e = Malt::Engine::Coffee.new 24 | # r = e.intermediate(:text=>"square = (x) -> x * x") 25 | # r.assert.is_a? ::Coffee 26 | # end 27 | # 28 | #end 29 | 30 | end 31 | -------------------------------------------------------------------------------- /lib/malt/formats/textile.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/engines/redcloth' 3 | 4 | module Malt::Format 5 | 6 | # 7 | class Textile < Abstract 8 | 9 | file_extension 'textile', 'tt' 10 | 11 | # 12 | def textile(*) 13 | text 14 | end 15 | 16 | # 17 | alias_method :tt, :textile 18 | 19 | # 20 | def to_textile(*) 21 | self 22 | end 23 | 24 | alias_method :to_tt, :to_textile 25 | 26 | # 27 | def html(*data, &content) 28 | render_into(:html, *data, &content) 29 | end 30 | 31 | # 32 | def to_html(*) 33 | opts = options.merge(:text=>html, :file=>refile(:html), :type=>:html) 34 | HTML.new(opts) 35 | end 36 | 37 | #private 38 | # 39 | ## 40 | #def render_engine 41 | # @render_engine ||= Malt::Engine::RedCloth.new(options) 42 | #end 43 | 44 | end 45 | 46 | end 47 | 48 | -------------------------------------------------------------------------------- /work/consider/06_tilted.rdoc: -------------------------------------------------------------------------------- 1 | # Tilted 2 | 3 | Malt provides a Tile compatability layer, which can be used as a drop 4 | in replacement for Tilt in most cases. 5 | 6 | require 'malt/tilted' 7 | 8 | Now we can use Malt as if it were Tilt. 9 | 10 | Lets say we have an ERB document called 'foo.erb' containing: 11 | 12 | Hello world! 13 | 14 | Then just like with Tilt, 15 | 16 | template = Tilt.new('foo.erb') 17 | output = template.render 18 | 19 | output #=> "Hello world!" 20 | 21 | Lets say we have an ERB document called 'foo.erb' containing: 22 | 23 | Hey <%= yield %>! 24 | 25 | Then we can supply a block to the render method. 26 | 27 | template = Tilt::ERBTemplate.new('foo.erb') 28 | template.render { 'Joe' } #=> "Hey Joe!" 29 | 30 | Let's try Erubis for good measure. 31 | 32 | template = Tilt::ErubisTemplate.new('foo.erb') 33 | template.render { 'Joe' } #=> "Hey Joe!" 34 | 35 | 36 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_creole.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Creole do 2 | 3 | method :render do 4 | 5 | test "convert media wiki text to HTML by default" do 6 | e = Malt::Engine::Creole.new(:text=>"== Testing ==") 7 | h = e.render 8 | h.assert.index "

" # so complicated that we're lucky to find it ;) 9 | h.assert.index "Testing" 10 | end 11 | 12 | end 13 | 14 | method :prepare_engine do 15 | 16 | test "returns a Creole instance" do 17 | e = Malt::Engine::Creole.new 18 | r = e.prepare_engine(:text=>"== Testing ==") 19 | r.assert.is_a? ::Creole::Parser 20 | end 21 | 22 | end 23 | 24 | method :create_engine do 25 | 26 | test "returns a Creole instance" do 27 | e = Malt::Engine::Creole.new 28 | r = e.create_engine(:text=>"== Testing ==") 29 | r.assert.is_a? ::Creole::Parser 30 | end 31 | 32 | end 33 | 34 | end 35 | 36 | -------------------------------------------------------------------------------- /lib/malt/formats/scss.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/css' 3 | require 'malt/engines/sass' 4 | 5 | module Malt::Format 6 | 7 | # SCSS Format 8 | # 9 | # This uses the same engine as Sass. 10 | class SCSS < Abstract 11 | 12 | file_extension 'scss' 13 | 14 | # 15 | def scss(*) 16 | text 17 | end 18 | 19 | # 20 | def to_scss(*) 21 | self 22 | end 23 | 24 | # 25 | def css(*data, &content) 26 | render_into(:css, *data, &content) 27 | end 28 | 29 | # 30 | def to_css(*data, &content) 31 | result = css(*data, &content) 32 | CSS.new(:text=>result, :file=>refile(:css), :type=>:css) 33 | end 34 | 35 | private 36 | 37 | ## 38 | #def render_engine 39 | # @render_engine ||= Malt::Engine::Sass.new(options) 40 | #end 41 | 42 | # Sass default output type is CSS. 43 | def default 44 | :css 45 | end 46 | 47 | end 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'blankslate' 4 | 5 | group :build, :development do 6 | gem 'detroit' 7 | end 8 | 9 | group :test, :development do 10 | gem 'qed' 11 | gem 'rubytest' 12 | gem 'rubytest-cli' 13 | gem 'lemon' 14 | gem 'ae' 15 | gem 'rdoc', '>= 3' 16 | gem 'RedCloth' 17 | gem 'bluecloth' 18 | gem 'kramdown' 19 | gem 'rdiscount' 20 | gem 'haml' 21 | gem 'sass' 22 | gem 'less' 23 | gem 'tenjin' 24 | gem 'liquid' 25 | gem 'erubis' 26 | gem 'mustache' 27 | gem 'markaby' 28 | gem 'builder' 29 | gem 'radius' 30 | gem 'ragtag' 31 | gem 'redcarpet' 32 | gem 'wikicloth' 33 | gem 'maruku' 34 | gem 'creole' 35 | gem 'erector' 36 | gem 'coffee-script' 37 | end 38 | 39 | ## JRuby can't compile libv8 which both less and coffee-script gems depend. 40 | #if defined?(RUBY_ENGINE) 41 | # if RUBY_ENGINE == 'jruby' 42 | # @dependencies.reject!{ |d| d.name == 'less' or d.name == 'coffee-script' } 43 | # end 44 | #end 45 | 46 | -------------------------------------------------------------------------------- /demo/04sgml/06ragtag/08_ragtag.rdoc: -------------------------------------------------------------------------------- 1 | == RagTag 2 | 3 | Lets say we have a RagTag document called 'test.rt' containing: 4 | 5 | 6 | 7 |

Example DUMMY

8 |

This is an example of a RagTag template.

9 | 10 | 11 | 12 | We can render Rtal documents via the +render+ method, as we can any format. 13 | 14 | data = {:title=>"Document"} 15 | 16 | html = Malt.render(:file=>'test.rt', :data=>data) 17 | 18 | html.assert.include?('

Example Document

') 19 | 20 | === Content Blocks 21 | 22 | Lets say we have a RagTag document called 'test.rt' containing: 23 | 24 | 25 | 26 |

Example DUMMY

27 |
DUMMY
28 | 29 | 30 | 31 | Then 32 | 33 | data = {:title=>"Document"} 34 | 35 | html = Malt.render(:file=>'test.rt', :data=>data){ 'Content' } 36 | 37 | html.assert.include?('
Content
') 38 | 39 | -------------------------------------------------------------------------------- /lib/malt/formats/yaml.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | 4 | module Malt::Format 5 | 6 | # = YAML format 7 | # 8 | # TODO: hmm... maybe use data to update yaml? 9 | class YAML < Abstract 10 | 11 | register 'yaml', 'yml' 12 | 13 | # 14 | def yaml(*) 15 | text 16 | end 17 | 18 | alias_method :yml, :yaml 19 | 20 | # 21 | def to_yaml(*) 22 | self 23 | end 24 | 25 | alias_method :to_yml, :to_yaml 26 | 27 | # Converting a plan YAML file to HTML makes no sense so we 28 | # just wrap it in +pre+ tags. 29 | def html(*) 30 | "
\n#{h text}\n
" 31 | end 32 | 33 | # 34 | def to_html(*) 35 | text = html 36 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 37 | HTML.new(opts) 38 | end 39 | 40 | private 41 | 42 | # TODO: HTML escaping 43 | def h(text) 44 | text 45 | end 46 | 47 | end 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /lib/malt/formats/radius.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/radius' 4 | 5 | module Malt::Format 6 | 7 | # Radius Template 8 | # 9 | # http://github.com/jlong/radius/ 10 | # 11 | class Radius < Abstract 12 | 13 | register('radius') 14 | 15 | # 16 | def radius(*) 17 | text 18 | end 19 | 20 | # 21 | def to_radius(*) 22 | self 23 | end 24 | 25 | # 26 | def html(*data, &content) 27 | render_into(:html, *data, &content) 28 | #render_engine.render(:text=>text, :file=>file, :data=>data, &yld) 29 | end 30 | 31 | # 32 | def to_html(*data, &content) 33 | text = html(*data, &content) 34 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 35 | HTML.new(opts) 36 | end 37 | 38 | private 39 | 40 | # 41 | def render_engine 42 | @render_engine ||= Malt::Engine::Radius.new(options) 43 | end 44 | 45 | end 46 | 47 | end 48 | 49 | -------------------------------------------------------------------------------- /lib/malt/engines/haml.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Haml 6 | # 7 | class Haml < Abstract 8 | 9 | default :haml 10 | 11 | # 12 | def render(params={}, &content) 13 | into, scope, locals = parameters(params, :to, :scope, :locals) 14 | 15 | scope, locals = make_ready(scope, locals, &content) 16 | 17 | case into 18 | when :html, nil 19 | prepare_engine(params, &content).render(scope, locals, &content) 20 | else 21 | super(params, &content) 22 | end 23 | end 24 | 25 | # 26 | def create_engine(params={}) 27 | text, file = parameters(params, :text, :file) 28 | cached(text, file) do 29 | ::Haml::Engine.new(text, :filename=>file) 30 | end 31 | end 32 | 33 | private 34 | 35 | # Load Haml library if not already loaded. 36 | def require_engine 37 | return if defined? ::Haml::Engine 38 | require_library 'haml' 39 | end 40 | 41 | end 42 | 43 | end 44 | 45 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_erector.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Erector do 2 | 3 | method :render do 4 | 5 | test "convert Erector template" do 6 | e = Malt::Engine::Erector.new(:text=>"h1 'Testing'") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | end 12 | 13 | # NOTE: truth is these will probably become private so there isn't 14 | # really necessary to test them directly. 15 | 16 | method :prepare_engine do 17 | 18 | test "returns an instance of a subclass of Erector::Widget" do 19 | e = Malt::Engine::Erector.new 20 | r = e.prepare_engine(:text=>"h1 'Testing'") 21 | assert r.is_a?(::Erector::Widget) # do it this way b/c of odd warning 22 | end 23 | 24 | end 25 | 26 | method :create_engine do 27 | 28 | test "returns a subclass of Erector::Widget" do 29 | e = Malt::Engine::Erector.new 30 | r = e.create_engine(:text=>"h1 'Testing'") 31 | r.assert < ::Erector::Widget 32 | end 33 | 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_sass.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Sass do 2 | 3 | method :render do 4 | 5 | test "convert SASS to CSS by default" do 6 | e = Malt::Engine::Sass.new(:text=>"#menu\n :margin 0") 7 | h = e.render 8 | h.assert.index "#menu {\n margin: 0; }\n" 9 | end 10 | 11 | test "convert SCSS to CSS" do 12 | e = Malt::Engine::Sass.new 13 | h = e.render(:text=>"#menu{ margin: 0 }", :type=>:scss) 14 | h.assert.index "#menu {\n margin: 0; }\n" 15 | end 16 | 17 | test "raises NotImplementedError if converstion format not supported" do 18 | e = Malt::Engine::Sass.new 19 | expect NotImplementedError do 20 | e.render(:to=>:DNE, :text=>"#menu\n :margin 0") 21 | end 22 | end 23 | 24 | end 25 | 26 | method :prepare_engine do 27 | 28 | test "returns an ::Sass instance" do 29 | e = Malt::Engine::Sass.new 30 | r = e.prepare_engine(:text=>"#menu\n :margin 0") 31 | r.assert.is_a? ::Sass::Engine 32 | end 33 | 34 | end 35 | 36 | end 37 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_bluecloth.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::BlueCloth do 2 | 3 | method :render do 4 | 5 | test "convert BlueCloth text" do 6 | e = Malt::Engine::BlueCloth.new(:text=>"# Testing") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::BlueCloth.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"# Testing") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns a ::BlueCloth instance" do 23 | e = Malt::Engine::BlueCloth.new 24 | r = e.prepare_engine(:text=>"# Testing") 25 | r.assert.is_a? ::BlueCloth 26 | end 27 | 28 | end 29 | 30 | method :create_engine do 31 | 32 | test "returns a ::BlueCloth instance" do 33 | e = Malt::Engine::BlueCloth.new 34 | r = e.create_engine(:text=>"# Testing") 35 | r.assert.is_a? ::BlueCloth 36 | end 37 | 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /lib/malt/engines/redcloth.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Redcloth handles textile markup. 6 | # 7 | # @see http://redcloth.org/ 8 | 9 | class RedCloth < Abstract 10 | 11 | default :tt, :textile 12 | 13 | # Convert textile text to html. 14 | # 15 | # params: 16 | # 17 | # :format => Symbol of the format to render [:html] 18 | # 19 | def render(params={}) 20 | into, text = parameters(params, :to, :text) 21 | 22 | case into 23 | when :html, nil 24 | prepare_engine(params).to_html 25 | else 26 | super(params) 27 | end 28 | end 29 | 30 | # 31 | def create_engine(params={}) 32 | text = parameters(params, :text) 33 | 34 | cached(text) do 35 | ::RedCloth.new(text) 36 | end 37 | end 38 | 39 | private 40 | 41 | # Load redcloth library if not already loaded. 42 | def require_engine 43 | return if defined? ::RedCloth 44 | require_library 'redcloth' 45 | end 46 | 47 | end 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /lib/malt/formats/less.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/engines/less' 3 | 4 | module Malt::Format 5 | 6 | # = LESS 7 | # 8 | # See http://lesscss.org/ 9 | # 10 | class LESS < Abstract 11 | 12 | file_extension 'less' 13 | 14 | # 15 | def less(*) 16 | text 17 | end 18 | 19 | # 20 | def to_less(*) 21 | self 22 | end 23 | 24 | # 25 | def css(*data, &content) 26 | render_into(:css, *data, &content) 27 | #opts = options.merge(:text=>text, :file=>file, :format=>:css) 28 | #render_engine.render(opts) 29 | end 30 | 31 | # 32 | def to_css(*data, &content) 33 | text = css(*data, &content) 34 | opts = options.merge(:text=>text, :file=>refile(:css), :type=>:css) 35 | CSS.new(opts) 36 | end 37 | 38 | # private 39 | # 40 | # # 41 | # def render_engine 42 | # @render_engine ||= Malt::Engine::Less.new(options) 43 | # end 44 | 45 | # LESS default output type is CSS. 46 | def default 47 | :css 48 | end 49 | 50 | end 51 | 52 | end 53 | 54 | -------------------------------------------------------------------------------- /lib/malt/engines/coffee.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Coffee Malt Engine 6 | # 7 | class Coffee < Abstract 8 | 9 | default :coffee 10 | 11 | # Render coffee script to JavaScript. 12 | def render(params={}, &content) 13 | into, text, file = parameters(params, :to, :text, :file) 14 | 15 | case into 16 | when :javascript, :js, nil 17 | ::CoffeeScript.compile(text, engine_options(params)) 18 | else 19 | super(params, &content) 20 | end 21 | end 22 | 23 | # TODO: make a psuedo intermediate ? 24 | # def prepare_engine(params) 25 | # 26 | # end 27 | 28 | private 29 | 30 | # Load CoffeeScript library if not already loaded. 31 | def require_engine 32 | return if defined? ::CoffeeScript 33 | require_library 'coffee_script' 34 | end 35 | 36 | # 37 | def engine_options(params) 38 | options = {} 39 | options[:bare] = params[:bare] || params[:no_wrap] || false 40 | options 41 | end 42 | 43 | end 44 | 45 | end 46 | 47 | -------------------------------------------------------------------------------- /lib/malt/engines/bluecloth.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # 6 | class BlueCloth < Abstract 7 | 8 | register :markdown, :md 9 | 10 | # Convert Markdown text to HTML text. 11 | def render(params={}) 12 | into = params[:to] 13 | 14 | text = parameters(params, :text) 15 | 16 | case into 17 | when :html, nil 18 | prepare_engine(params).to_html 19 | else 20 | super(params) 21 | end 22 | end 23 | 24 | # Prepare engine for rendering. 25 | #def prepare_engine(params={}) 26 | # create_engine(params) 27 | #end 28 | 29 | # Instantiate engine class and cache if applicable. 30 | def create_engine(params={}) 31 | text = parameters(params, :text) 32 | 33 | cached(text) do 34 | ::BlueCloth.new(text) 35 | end 36 | end 37 | 38 | private 39 | 40 | # Load bluecloth library if not already loaded. 41 | def require_engine 42 | return if defined? ::BlueCloth 43 | require_library 'bluecloth' 44 | end 45 | 46 | end 47 | 48 | end 49 | 50 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_less.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::Less do 2 | 3 | method :render do 4 | 5 | test "convert LESS to CSS" do 6 | e = Malt::Engine::Less.new(:text=>"#menu {\n margin: 0; }") 7 | h = e.render 8 | h.assert.index "#menu {\n margin: 0;\n}\n" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::Less.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"#menu {\n margin: 0; }") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an Less::Tree instance" do 23 | e = Malt::Engine::Less.new 24 | r = e.prepare_engine(:text=>"#menu {\n margin: 0; }") 25 | r.assert.is_a? ::Less::Tree 26 | end 27 | 28 | end 29 | 30 | method :create_engine do 31 | 32 | test "returns an Less::Tree instance" do 33 | e = Malt::Engine::Less.new 34 | r = e.create_engine(:text=>"#menu {\n margin: 0; }") 35 | r.assert.is_a? ::Less::Tree 36 | end 37 | 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /test/unit/engines/case_engine_ragtag.rb: -------------------------------------------------------------------------------- 1 | testcase Malt::Engine::RagTag do 2 | 3 | method :render do 4 | 5 | test "convert RagTag DSL to XML by default" do 6 | e = Malt::Engine::RagTag.new(:text=>"

Testing

") 7 | h = e.render 8 | h.assert.index "

Testing

" 9 | end 10 | 11 | test "raises NotImplementedError if converstion format not supported" do 12 | e = Malt::Engine::RagTag.new 13 | expect NotImplementedError do 14 | e.render(:to=>:DNE, :text=>"

Testing

") 15 | end 16 | end 17 | 18 | end 19 | 20 | method :prepare_engine do 21 | 22 | test "returns an ::Nokogiri document" do 23 | e = Malt::Engine::RagTag.new 24 | r = e.prepare_engine(:text=>"

Testing

") 25 | r.assert.is_a? ::Nokogiri::XML::Document 26 | end 27 | 28 | end 29 | 30 | method :create_engine do 31 | 32 | test "returns an ::RagTag::Engine instance" do 33 | e = Malt::Engine::RagTag.new 34 | r = e.create_engine(:text=>"

Testing

") 35 | r.assert.is_a? ::RagTag 36 | end 37 | 38 | end 39 | 40 | end 41 | -------------------------------------------------------------------------------- /demo/01general/05_machine/02_prioritized_engines.rdoc: -------------------------------------------------------------------------------- 1 | == Prioritized Engines 2 | 3 | The Malt Machine class can also be used to prioritize engines. 4 | For instance, by default markdown documents are handled by 5 | the RDiscount library. 6 | 7 | malt = Malt::Machine.new 8 | 9 | engine = malt.pry.engine(:markdown) 10 | engine.assert == Malt::Engine::RDiscount 11 | 12 | To use Kramdown instead, we can specify 13 | it as a priority when initilizeing a new Machine. 14 | 15 | malt = Malt::Machine.new(:priority=>[:kramdown]) 16 | 17 | Lets check to make sure. 18 | 19 | engine = malt.pry.engine(:markdown) 20 | engine.assert == Malt::Engine::Kramdown 21 | 22 | To change the engine priorities of the master Malt Machine, provide 23 | the #priority method with the type and it will put it at the top of 24 | the priority list. 25 | 26 | Malt.machine.priority :kramdown 27 | 28 | Lets check to make sure. 29 | 30 | engine = Malt.machine.pry.engine(:markdown) 31 | engine.assert == Malt::Engine::Kramdown 32 | 33 | (If you are wondering, #pry is simply used to call a private method.) 34 | 35 | -------------------------------------------------------------------------------- /lib/malt/formats/haml.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/haml' 4 | 5 | module Malt::Format 6 | 7 | # Haml looks like a Markup format, but it turns out to be 8 | # a template format too. 9 | class Haml < Abstract 10 | 11 | register 'haml' 12 | 13 | # 14 | def haml(*) 15 | text 16 | end 17 | 18 | # 19 | def to_haml(*) 20 | self 21 | end 22 | 23 | # 24 | def html(*data, &content) 25 | render_into(:html, *data, &content) 26 | end 27 | 28 | # 29 | def to_html(*data, &content) 30 | text = html(*data, &content) 31 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 32 | HTML.new(opts) 33 | end 34 | 35 | # 36 | #def to_ruby(db, &yld) 37 | # @ruby ||= ( 38 | # source = engine.compile(text, file) 39 | # Ruby.new(:text=>source, :file=>refile(:rb)) 40 | # ) 41 | #end 42 | 43 | #private 44 | 45 | # 46 | #def render_engine 47 | # @render_engine ||= Malt::Engine::Haml.new(options) 48 | #end 49 | 50 | end 51 | 52 | end 53 | 54 | -------------------------------------------------------------------------------- /lib/malt/engines/wikicloth.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # WikiCloth is a MediaWiki format for Ruby. Unlike Creole, WikiCloth 6 | # also supports variable interpolation. 7 | # 8 | #@see http://code.google.com/p/wikicloth/ 9 | 10 | class WikiCloth < Abstract 11 | 12 | default :wiki, :mediawiki, :mw 13 | 14 | # 15 | def render(params={}, &content) 16 | scope, locals = parameters(params, :scope, :locals) 17 | 18 | data = make_hash(scope, locals, &content) 19 | 20 | case params[:to] 21 | when :html, nil 22 | prepare_engine(params).to_html(:params => data) 23 | else 24 | super(params) 25 | end 26 | end 27 | 28 | # 29 | def create_engine(params={}) 30 | text = parameters(params, :text) 31 | 32 | cached(text) do 33 | ::WikiCloth::WikiCloth.new(:data => text) 34 | end 35 | end 36 | 37 | private 38 | 39 | # Load `wikicloth` library if not already loaded. 40 | def require_engine 41 | return if defined? ::WikiCloth 42 | require_library 'wikicloth' 43 | end 44 | 45 | end 46 | 47 | end 48 | 49 | -------------------------------------------------------------------------------- /lib/malt/formats/tenjin.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract_template' 2 | require 'malt/formats/html' 3 | require 'malt/engines/tenjin' 4 | 5 | module Malt::Format 6 | 7 | # Tenjin 8 | # 9 | # http://www.kuwata-lab.com/tenjin/ 10 | # 11 | class Tenjin < AbstractTemplate 12 | 13 | register 'tenjin' 14 | 15 | def rb(*) 16 | render_engine.compile(text, file) 17 | end 18 | 19 | # Erb templates can be "precompiled" into Ruby templates. 20 | def to_rb(*) 21 | text = rb 22 | Ruby.new(:text=>text, :file=>refile(:rb), :type=>:rb) 23 | end 24 | 25 | alias_method(:to_ruby, :to_rb) 26 | 27 | # 28 | def html(*data, &content) 29 | render_into(:html, *data, &content) 30 | end 31 | 32 | # 33 | def to_html(*data, &yld) 34 | new_text = render(:html, *data, &yld) 35 | new_file = refile(:html) 36 | new_options = options.merge(:text=>new_text, :file=>new_file, :type=>:html) 37 | HTML.new(new_options) 38 | end 39 | 40 | private 41 | 42 | # 43 | def render_engine 44 | @render_engine ||= Malt::Engine::Tenjin.new(options) 45 | end 46 | 47 | end 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /lib/malt/engines/less.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # LESS is an extension of CSS. You can write LESS code just like you 6 | # would write CSS, except you need to compile it to CSS. 7 | # 8 | # @see http://lesscss.org/ 9 | # 10 | class Less < Abstract 11 | 12 | default :less 13 | 14 | # 15 | def render(params={}) 16 | into, text, compress = parameters(params, :to, :text, :compress) 17 | 18 | case into 19 | when :css, nil 20 | prepare_engine(params).to_css(:compress=>compress) 21 | else 22 | super(params) 23 | end 24 | end 25 | 26 | # 27 | def create_engine(params={}) 28 | text, file = parameters(params, :text, :file) 29 | cached(text, file) do 30 | ::Less::Parser.new(:filename=>file).parse(text) 31 | end 32 | end 33 | 34 | # 35 | #def compile(text, file) 36 | # intermediate # ?? 37 | #end 38 | 39 | private 40 | 41 | # Load Less library if not already loaded. 42 | def require_engine 43 | return if defined? ::Less::Parser 44 | require_library 'less' 45 | end 46 | 47 | end 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /lib/malt/formats/coffee.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/javascript' 3 | require 'malt/engines/coffee' 4 | 5 | module Malt::Format 6 | 7 | # Coffee Format 8 | # 9 | class Coffee < Abstract 10 | 11 | file_extension 'coffee' 12 | 13 | # 14 | def coffee(*) 15 | text 16 | end 17 | 18 | # 19 | def to_coffee(*) 20 | self 21 | end 22 | 23 | # 24 | def javascript(*data, &content) 25 | #render_engine.render(:format=>:javascript, :text=>text, :file=>file, :data=>data, :type=>type, &yielding) 26 | render_into(:javascript, *data, &content) 27 | end 28 | 29 | alias :js :javascript 30 | 31 | # 32 | def to_javascript(*data, &content) 33 | result = javascript(*data, &content) 34 | Javascript.new(:text=>result, :file=>refile(:js), :type=>:javascript) 35 | end 36 | 37 | alias :to_js :to_javascript 38 | 39 | private 40 | 41 | # 42 | #def render_engine 43 | # @render_engine ||= Malt::Engine::Coffee.new(options) 44 | #end 45 | 46 | # Coffee default output type is Javascript. 47 | def default 48 | :javascript 49 | end 50 | 51 | end 52 | 53 | end 54 | 55 | -------------------------------------------------------------------------------- /lib/malt/formats/ragtag.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/formats/xml' 4 | require 'malt/engines/ragtag' 5 | 6 | module Malt::Format 7 | 8 | # RagTag 9 | # 10 | # http://github.com/rubyworks/ragtag 11 | # 12 | class RagTag < Abstract 13 | 14 | file_extension 'ragtag', 'rt' 15 | 16 | # 17 | def html(*data, &content) 18 | render_into(:html, *data, &content) 19 | #render_engine.render(:text=>text, :data=>data, &yld) 20 | end 21 | 22 | # 23 | def to_html(*data, &yld) 24 | text = html(*data, &yld) 25 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 26 | HTML.new(opts) 27 | end 28 | 29 | # 30 | def xml(*data, &yld) 31 | render_into(:xml, *data, &content) 32 | end 33 | 34 | # 35 | def to_xml(*data, &yld) 36 | text = xml(*data, &yld) 37 | opts = options.merge(:text=>text, :file=>refile(:xml), :type=>:xml) 38 | XML.new(opts) 39 | end 40 | 41 | #private 42 | 43 | # 44 | #def render_engine 45 | # @render_engine ||= Malt::Engine::RagTag.new(options) 46 | #end 47 | 48 | end 49 | 50 | end 51 | 52 | -------------------------------------------------------------------------------- /work/defunct/erector.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/erector' 4 | 5 | module Malt::Format 6 | 7 | # Erecotr looks like a Markup format, but it is a template format 8 | # Much like pure Ruby too. 9 | class Erector < Abstract 10 | 11 | register 'erector' 12 | 13 | # 14 | def erector(*) 15 | text 16 | end 17 | 18 | # 19 | def to_erector(*) 20 | self 21 | end 22 | 23 | # 24 | def html(*data, &yld) 25 | render_engine.render(:format=>:html, :text=>text, :file=>file, :data=>data, &yld) 26 | end 27 | 28 | # 29 | def to_html(*data, &yld) 30 | text = html(*data, &yld) 31 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 32 | HTML.new(opts) 33 | end 34 | 35 | # 36 | #def to_ruby(db, &yld) 37 | # @ruby ||= ( 38 | # source = engine.compile(text, file) 39 | # Ruby.new(:text=>source, :file=>refile(:rb)) 40 | # ) 41 | #end 42 | 43 | private 44 | 45 | # 46 | def render_engine 47 | @render_engine ||= Malt::Engine::Erector.new(options) 48 | end 49 | 50 | end 51 | 52 | end 53 | 54 | -------------------------------------------------------------------------------- /work/defunct/markaby.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/markaby' 4 | 5 | module Malt::Format 6 | 7 | # Erecotr looks like a Markup format, but it is a template format 8 | # Much like pure Ruby too. 9 | class Markaby < Abstract 10 | 11 | register 'markaby', 'mab' 12 | 13 | # 14 | def markaby(*) 15 | text 16 | end 17 | 18 | # 19 | def to_markaby(*) 20 | self 21 | end 22 | 23 | # 24 | def html(*data, &yld) 25 | render_engine.render(:format=>:html, :text=>text, :file=>file, :data=>data, &yld) 26 | end 27 | 28 | # 29 | def to_html(*data, &yld) 30 | text = html(*data, &yld) 31 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 32 | HTML.new(opts) 33 | end 34 | 35 | # 36 | #def to_ruby(db, &yld) 37 | # @ruby ||= ( 38 | # source = engine.compile(text, file) 39 | # Ruby.new(:text=>source, :file=>refile(:rb)) 40 | # ) 41 | #end 42 | 43 | private 44 | 45 | # 46 | def render_engine 47 | @render_engine ||= Malt::Engine::Markaby.new(options) 48 | end 49 | 50 | end 51 | 52 | end 53 | 54 | -------------------------------------------------------------------------------- /lib/malt/engines/liquid.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Liquid templates. 6 | # 7 | # @see http://liquid.rubyforge.org/ 8 | # 9 | class Liquid < Abstract 10 | 11 | default :liquid 12 | 13 | # 14 | def render(params={}, &content) #file, db, &content) 15 | text, scope, locals = parameters(params, :text, :scope, :locals) 16 | 17 | data = make_hash(scope, locals, &content) 18 | 19 | # convert symbol keys to strings w/o rewriting the hash 20 | symbol_keys = data.keys.select{ |k| Symbol === k } 21 | symbol_keys.each do |k| 22 | data[k.to_s] = data[k] 23 | data.delete(k) 24 | end 25 | 26 | engine = prepare_engine(params) 27 | 28 | engine.render(data) 29 | end 30 | 31 | # 32 | def create_engine(params={}) 33 | text = parameters(params, :text) 34 | cached(text) do 35 | ::Liquid::Template.parse(text) 36 | end 37 | end 38 | 39 | private 40 | 41 | # Load Liquid library if not already loaded. 42 | def require_engine 43 | return if defined? ::Liquid::Template 44 | require_library 'liquid' 45 | end 46 | 47 | end 48 | 49 | end 50 | 51 | -------------------------------------------------------------------------------- /lib/malt/engines/mustache.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Mustache engine. 6 | # 7 | # @see http://github.com/defunkt/mustache 8 | # 9 | class Mustache < Abstract 10 | 11 | register :mustache 12 | 13 | # 14 | def render(params={}, &content) #file, db, &content) 15 | text, scope, locals = parameters(params, :text, :scope, :locals) 16 | 17 | locals = make_hash(scope, locals, &content) 18 | 19 | # convert symbol keys to strings w/o rewriting the hash 20 | symbol_keys = locals.keys.select{ |k| Symbol === k } 21 | symbol_keys.each do |k| 22 | locals[k.to_s] = locals[k] 23 | locals.delete(k) 24 | end 25 | 26 | #engine = intermediate(params) 27 | #engine.render(data) 28 | 29 | ::Mustache.render(text, locals) 30 | end 31 | 32 | # 33 | #def intermediate(params) 34 | # text = parameters(params, :text) 35 | # ??? 36 | #end 37 | 38 | private 39 | 40 | # Load rdoc makup library if not already loaded. 41 | def require_engine 42 | return if defined? ::Mustache 43 | require_library 'mustache' 44 | end 45 | 46 | end 47 | 48 | end 49 | 50 | 51 | -------------------------------------------------------------------------------- /demo/applique/malt.rb: -------------------------------------------------------------------------------- 1 | require 'malt' 2 | 3 | require 'ae' 4 | require 'ae/pry' 5 | 6 | def sample(file) 7 | s = File.join(File.dirname(__FILE__), '..', '..', 'demo', 'samples', file) 8 | File.expand_path(s) 9 | end 10 | 11 | #unless File.directory?('samples') 12 | # dir = File.dirname(__FILE__)+'/../samples' 13 | # FileUtils.cp_r(dir,'.') 14 | #end 15 | 16 | When "say we have a((n?)) (((\\w+))) document called '(((\\S+)))' containing" do |type, fname, text| 17 | @params ||= {} 18 | @params[:file] = fname 19 | 20 | file = File.join(fname) 21 | File.open(file, 'w'){ |f| f << text } 22 | end 23 | 24 | When "verify that (((@\w+))) is" do |iv, text| 25 | out = instance_variable_get(iv) 26 | out.strip.assert == text.strip 27 | end 28 | 29 | When 'verify that the result is' do |text| 30 | @_.strip.assert == text.strip 31 | end 32 | 33 | When 'the result (((will|should))) be' do |_, text| 34 | @_.to_s.strip.assert == text.strip 35 | end 36 | 37 | When "render the `(((\S+)))` document as `(((\w+)))` via `Malt.render`." do |file, into, text| 38 | @_ = Malt.render(:to=>into, file=>file) 39 | end 40 | 41 | When 'the following (((@\w+)))' do |name, text| 42 | instance_variable_set(name, text) 43 | end 44 | 45 | -------------------------------------------------------------------------------- /lib/malt/formats/sass.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/css' 3 | require 'malt/engines/sass' 4 | 5 | module Malt::Format 6 | 7 | # Sass Format 8 | # 9 | # 10 | class Sass < Abstract 11 | 12 | file_extension 'sass' 13 | 14 | # 15 | def sass(*) 16 | text 17 | end 18 | 19 | # 20 | def to_sass(*) 21 | self 22 | end 23 | 24 | # 25 | def css(*data, &content) 26 | render_into(:css, *data, &content) 27 | #render_engine.render(:format=>:css, :text=>text, :file=>file, :data=>data, :type=>type, &yld) 28 | end 29 | 30 | # 31 | def to_css(*data, &content) 32 | result = css(*data, &content) 33 | CSS.new(:text=>result, :file=>refile(:css), :type=>:css) 34 | end 35 | 36 | # 37 | #def compile(db, &yld) 38 | # result = render_engine.render(text, db, &yld) 39 | # opts = options.merge(:text=>result, file=>refile(:css)) 40 | # CSS.new(opts) 41 | #end 42 | 43 | private 44 | 45 | ## 46 | #def render_engine 47 | # @render_engine ||= Malt::Engine::Sass.new(options) 48 | #end 49 | 50 | # Sass default output type is CSS. 51 | def default 52 | :css 53 | end 54 | 55 | end 56 | 57 | end 58 | 59 | -------------------------------------------------------------------------------- /demo/02markup/02markdown/bluecloth/bluecloth.rdoc: -------------------------------------------------------------------------------- 1 | == BlueCloth 2 | 3 | Malt can render Markdown via BlueCltoh. 4 | 5 | Lets say we have a Markdown document called 'test.md' containing: 6 | 7 | # Example 8 | 9 | This is an example of Markdown rendering. 10 | 11 | Markdown documents are recognized by the +.markdown+ or +.md+ file extensions. 12 | These engine used by setting the :engine option. 13 | 14 | html = Malt.render(:file=>'test.md', :engine=>:bluecloth) 15 | 16 | html.assert.include?('

Example

') 17 | 18 | We can access the file via the +Malt.file+ method. Markdown documents are 19 | recognized by the +.markdown+ or +.md+ file extensions. 20 | 21 | mark = Malt.file('test.md', :engine=>:bluecloth) 22 | 23 | We can the convert the document to a Malt Html object via the #to_html method. 24 | 25 | html = mark.to_html 26 | 27 | Notice that the output is an instance of Malt::Format::HTML. 28 | 29 | html.class.assert == Malt::Format::HTML 30 | 31 | And that by calling #to_s we can get the rendered HTML document. 32 | 33 | html.to_s.assert.include?('

Example

') 34 | 35 | Or we can convert the document directly to HTML via the #html method. 36 | 37 | out = mark.html 38 | 39 | out.assert.include?('

Example

') 40 | 41 | -------------------------------------------------------------------------------- /demo/02markup/02markdown/rdiscount/rdiscount.rdoc: -------------------------------------------------------------------------------- 1 | == RDiscount 2 | 3 | Malt can render Markdown via RDiscount. 4 | 5 | Lets say we have a Markdown document called 'test.md' containing: 6 | 7 | # Example 8 | 9 | This is an example of Markdown rendering. 10 | 11 | Markdown documents are recognized by the +.markdown+ or +.md+ file extensions. 12 | These engine used by setting the :engine option. 13 | 14 | html = Malt.render(:file=>'test.md', :engine=>:rdiscount) 15 | 16 | html.assert.include?('

Example

') 17 | 18 | We can access the file via the +Malt.file+ method. Markdown documents are 19 | recognized by the +.markdown+ or +.md+ file extensions. 20 | 21 | mark = Malt.file('test.md', :engine=>:rdiscount) 22 | 23 | We can the convert the document to a Malt Html object via the #to_html method. 24 | 25 | html = mark.to_html 26 | 27 | Notice that the output is an instance of Malt::Format::HTML. 28 | 29 | html.class.assert == Malt::Format::HTML 30 | 31 | And that by calling #to_s we can get the rendered HTML document. 32 | 33 | html.to_s.assert.include?('

Example

') 34 | 35 | Or we can convert the document directly to HTML via the #html method. 36 | 37 | out = mark.html 38 | 39 | out.assert.include?('

Example

') 40 | 41 | -------------------------------------------------------------------------------- /demo/03template/01erb/format_erb.rdoc: -------------------------------------------------------------------------------- 1 | == ERB 2 | 3 | Malt supports ERB via the ERB engine. 4 | 5 | Lets say we have a ERB document called 'test.erb' containing: 6 | 7 |

Example <%= title %>

8 | 9 |

This is an example of ERB template.

10 | 11 | We can render erb documents via the +render+ method, as we can any format. 12 | However, becuase ERB if a template format and not just a markup syntax, 13 | we need to also provide the +render+ method with data for interpolation 14 | into the ERB document. 15 | 16 | data = { :title=>"Document" } 17 | 18 | html = Malt.render(:file=>'test.erb', :data=>data) 19 | 20 | And as we can see the document rendered as expected. 21 | 22 | html.assert.include?('

Example Document

') 23 | 24 | ERB doesn't actually care what format the document is rendered as. The 25 | template could have been any text file what so ever, so using the `:format` 26 | option would have no effect here. 27 | 28 | === Content Block 29 | 30 | Lets say we have an ERB document called 'test.erb' containing: 31 | 32 | Hello <%= content %>! 33 | 34 | Then 35 | 36 | data = { :title=>"Document" } 37 | 38 | text = Malt.render(:file=>'test.erb',:engine=>:erb){ 'world' } 39 | 40 | Then 41 | 42 | text.strip #=> "Hello world!" 43 | 44 | -------------------------------------------------------------------------------- /work/consider/slim/lib/malt/formats/slim.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/slim' 4 | 5 | module Malt::Format 6 | 7 | # Slim looks like a Markup format, but it turns out to be 8 | # a template format too. 9 | class Slim < Abstract 10 | 11 | register 'slim' 12 | 13 | # 14 | def slim(*) 15 | text 16 | end 17 | 18 | # 19 | def to_slim(*) 20 | self 21 | end 22 | 23 | # 24 | def html(*data, &yld) 25 | render_engine.render( 26 | :format => :html, 27 | :text => text, 28 | :file => file, 29 | :data => data, 30 | &yld 31 | ) 32 | end 33 | 34 | # 35 | def to_html(*data, &yld) 36 | text = html(*data, &yld) 37 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 38 | HTML.new(opts) 39 | end 40 | 41 | # 42 | #def to_ruby(db, &yld) 43 | # @ruby ||= ( 44 | # source = engine.compile(text, file) 45 | # Ruby.new(:text=>source, :file=>refile(:rb)) 46 | # ) 47 | #end 48 | 49 | private 50 | 51 | # 52 | def render_engine 53 | @render_engine ||= Malt::Engine::Smil.new(options) 54 | end 55 | 56 | end 57 | 58 | end 59 | -------------------------------------------------------------------------------- /demo/01general/03_formats.rdoc: -------------------------------------------------------------------------------- 1 | = Formats 2 | 3 | We have created a set of sample documents in the samples directory. 4 | We will take each format in turn. 5 | 6 | formats = %w{erb liquid} 7 | 8 | Included with the format samples are files containing the expected results 9 | of each rendering. 10 | 11 | expected_output = {} 12 | 13 | formats.each do |format| 14 | expected_output[format] = File.read(sample("output-#{format}.txt")) 15 | end 16 | 17 | The data to inject into the formats that interpolate, is also stored in the 18 | samples folder. 19 | 20 | data = YAML.load(File.new(sample('data.yml'))) 21 | 22 | Now we can render each of thes formats, and verify we get the expected result. 23 | 24 | formats.each do |format| 25 | output = Malt.render(:file=>sample("sample.#{format}"), :format=>format, :data=>data) 26 | output.assert == expected_output[format] 27 | end 28 | 29 | Notice that formats the do not use interpolation data simply ignore it even 30 | if it is given. 31 | 32 | We can also handle the files in a more object-oriented manner. 33 | 34 | formats.each do |format| 35 | object = Malt.file(sample("sample.#{format}"), :format=>format) 36 | output = object.render(data) 37 | output.assert == expected_output[format] 38 | end 39 | 40 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | (BSD-2-Clause) 2 | 3 | Redistribution and use in source and binary forms, with or without 4 | modification, are permitted provided that the following conditions are met: 5 | 6 | 1. Redistributions of source code must retain the above copyright notice, 7 | this list of conditions and the following disclaimer. 8 | 9 | 2. Redistributions in binary form must reproduce the above copyright 10 | notice, this list of conditions and the following disclaimer in the 11 | documentation and/or other materials provided with the distribution. 12 | 13 | THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, 14 | INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 15 | AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE 16 | COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, 17 | INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 18 | NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 19 | DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 20 | OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, 22 | EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 | 24 | -------------------------------------------------------------------------------- /lib/malt/formats/text.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/formats/pdf' 4 | 5 | module Malt::Format 6 | 7 | # Plain text format. Plain text documents are unique in that they can 8 | # be transformed into any other type of document. For example, applying 9 | # #to_html in text doesn't actually transform the source text in any way. 10 | # Rather it simply "informs" Malt to treat the text as HTML. 11 | # 12 | class Text < Abstract 13 | 14 | file_extension 'txt' 15 | 16 | # 17 | def txt(*) 18 | text 19 | end 20 | 21 | # 22 | def to_txt(*) 23 | self 24 | end 25 | 26 | # 27 | def method_missing(sym, *args, &block) 28 | if md = /^to_/.match(sym.to_s) 29 | type = md.post_match.to_sym 30 | opts = options.merge(:type=>type, :file=>refile(type)) 31 | return Malt.text(text, opts) 32 | end 33 | super(sym, *args, &block) 34 | end 35 | 36 | # Returns an HTML object. 37 | #def to_html 38 | # HTML.new(:text=>text,:file=>refile(:html)) 39 | #end 40 | 41 | # Returns a PDF object. 42 | #def to_pdf 43 | # PDF.new(:text=>text,:file=>refile(:pdf)) 44 | #end 45 | 46 | private 47 | 48 | def render_engine 49 | end 50 | 51 | end 52 | 53 | end 54 | 55 | -------------------------------------------------------------------------------- /demo/01general/05_machine/01_limited_formats.rdoc: -------------------------------------------------------------------------------- 1 | == Limited Formats 2 | 3 | The Machine class makes it possible to control which formats 4 | are available for rendering. 5 | 6 | For example, let's make a Machine that only support RDoc format 7 | and no others. 8 | 9 | malt = Malt::Machine.new(:types=>[:rdoc]) 10 | 11 | Now we use the `malt` machine object to handle rendering. First let's 12 | make sure that the machine is in fact setup to limit formats to just RDoc. 13 | 14 | malt.formats.keys.assert = [:rdoc] 15 | 16 | malt.assert.format?('.rdoc') 17 | malt.refute.format?('.markdown') 18 | 19 | This being the case we should be able to render an RDoc file without issue. 20 | So, lets say we have a Ruby document called 'sample.rdoc' containing: 21 | 22 | = Sample 23 | 24 | This is an sample. 25 | 26 | Then it can be rendered as follows. 27 | 28 | malt.render(:file=>'sample.rdoc') 29 | 30 | Where as another format type, though usually supported, but excluded in this 31 | case, will fail. Lets say we have a Ruby document called 'sample.markdown' 32 | containing: 33 | 34 | # Sample 35 | 36 | This is an sample. 37 | 38 | Then rendering to will bulk with a `Malt::NoEngineError`. 39 | 40 | expect Malt::NoEngineError do 41 | malt.render(:file=>'sample.markdown') 42 | end 43 | 44 | -------------------------------------------------------------------------------- /lib/malt/engines/creole.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Creole is a MediaWiki format for Ruby. 6 | # 7 | # @see http://github.com/larsch/creole 8 | 9 | class Creole < Abstract 10 | 11 | default :wiki, :creole 12 | 13 | # Convert WikiMedia format to HTML. 14 | # 15 | def render(params={}, &content) 16 | into = parameters(params, :to) 17 | 18 | case into 19 | when :html, nil 20 | prepare_engine(params, &content).to_html 21 | else 22 | super(params) 23 | end 24 | end 25 | 26 | # 27 | #def prepare_engine(params={}, &content) 28 | # create_engine(params) 29 | #end 30 | 31 | # 32 | def create_engine(params={}) 33 | text = parameters(params, :text) 34 | opts = engine_options(params) 35 | 36 | cached(opts, text) do 37 | ::Creole::Parser.new(text, opts) 38 | end 39 | end 40 | 41 | private 42 | 43 | # Load `creole` library if not already loaded. 44 | def require_engine 45 | return if defined? ::Creole 46 | require_library 'creole' 47 | end 48 | 49 | # 50 | ENGINE_OPTION_NAMES = [:allowed_schemes, :extensions, :no_escape] 51 | 52 | # 53 | def engine_option_names 54 | ENGINE_OPTION_NAMES 55 | end 56 | 57 | end 58 | 59 | end 60 | 61 | -------------------------------------------------------------------------------- /demo/06source/21_coffee.rdoc: -------------------------------------------------------------------------------- 1 | == Coffee Script 2 | 3 | Lets say we have a Coffee document called 'test.coffee' containing: 4 | 5 | square = (x) -> x * x 6 | 7 | We can run this Coffee script thru Malt's +render+ function. 8 | 9 | jscript = Malt.render(:file=>'test.coffee') 10 | 11 | jscript.assert.include?("square = function(x) {\n return x * x;\n };") 12 | 13 | We can get a hold of a Coffee script via the Malt.file function. 14 | 15 | coffee = Malt.file('test.coffee') 16 | 17 | coffee.class.assert == Malt::Format::Coffee 18 | 19 | Coffee can only convert to Javascript. 20 | 21 | jscript = coffee.to_javascript 22 | 23 | First we will notice that the output is an instance of Malt::Format::Javascript. 24 | 25 | jscript.class.assert == Malt::Format::Javascript 26 | 27 | And that by calling `#to_s` we can get the rendered javascript document. 28 | 29 | jscript.to_s.assert.include?("square = function(x) {\n return x * x;\n };") 30 | 31 | Or we can convert the Coffee script directly to Javascript via the `#javascript` 32 | method. 33 | 34 | out = coffee.javascript 35 | 36 | out.assert.include?("square = function(x) {\n return x * x;\n };") 37 | 38 | Malt also offers shorter aliases as `#to_js` and `#js`. 39 | 40 | out = coffee.js 41 | 42 | out.assert.include?("square = function(x) {\n return x * x;\n };") 43 | 44 | -------------------------------------------------------------------------------- /lib/malt/engines/ragtag.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # RagTag XML/HTML templates. 6 | # 7 | # @see http://github.com/rubyworks/ragtag 8 | # 9 | class RagTag < Abstract 10 | 11 | default :ragtag, :rt 12 | 13 | # 14 | def render(params={}, &content) 15 | into = parameters(params, :to) || :html 16 | 17 | case into 18 | when :html 19 | prepare_engine(params,&content).to_html 20 | when :xhtml 21 | prepare_engine(params,&content).to_xhtml 22 | when :xml 23 | prepare_engine(params,&content).to_xml 24 | else 25 | super(params, &content) 26 | end 27 | end 28 | 29 | # 30 | def prepare_engine(params={}, &content) 31 | text, file, scope, locals = parameters(params, :text, :file, :scope, :locals) 32 | 33 | binding = make_binding(scope, locals, &content) 34 | 35 | create_engine(params).compile(binding) 36 | end 37 | 38 | # 39 | def create_engine(params={}) 40 | text = parameters(params, :text) 41 | 42 | cached(text) do 43 | ::RagTag.new(text) 44 | end 45 | end 46 | 47 | private 48 | 49 | # Load Haml library if not already loaded. 50 | def require_engine 51 | return if defined? ::RagTag 52 | require_library 'ragtag' 53 | end 54 | 55 | end 56 | 57 | end 58 | -------------------------------------------------------------------------------- /demo/02markup/02markdown/kramdown/kramdown.rdoc: -------------------------------------------------------------------------------- 1 | == Kramdown 2 | 3 | Malt can render Markdown via Kramdown. 4 | 5 | Lets say we have a Markdown document called 'test.md' containing: 6 | 7 | # Example 8 | 9 | This is an example of Markdown rendering. 10 | 11 | Markdown documents are recognized by the +.markdown+ or +.md+ file extensions. 12 | These engine used by setting the :engine option. 13 | 14 | html = Malt.render(:file=>'test.md', :engine=>:kramdown) 15 | 16 | Notice that Kramdown provides some bonus features compared to the other 17 | rendering engines. 18 | 19 | html.assert.include?('

Example

') 20 | 21 | We can access the file via the +Malt.file+ method. Markdown documents are 22 | recognized by the +.markdown+ or +.md+ file extensions. 23 | 24 | mark = Malt.file('test.md', :engine=>:kramdown) 25 | 26 | We can the convert the document to a Malt Html object via the #to_html method. 27 | 28 | html = mark.to_html 29 | 30 | Notice that the output is an instance of Malt::Format::HTML. 31 | 32 | html.class.assert == Malt::Format::HTML 33 | 34 | And that by calling #to_s we can get the rendered HTML document. 35 | 36 | html.to_s.assert.include?('

Example

') 37 | 38 | Or we can convert the document directly to HTML via the #html method. 39 | 40 | out = mark.html 41 | 42 | out.assert.include?('

Example

') 43 | 44 | -------------------------------------------------------------------------------- /demo/03template/07radius/09_radius.rdoc: -------------------------------------------------------------------------------- 1 | == Radius 2 | 3 | Lets say we have a Radius document called 'test.radius' containing: 4 | 5 |

Example

6 |

This is an example of a Radius template.

7 | 8 | We can render Radius documents via the +render+ method, as we can any format. 9 | 10 | data = {:title=>"Document"} 11 | 12 | html = Malt.render(:file=>'test.radius', :data=>data, :tag_prefix=>'r') 13 | 14 | html.assert.include?('

Example Document

') 15 | 16 | We can get a hold of the Radius document via the Malt.file function. 17 | 18 | radi = Malt.file('test.radius', :tag_prefix=>'r') 19 | 20 | radi.class.assert == Malt::Format::Radius 21 | 22 | Notice here we have passed an option to the file constructor. This option 23 | is passed on the underlying Radius.new method. Now we can convert Radius 24 | documents to HTML documents via #to_html. 25 | 26 | data = {:title => "Document"} 27 | 28 | html = radi.to_html(data) 29 | 30 | First we will notice that the output is an instance of Malt::Format::HTML. 31 | 32 | html.class.assert == Malt::Format::HTML 33 | 34 | And that by calling #to_s we can get the rendered HTML document. 35 | 36 | html.to_s.assert.include?('

Example Document

') 37 | 38 | Or we can convert the Radius document directly to HTML via the #html method. 39 | 40 | out = radi.html(data) 41 | 42 | out.assert.include?('

Example Document

') 43 | 44 | -------------------------------------------------------------------------------- /lib/malt/formats/rbhtml.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/erb' 4 | require 'malt/engines/erubis' 5 | 6 | module Malt::Format 7 | 8 | # RBHTML is a variant of Tenjin, but limited to HTML conversion. 9 | class RBHTML < Abstract 10 | 11 | file_extension 'rbhtml' 12 | 13 | # 14 | def html(*data, &content) 15 | render_into(:html, *data, &content) 16 | end 17 | 18 | # 19 | def to_html(*data, &yld) 20 | text = html(*data, &yld) 21 | opts = options.merge( 22 | :text => text, 23 | :file => refile(:html), 24 | :type => :html, 25 | :engine => nil 26 | ) 27 | HTML.new(opts) 28 | end 29 | 30 | # TODO: to_rb 31 | =begin 32 | # RHTML templates can be "pre-compiled" into Ruby templates. 33 | def rb(*) 34 | render_engine.compile(:text=>text, :file=>file) 35 | end 36 | 37 | # RHTML templates can be "pre-compiled" into Ruby templates. 38 | def to_rb(*) 39 | text = rb 40 | Ruby.new(:text=>text, :file=>refile(:rb), :type=>:rb) 41 | end 42 | 43 | # 44 | alias_method(:to_ruby, :to_rb) 45 | 46 | # 47 | alias_method(:precompile, :to_rb) 48 | =end 49 | 50 | #private 51 | # 52 | # # 53 | # def render_engine 54 | # @render_engine ||= Malt::Engine::Tenjin.new(options) 55 | # end 56 | 57 | end 58 | 59 | end 60 | 61 | -------------------------------------------------------------------------------- /demo/05css/01sass/13_sass.rdoc: -------------------------------------------------------------------------------- 1 | == Sass 2 | 3 | Lets say we have a Sass document called 'test.sass' containing: 4 | 5 | $blue: #3bbfce 6 | $margin: 16px 7 | 8 | .content-navigation 9 | border-color: $blue 10 | color: darken($blue, 9%) 11 | 12 | .border 13 | padding: $margin / 2 14 | margin: $margin / 2 15 | border-color: $blue 16 | 17 | We can render the Sass document via #render. 18 | 19 | @css = Malt.render(:file=>'test.sass') 20 | 21 | And we can verify that @css is the expected CSS: 22 | 23 | .content-navigation { 24 | border-color: #3bbfce; 25 | color: #2ca2af; } 26 | 27 | .border { 28 | padding: 8px; 29 | margin: 8px; 30 | border-color: #3bbfce; } 31 | 32 | We can also get a hold of the Sass document via the Malt.file function. 33 | 34 | sass = Malt.file('test.sass') 35 | 36 | sass.class.assert == Malt::Format::Sass 37 | 38 | We can convert the Sass document to a CSS document via the #to_css method. 39 | 40 | css = sass.to_css 41 | 42 | We can see that the output is an instance of Malt::Format::HTML. 43 | 44 | css.class.assert == Malt::Format::CSS 45 | 46 | And that by calling #to_s we can get the rendered CSS document. 47 | 48 | css.to_s.assert.include?('border-color: #3bbfce;') 49 | 50 | Or we can convert the Sass document directly to CSS via the #css method. 51 | 52 | out = sass.css 53 | 54 | out.assert.include?('border-color: #3bbfce;') 55 | 56 | -------------------------------------------------------------------------------- /demo/02markup/03textile/redcloth/format_redcloth.rdoc: -------------------------------------------------------------------------------- 1 | == Textile 2 | 3 | Malt supports Textile via RedCloth. 4 | 5 | Lets say we have a Textile document called 'test.tt' containing: 6 | 7 | h1. Example 8 | 9 | This is an example of Textile rendering. 10 | 11 | We can redner the textile document via the universal render function. 12 | Textile documents are recognized by the +.textile+ or +.tt+ extension. 13 | 14 | html = Malt.render(:file=>'test.tt') 15 | 16 | html.assert.include?('

Example

') 17 | 18 | Malt supports Textile via either the RedCloth backend. 19 | 20 | Lets say we have an Textile document called 'test.tt' containing: 21 | 22 | h1. Example 23 | 24 | This is an example of Textile rendering. 25 | 26 | We can access the file via the +Malt.file+ method. Textile documents are 27 | recognized by the +.textile+ or +.tt+ extension. 28 | 29 | tile = Malt.file('test.tt') 30 | 31 | We can the convert the document to a Malt Html object via the #to_html method. 32 | 33 | html = tile.to_html 34 | 35 | Notice that the output is an instance of Malt::Format::HTML. 36 | 37 | html.class.assert == Malt::Format::HTML 38 | 39 | And that by calling #to_s we can get the rendered HTML document. 40 | 41 | html.to_s.assert.include?('

Example

') 42 | 43 | Or we can convert the document directly to HTML via the #html method. 44 | 45 | out = tile.html 46 | 47 | out.assert.include?('

Example

') 48 | 49 | -------------------------------------------------------------------------------- /demo/04sgml/01haml/format_haml.rdoc: -------------------------------------------------------------------------------- 1 | == Haml 2 | 3 | Lets say we have a Haml document called 'test.haml' containing: 4 | 5 | %h1 Example #{title} 6 | %p This is an example of a Haml template. 7 | 8 | We can render Haml documents via the +render+ method, as we can any format. 9 | While it might not appear as such on first glance, Haml is actually a template 10 | format and not just a markup language, so we need to also provide the +render+ 11 | function with data for interpolation into the Haml document. 12 | 13 | data = { :title=>"Document" } 14 | 15 | html = Malt.render(:file=>'test.haml', :data=>data) 16 | 17 | html.assert.include?('

Example Document

') 18 | 19 | We can get a hold of the Haml document via the Malt.file function. 20 | 21 | haml = Malt.file('test.haml') 22 | 23 | haml.class.assert == Malt::Format::Haml 24 | 25 | We can convert Haml documents to html very easily. 26 | 27 | data = {:title => "Document"} 28 | 29 | html = haml.to_html(data) 30 | 31 | First we will notice that the output is an instance of Malt::Format::HTML. 32 | 33 | html.class.assert == Malt::Format::HTML 34 | 35 | And that by calling #to_s we can get the rendered HTML document. 36 | 37 | html.to_s.assert.include?('

Example Document

') 38 | 39 | Or we can convert the Haml document directly to HTML via the #html method. 40 | 41 | out = haml.html(data) 42 | 43 | out.assert.include?('

Example Document

') 44 | 45 | -------------------------------------------------------------------------------- /lib/malt/engines/rdiscount.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | require 'malt/formats/rdoc' 3 | require 'malt/formats/html' 4 | 5 | module Malt::Engine 6 | 7 | # Discount Markdown implementation. 8 | # 9 | # @see http://github.com/rtomayko/rdiscount 10 | # 11 | # The +:smart+ and +:filter_html+ options can be set true 12 | # to enable those flags on the underlying RDiscount object. 13 | class RDiscount < Abstract 14 | 15 | default :markdown, :md 16 | 17 | # Convert Markdown text to HTML text. 18 | def render(params={}) 19 | into = parameters(params, :to) 20 | 21 | case into 22 | when :html, nil 23 | prepare_engine(params).to_html 24 | else 25 | super(params) 26 | end 27 | end 28 | 29 | # Convert Markdown text to create_engine engine object. 30 | def create_engine(params={}) 31 | text = parameters(params, :text) 32 | 33 | flags = engine_options(params) 34 | 35 | cached(text, flags) do 36 | ::RDiscount.new(text, *flags) 37 | end 38 | end 39 | 40 | private 41 | 42 | # Load rdoc makup library if not already loaded. 43 | def require_engine 44 | return if defined? ::RDiscount 45 | require_library 'rdiscount' 46 | end 47 | 48 | # 49 | def engine_options(params={}) 50 | [:smart, :filter_html].select{ |flag| params[flag] || settings[flag] } 51 | end 52 | 53 | end 54 | 55 | end 56 | 57 | -------------------------------------------------------------------------------- /work/consider/slim/qed/03_formats/10_slim.rdoc: -------------------------------------------------------------------------------- 1 | == Slim 2 | 3 | Lets say we have a Slim document called 'test.slim' containing: 4 | 5 | h1 Example = title 6 | p This is an example of a Slim template. 7 | 8 | We can render Slim documents via the +render+ method, as we can any format. 9 | While it might not appear as such on first glance, Slim is actually a template 10 | format and not just a markup language, so we need to also provide the +render+ 11 | function with data for interpolation into the Haml document. 12 | 13 | data = { :title=>"Document" } 14 | 15 | html = Malt.render(:file=>'test.slim', :data=>data) 16 | 17 | html.assert.include?('

Example Document

') 18 | 19 | We can get a hold of the Slim document via the Malt.file function. 20 | 21 | slim = Malt.file('test.slim') 22 | 23 | slim.class.assert == Malt::Format::Slim 24 | 25 | We can convert Slim documents to html very easily. 26 | 27 | data = {:title => "Document"} 28 | 29 | html = slim.to_html(data) 30 | 31 | First we will notice that the output is an instance of Malt::Format::HTML. 32 | 33 | html.class.assert == Malt::Format::HTML 34 | 35 | And that by calling #to_s we can get the rendered HTML document. 36 | 37 | html.to_s.assert.include?('

Example Document

') 38 | 39 | Or we can convert the Haml document directly to HTML via the #html method. 40 | 41 | out = slim.html(data) 42 | 43 | out.assert.include?('

Example Document

') 44 | 45 | -------------------------------------------------------------------------------- /demo/03template/consistent.rdoc: -------------------------------------------------------------------------------- 1 | = Feature: Consistant rendering across all template engines 2 | 3 | * As a developer 4 | * In order to render templates 5 | * I want to have my choice of template engines 6 | * And I want all templates to behave consistently 7 | 8 | == Scenario: Template with Binding Data Source 9 | 10 | * Given an equivalent template for each engine 11 | * And a Binding for a data source 12 | * When the equivalent template is rendered 13 | * Then the result is the same for each 14 | 15 | == Scenario: Template with Object Data Source 16 | 17 | * Given an equivalent template for each engine 18 | * And a Object for a data source 19 | * When the equivalent template is rendered 20 | * Then the result is the same for each 21 | 22 | == Scenario: Template with Struct Data Source 23 | 24 | * Given an equivalent template for each engine 25 | * And a Struct for a data source 26 | * When the equivalent template is rendered 27 | * Then the result is the same for each 28 | 29 | == Scenario: Template with Hash Date Source 30 | 31 | * Given an equivalent template for each engine 32 | * And a Hash for a data source 33 | * When the equivalent template is rendered 34 | * Then the result is the same for each 35 | 36 | == Scenario: Template with OpenStruct Locals 37 | 38 | * Given an equivalent template for each engine 39 | * And a OpenStruct for a data source 40 | * When the equivalent template is rendered 41 | * Then the result is the same for each 42 | 43 | -------------------------------------------------------------------------------- /demo/05css/01sass/14_scss.rdoc: -------------------------------------------------------------------------------- 1 | == SCSS 2 | 3 | Lets say we have a SCSS document called 'test.scss' containing: 4 | 5 | $blue: #3bbfce; 6 | $margin: 16px; 7 | 8 | .content-navigation { 9 | border-color: $blue; 10 | color: 11 | darken($blue, 9%); 12 | } 13 | 14 | .border { 15 | padding: $margin / 2; 16 | margin: $margin / 2; 17 | border-color: $blue; 18 | } 19 | 20 | We can render the Sass document via #render. 21 | 22 | @css = Malt.render(:file=>'test.scss') 23 | 24 | And we can verify that @css is the expected CSS: 25 | 26 | .content-navigation { 27 | border-color: #3bbfce; 28 | color: #2ca2af; } 29 | 30 | .border { 31 | padding: 8px; 32 | margin: 8px; 33 | border-color: #3bbfce; } 34 | 35 | We can also get a hold of the SCSS document via the Malt.file function. 36 | 37 | scss = Malt.file('test.scss') 38 | 39 | scss.class.assert == Malt::Format::SCSS 40 | 41 | We can convert the SCSS document to a CSS document via the #to_css method. 42 | 43 | css = scss.to_css 44 | 45 | We can see that the output is an instance of Malt::Format::SCSS. 46 | 47 | css.class.assert == Malt::Format::CSS 48 | 49 | And that by calling #to_s we can get the rendered CSS document. 50 | 51 | css.to_s.assert.include?('border-color: #3bbfce;') 52 | 53 | Or we can convert the SCSS document directly to CSS via the #css method. 54 | 55 | out = scss.css 56 | 57 | out.assert.include?('border-color: #3bbfce;') 58 | 59 | -------------------------------------------------------------------------------- /demo/04sgml/consistent.rdoc: -------------------------------------------------------------------------------- 1 | = Feature: Consistant rendering across all HTML/XML engines 2 | 3 | * As a developer 4 | * In order to render templates 5 | * I want to have my choice of template engines 6 | * And I want all templates to behave consistently 7 | 8 | == Scenario: Template with Binding Data Source 9 | 10 | * Given an equivalent template for each html engine 11 | * And a Binding for a data source 12 | * When the equivalent template is rendered 13 | * Then the result is the same for each 14 | 15 | == Scenario: Template with Object Data Source 16 | 17 | * Given an equivalent template for each html engine 18 | * And a Object for a data source 19 | * When the equivalent template is rendered 20 | * Then the result is the same for each 21 | 22 | == Scenario: Template with Struct Data Source 23 | 24 | * Given an equivalent template for each html engine 25 | * And a Struct for a data source 26 | * When the equivalent template is rendered 27 | * Then the result is the same for each 28 | 29 | == Scenario: Template with Hash Date Source 30 | 31 | * Given an equivalent template for each html engine 32 | * And a Hash for a data source 33 | * When the equivalent template is rendered 34 | * Then the result is the same for each 35 | 36 | == Scenario: Template with OpenStruct Locals 37 | 38 | * Given an equivalent template for each html engine 39 | * And a OpenStruct for a data source 40 | * When the equivalent template is rendered 41 | * Then the result is the same for each 42 | 43 | -------------------------------------------------------------------------------- /demo/06source/16_ruby.rdoc: -------------------------------------------------------------------------------- 1 | == Ruby 2 | 3 | It may not seem obvious at first, but Ruby itself can be used as 4 | a template system. 5 | 6 | Lets say we have a Ruby document called 'test.rb' containing: 7 | 8 | "

Example #{ title }

\n" + 9 | "

This is an example of Ruby rendering.

" 10 | 11 | We can run this Ruby script thru Malt's +render+ function. 12 | 13 | data = {:title => 'Document'} 14 | 15 | html = Malt.render(:file=>'test.rb', :data=>data) 16 | 17 | Whatever was the final result of evaluating the Ruby script, converted to 18 | a string via #to_s, will be the result of the rendering. 19 | 20 | html.assert.include?('

Example Document

') 21 | 22 | We can get a hold of the Ruby template via the Malt.file function. 23 | 24 | ruby = Malt.file('test.rb') 25 | 26 | ruby.class.assert == Malt::Format::Ruby 27 | 28 | Ruby is a Universal Template Format, so it can be converted to any other 29 | format (even if it is not really that format). 30 | 31 | data = {:title => "Document"} 32 | 33 | html = ruby.to_html(data) 34 | 35 | First we will notice that the output is an instance of Malt::Format::HTML. 36 | 37 | html.class.assert == Malt::Format::HTML 38 | 39 | And that by calling #to_s we can get the rendered HTML document. 40 | 41 | html.to_s.assert.include?('

Example Document

') 42 | 43 | Or we can convert the Ruby document directly to HTML via the #html method. 44 | 45 | out = ruby.html(data) 46 | 47 | out.assert.include?('

Example Document

') 48 | 49 | -------------------------------------------------------------------------------- /demo/03template/08ruby/ruby_example.rdoc: -------------------------------------------------------------------------------- 1 | == Ruby 2 | 3 | Lets say we have a Ruby document called 'test.rb' containing: 4 | 5 | "

Example #{title}

\n" + 6 | "

This is an example of a Radius template.

" 7 | 8 | We can render such documents via the +render+ method, as we can any format. 9 | 10 | data = {:title=>"Document"} 11 | 12 | html = Malt.render(:file=>'test.rb', :data=>data) 13 | 14 | html.assert.include?('

Example Document

') 15 | 16 | We can get a hold of the String document via the `Malt.file` function. 17 | 18 | rb = Malt.file('test.rb') 19 | 20 | rb.class.assert == Malt::Format::Ruby 21 | 22 | Now we can convert the String document to an HTML document via #to_html. 23 | 24 | data = {:title => "Document"} 25 | 26 | html = rb.to_html(data) 27 | 28 | First we will notice that the output is an instance of Malt::Format::HTML. 29 | 30 | html.class.assert == Malt::Format::HTML 31 | 32 | And that by calling #to_s we can get the rendered HTML document. 33 | 34 | html.to_s.assert.include?('

Example Document

') 35 | 36 | Or we can convert the String document directly to HTML via the #html method. 37 | 38 | out = rb.html(data) 39 | 40 | out.assert.include?('

Example Document

') 41 | 42 | Ruby templates are *polyglot*, so they can be converted to any format, 43 | and it is simply assumed the result is the format intended. In other words, 44 | it doesn't ensure the result is HTML just b/c it was asked to render the 45 | String document into HTML. 46 | 47 | -------------------------------------------------------------------------------- /demo/03template/09string/string_exmple.rdoc: -------------------------------------------------------------------------------- 1 | == String 2 | 3 | Lets say we have a String document called 'test.str' containing: 4 | 5 |

Example #{title}

6 |

This is an example of a Radius template.

7 | 8 | We can render such documents via the +render+ method, as we can any format. 9 | 10 | data = {:title=>"Document"} 11 | 12 | html = Malt.render(:file=>'test.str', :data=>data) 13 | 14 | html.assert.include?('

Example Document

') 15 | 16 | We can get a hold of the String document via the `Malt.file` function. 17 | 18 | str = Malt.file('test.str') 19 | 20 | str.class.assert == Malt::Format::String 21 | 22 | Now we can convert the String document to an HTML document via #to_html. 23 | 24 | data = {:title => "Document"} 25 | 26 | html = str.to_html(data) 27 | 28 | First we will notice that the output is an instance of Malt::Format::HTML. 29 | 30 | html.class.assert == Malt::Format::HTML 31 | 32 | And that by calling #to_s we can get the rendered HTML document. 33 | 34 | html.to_s.assert.include?('

Example Document

') 35 | 36 | Or we can convert the String document directly to HTML via the #html method. 37 | 38 | out = str.html(data) 39 | 40 | out.assert.include?('

Example Document

') 41 | 42 | Ruby string templates are *polyglot*, so they can be converted to any format, 43 | and it is simply assumed the result is the format intended. In other words, 44 | it doesn't ensure the result is HTML just b/c it was asked to render the 45 | String document into HTML. 46 | 47 | -------------------------------------------------------------------------------- /demo/03template/03tenjin/11_tenjin.rdoc: -------------------------------------------------------------------------------- 1 | == Tenjin 2 | 3 | While Tenjin is generally intended to be used to render HTML documents, it is 4 | a general purpose template format that can be used for any type of document. 5 | For these uses, the Tenjin file extension is '.tenjin'. 6 | 7 | Lets say we have a Tenjin document called 'test.tenjin' containing: 8 | 9 | Hello #{name}! 10 | 11 | We can render the document via #render. 12 | 13 | data = { :name=>'World', :items=>['A','B','C'] } 14 | 15 | @text = Malt.render(:file=>'test.tenjin', :data=>data) 16 | 17 | And we can verify that @text is: 18 | 19 | Hello World! 20 | 21 | We can get a OOP interface tothe Tenjin document via the Malt.file function. 22 | 23 | tenjin = Malt.file('test.tenjin') 24 | 25 | tenjin.class.assert == Malt::Format::Tenjin 26 | 27 | Since Tenjin is aa general pupose template foramt, we can convert Tenjin 28 | documents to any format we wish. For instance we can convert our example 29 | to a Text documents via #to_txt. 30 | 31 | data = { :name=>'World', :items=>['', 'B&B', '"CCC"'] } 32 | 33 | text = tenjin.to_txt(data) 34 | 35 | First we will notice that the output is an instance of `Malt::Format::Text`. 36 | 37 | text.class.assert == Malt::Format::Text 38 | 39 | And that by calling #to_s we can get the rendered Text document. 40 | 41 | text.to_s.assert.include?('Hello World!') 42 | 43 | Or we can convert the Tenjin document directly to text via the #txt method. 44 | 45 | out = tenjin.txt(data) 46 | 47 | out.assert.include?('Hello World!') 48 | -------------------------------------------------------------------------------- /lib/malt/formats/rhtml.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/erb' 4 | require 'malt/engines/erubis' 5 | 6 | module Malt::Format 7 | 8 | # RHTML is a variant of Erb files which are limited to conversion to HTML. 9 | class RHTML < Abstract 10 | 11 | file_extension 'rhtml' 12 | 13 | =begin 14 | # RHTML templates can be "pre-compiled" into Ruby templates. 15 | def rb(*) 16 | render_engine.compile(:text=>text, :file=>file) 17 | end 18 | 19 | # RHTML templates can be "pre-compiled" into Ruby templates. 20 | def to_rb(*) 21 | text = rb 22 | Ruby.new(:text=>text, :file=>refile(:rb), :type=>:rb) 23 | end 24 | 25 | # 26 | alias_method(:to_ruby, :to_rb) 27 | 28 | # 29 | alias_method(:precompile, :to_rb) 30 | =end 31 | 32 | # 33 | def html(*data, &content) 34 | render_into(:html, *data, &content) 35 | #render_engine.render(:text=>text, :file=>file, :data=>data, :to=>:html, &yld) 36 | end 37 | 38 | # 39 | def to_html(*data, &yld) 40 | text = html(data, &yld) 41 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 42 | HTML.new(opts) 43 | end 44 | 45 | #private 46 | 47 | ## 48 | #def render_engine 49 | # @render_engine ||= ( 50 | # case engine 51 | # when :erubis 52 | # Malt::Engine::Erubis.new(options) 53 | # else 54 | # Malt::Engine::Erb.new(options) 55 | # end 56 | # ) 57 | #end 58 | 59 | end 60 | 61 | end 62 | 63 | -------------------------------------------------------------------------------- /lib/malt/engines/sass.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Sass Malt Engine 6 | # 7 | class Sass < Abstract 8 | 9 | default :sass, :scss 10 | 11 | # 12 | def render(params={}, &content) 13 | into = parameters(params, :to) 14 | 15 | case into 16 | when :css, nil 17 | engine = prepare_engine(params) 18 | engine.render 19 | else 20 | super(params, &content) 21 | end 22 | end 23 | 24 | # 25 | def create_engine(params={}) 26 | text, file, type = parameters(params, :text, :file, :type) 27 | 28 | opts = engine_options(params) 29 | 30 | opts[:filename] = file 31 | opts[:syntax] = type 32 | 33 | cached(text, file, type) do 34 | ::Sass::Engine.new(text, opts) 35 | end 36 | end 37 | 38 | private 39 | 40 | # Load Sass library if not already loaded. 41 | def require_engine 42 | return if defined? ::Sass::Engine 43 | require_library 'sass' 44 | end 45 | 46 | # List of Sass/Scss engine options. Note that not all options are supported. 47 | # Also use `:type` instead of `:syntax` and `:file` instead of `:filename`. 48 | # 49 | # @see http://sass-lang.com/docs/yardoc/file.SASS_REFERENCE.html#options 50 | ENGINE_OPTION_NAMES = %w{ 51 | syntax filename line style unix_newlines 52 | line_numbers trace_selectors debug_info quiet 53 | } 54 | 55 | # 56 | def engine_option_names 57 | ENGINE_OPTION_NAMES 58 | end 59 | 60 | end 61 | 62 | end 63 | 64 | -------------------------------------------------------------------------------- /lib/malt/formats/liquid.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract_template' 2 | require 'malt/engines/liquid' 3 | 4 | module Malt::Format 5 | 6 | # Liquid templates 7 | # 8 | # http://liquid.rubyforge.org/ 9 | # 10 | class Liquid < AbstractTemplate 11 | 12 | file_extension 'liquid' 13 | 14 | # 15 | def liquid(*) 16 | text 17 | end 18 | 19 | # 20 | def to_liquid(*) 21 | self 22 | end 23 | 24 | # # 25 | # def to(type, data=nil, &yld) 26 | # type = type.to_sym 27 | # new_class = Malt.registry[type] 28 | # new_text = render(data, &yld) 29 | # new_file = refile(type) 30 | # new_options = options.merge(:text=>new_text, :file=>new_file, :type=>type) 31 | # new_class.new(new_options) 32 | # end 33 | 34 | # # 35 | # def render(*type_and_data, &yld) 36 | # type, data = parse_type_and_data(type_and_data) 37 | # render_engine.render(:text=>text, :file=>file, :data=>data, &yld) 38 | # end 39 | 40 | # # Liquid templates can be any type. 41 | # def method_missing(sym, *args, &yld) 42 | # if Malt.registry.key?(sym) 43 | # return render(sym, *args, &yld) 44 | # elsif md = /^to_/.match(sym.to_s) 45 | # type = md.post_match.to_sym 46 | # if Malt.registry.key?(type) 47 | # return to(type, *args, &yld) 48 | # end 49 | # end 50 | # super(sym, *args, &yld) 51 | # end 52 | 53 | # private 54 | # 55 | # # 56 | # def render_engine 57 | # @render_engine ||= Malt::Engine::Liquid.new(options) 58 | # end 59 | 60 | end 61 | 62 | end 63 | 64 | -------------------------------------------------------------------------------- /demo/03template/03tenjin/12_rbhtml.rdoc: -------------------------------------------------------------------------------- 1 | == RBHTML 2 | 3 | Tenjin is a general purpose template language with support for multiple 4 | languages including Ruby. The variation of Tenjin for Ruby, called rbTenjin, 5 | defines a document format with an extension of `.rbhtml`. 6 | 7 | Lets say we have a Tenjin document called 'test.rbhtml' containing: 8 | 9 | Hello #{name}! 10 |
    11 | 12 |
  • ${item}
  • 13 | 14 |
15 | 16 | We can render the document via #render. 17 | 18 | data = { :name=>'World', :items=>['', 'B&B', '"CCC"'] } 19 | 20 | @html = Malt.render(:file=>'test.rbhtml', :data=>data) 21 | 22 | And we can verify that @html is: 23 | 24 | Hello World! 25 |
    26 |
  • <AAA>
  • 27 |
  • B&B
  • 28 |
  • "CCC"
  • 29 |
30 | 31 | We can get a hold of the RBHTML document via the Malt.file function. 32 | 33 | rbhtml = Malt.file('test.rbhtml') 34 | 35 | rbhtml.class.assert == Malt::Format::RBHTML 36 | 37 | We can convert RBHTML documents to HTML documents via #to_html. 38 | 39 | data = { :name=>'World', :items=>['', 'B&B', '"CCC"'] } 40 | 41 | html = rbhtml.to_html(data) 42 | 43 | First we will notice that the output is an instance of Malt::Format::HTML. 44 | 45 | html.class.assert == Malt::Format::HTML 46 | 47 | And that by calling #to_s we can get the rendered HTML document. 48 | 49 | html.to_s.assert.include?('Hello World!') 50 | 51 | Or we can convert the RBHTML document directly to HTML via the #html method. 52 | 53 | out = rbhtml.html(data) 54 | 55 | out.assert.include?('Hello World!') 56 | -------------------------------------------------------------------------------- /demo/04sgml/02builder/format_builder.rdoc: -------------------------------------------------------------------------------- 1 | == Builder 2 | 3 | Lets say we have a Builder document called 'test.builder' containing: 4 | 5 | html do 6 | h1 "Example #{@title}" 7 | p "This is an example of a Maraby template." 8 | end 9 | 10 | Notice the use of the instance variable. Builder templates must use instance 11 | variables for data rendering in order to avoid ambiguity with the markup 12 | syntax itself. 13 | 14 | We can render Builder documents via the +render+ method, as we can any format. 15 | Since Builder is a template format and not just a markup syntax, so we need 16 | to also provide the +render+ function with data for interpolation into the 17 | Builder document. 18 | 19 | data = { :title=>"Document" } 20 | 21 | html = Malt.render(:file=>'test.builder', :data=>data, :engine=>:builder) 22 | 23 | html.assert.include?('

Example Document

') 24 | 25 | We can get a hold of the Builder document via the Malt.file function. 26 | 27 | builder = Malt.file('test.builder', :engine=>:builder) 28 | 29 | builder.class.assert == Malt::Format::Builder 30 | 31 | We can convert Builder documents to html very easily. 32 | 33 | data = {:title => "Document"} 34 | 35 | html = builder.to_html(data) 36 | 37 | First we will notice that the output is an instance of Malt::Format::HTML. 38 | 39 | html.class.assert == Malt::Format::HTML 40 | 41 | And that by calling #to_s we can get the rendered HTML document. 42 | 43 | html.to_s.assert.include?('

Example Document

') 44 | 45 | Or we can convert the Builder document directly to HTML via the #html method. 46 | 47 | out = builder.html(data) 48 | 49 | out.assert.include?('

Example Document

') 50 | 51 | -------------------------------------------------------------------------------- /lib/malt/formats/abstract_template.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | 3 | module Malt 4 | module Format 5 | 6 | # An AbstractTemplate is a subclass of Abstract. It is used as the base class 7 | # for general purpose template formats which can be used to render any other 8 | # type of format. 9 | class AbstractTemplate < Abstract 10 | 11 | # 12 | def to(type, *data, &yld) 13 | new_class = Malt::Format.registry[type.to_sym] # TODO: Malt.machine.format? 14 | new_text = render_into(type, *data, &yld) 15 | new_file = refile(type) 16 | new_options = options.merge(:text=>new_text, :file=>new_file, :type=>type) 17 | new_class.new(new_options) 18 | end 19 | 20 | # 21 | def render(*type_and_data, &content) 22 | type, data = parse_type_from_data(*type_and_data) 23 | #opts = options.merge(:to=>type, :text=>text, :file=>file, :data=>data) 24 | render_into(type, *data, &content) 25 | 26 | #render_engine.render(opts, &yld) 27 | #opts = options.merge(:format=>type, :text=>text, :file=>file, :data=>data, :engine=>engine) 28 | #Malt.render(opts, &yld) 29 | end 30 | 31 | # ERB templates can be any type. 32 | def method_missing(sym, *args, &yld) 33 | if Malt::Format.registry.key?(sym) # TODO: Malt.machine.format? 34 | return render_into(sym, *args, &yld) #.to_s 35 | elsif md = /^to_/.match(sym.to_s) 36 | type = md.post_match.to_sym 37 | if Malt::Format.registry.key?(type) # TODO: Malt.machine.format? 38 | return to(type, *args, &yld) 39 | end 40 | end 41 | super(sym, *args, &yld) 42 | end 43 | 44 | end 45 | 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /lib/malt/formats/mediawiki.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | #require 'malt/formats/latex' 4 | require 'malt/engines/creole' 5 | require 'malt/engines/wikicloth' 6 | 7 | module Malt::Format 8 | 9 | # 10 | class MediaWiki < Abstract 11 | 12 | file_extension 'mediawiki', 'mw' 13 | 14 | # 15 | def mediawiki(*) 16 | text 17 | end 18 | 19 | # 20 | def to_mediawiki(*) 21 | self 22 | end 23 | 24 | alias_method :mw, :mediawiki 25 | alias_method :to_mw, :to_mediawiki 26 | 27 | # 28 | def html(*data, &content) 29 | #render_engine.render(:text=>text, :file=>file, :format=>:html) 30 | render_into(:html, *data, &content) 31 | end 32 | 33 | # Convert to HTML. 34 | def to_html(*) 35 | opts = options.merge(:text=>html, :file=>refile(:html), :type=>:html) 36 | HTML.new(opts) 37 | end 38 | 39 | # 40 | #def latex(*) 41 | # render_engine.render(:text=>text, :file=>file, :format=>:latex) 42 | #end 43 | 44 | # Latex is only supported by the Kramdown engine. 45 | #def to_latex(*) 46 | # opts = options.merge(:text=>html, :file=>refile(:latex), :type=>:latex) 47 | # Latex.new(opts) 48 | #end 49 | 50 | =begin 51 | private 52 | 53 | # Select rendering engine. 54 | def render_engine 55 | @render_engine ||= ( 56 | case engine 57 | when :creole 58 | Malt::Engine::Creole.new(options) 59 | when :wikicloth 60 | Malt::Engine::WikiCloth.new(options) 61 | else 62 | Malt::Engine::WikiCloth.new(options) 63 | end 64 | ) 65 | end 66 | =end 67 | 68 | end 69 | 70 | end 71 | -------------------------------------------------------------------------------- /demo/05css/02less/15_less.rdoc: -------------------------------------------------------------------------------- 1 | == LESS 2 | 3 | Lets say we have a LESS document called 'test.less' containing: 4 | 5 | @brand_color: #4D926F; 6 | #header { 7 | color: @brand_color; 8 | } 9 | h2 { 10 | color: @brand_color; 11 | } 12 | 13 | We can render it via Malt with #render. 14 | 15 | @css = Malt.render(:file=>'test.less') 16 | 17 | And we can verify that @css is: 18 | 19 | #header { 20 | color: #4d926f; 21 | } 22 | h2 { 23 | color: #4d926f; 24 | } 25 | 26 | Look how concise that is. LESS is pretty slick. 27 | 28 | We can also get a hold of the LESS document via the Malt.file function. 29 | 30 | less = Malt.file('test.less') 31 | 32 | less.class.assert == Malt::Format::LESS 33 | 34 | We can convert the LESS document to a CSS document via the #to_css method. 35 | 36 | css = less.to_css 37 | 38 | We can see that the output is an instance of Malt::Format::HTML. 39 | 40 | css.class.assert == Malt::Format::CSS 41 | 42 | And that by calling #to_s we can get the rendered CSS document. 43 | 44 | css.to_s.assert.include?("#header {\n color: #4d926f;") 45 | css.to_s.assert.include?("h2 {\n color: #4d926f;") 46 | 47 | Or we can convert the LESS document directly to CSS via the #css method. 48 | 49 | out = less.css 50 | 51 | out.assert.include?("#header {\n color: #4d926f;") 52 | out.assert.include?("h2 {\n color: #4d926f;") 53 | 54 | Less supports a compression option. We can modify this option on the fly 55 | via the `#with` method. 56 | 57 | less = Malt.file('test.less') 58 | 59 | less.class.assert == Malt::Format::LESS 60 | 61 | out = less.with(:compress=>true).css 62 | 63 | out.assert.include?('#header{color:#4d926f;}') 64 | out.assert.include?('h2{color:#4d926f;}') 65 | 66 | -------------------------------------------------------------------------------- /lib/malt/formats/string.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/erb' 4 | 5 | module Malt::Format 6 | 7 | # Yes, pure Ruby as a template format. 8 | # 9 | # The ruby code is run through eval and whatever is returned is given 10 | # as the rendering. 11 | # 12 | # The Ruby format is a *polyglot* format --it accepts all conversion 13 | # types and assumes the end-user knows it will be the result. 14 | # 15 | # The Ruby type is also used for "precompiling" other formats such 16 | # as ERB. 17 | # 18 | class String < AbstractTemplate 19 | 20 | file_extension 'str' 21 | 22 | # 23 | def string(*) ; text ; end 24 | 25 | # 26 | def to_string(*) ; self ; end 27 | 28 | =begin 29 | # 30 | def to(type, *data, &yld) 31 | new_class = Malt::Format.registry[type.to_sym] # TODO: Malt.machine.format? 32 | new_text = render(*data, &yld) 33 | new_file = refile(type) 34 | new_options = options.merge(:text=>new_text, :file=>new_file) 35 | new_class.new(new_options) 36 | end 37 | =end 38 | 39 | # # Ruby templates can be any type. 40 | # def method_missing(sym, *args, &yld) 41 | # if Malt::Format.registry.key?(sym) 42 | # return to(sym, *args, &yld).to_s 43 | # elsif md = /^to_/.match(sym.to_s) 44 | # type = md.post_match.to_sym 45 | # if Malt::Format.registry.key?(type) # TODO: Malt.machine.format? 46 | # return to(type, *args, &yld) 47 | # end 48 | # end 49 | # super(sym, *args, &yld) 50 | # end 51 | 52 | #private 53 | 54 | ## 55 | #def render_engine 56 | # @render_engine ||= Malt::Engine::String.new(options) 57 | #end 58 | 59 | end 60 | 61 | end 62 | -------------------------------------------------------------------------------- /lib/malt/formats/erb.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract_template' 2 | require 'malt/formats/html' 3 | require 'malt/engines/erb' 4 | require 'malt/engines/erubis' 5 | 6 | module Malt::Format 7 | 8 | # 9 | class Erb < AbstractTemplate 10 | 11 | file_extension 'erb' 12 | 13 | # Technically #method_missing will pick this up, but since it is likely 14 | # to be the most commonly used, adding the method directly will provide 15 | # a small speed boost. 16 | # 17 | def html(*data, &content) 18 | render_into(:html, *data, &content) 19 | end 20 | 21 | # Technically #method_missing will pick this up, but since it is likely 22 | # to be the most commonly used, adding the method directly will provide 23 | # a small speed boost. 24 | def to_html(*data, &yld) 25 | new_text = render(:html, *data, &yld) 26 | new_file = refile(:html) 27 | new_options = options.merge(:text=>new_text, :file=>new_file, :type=>:html) 28 | HTML.new(new_options) 29 | end 30 | 31 | # TODO: compile, if we decide to support 32 | =begin 33 | # TODO: Lookup engine from engine registry. 34 | def rb(*) 35 | render_engine.compile(:text=>text, :file=>file) 36 | end 37 | 38 | # Erb templates can be "pre-compiled" into Ruby templates. 39 | def to_rb(*) 40 | text = rb 41 | Ruby.new(:text=>text, :file=>refile(:rb)) 42 | end 43 | 44 | # 45 | alias_method(:to_ruby, :to_rb) 46 | 47 | # 48 | alias_method :precompile, :to_rb 49 | =end 50 | 51 | #private 52 | 53 | # 54 | #def render_engine 55 | # @render_engine ||= ( 56 | # case engine 57 | # when :erubis 58 | # Malt::Engine::Erubis.new(options) 59 | # else 60 | # Malt::Engine::Erb.new(options) 61 | # end 62 | # ) 63 | #end 64 | 65 | end 66 | 67 | end 68 | -------------------------------------------------------------------------------- /demo/03template/04liquid/06_liquid.rdoc: -------------------------------------------------------------------------------- 1 | == Liquid 2 | 3 | Lets say we have a Liquid document called 'test.liquid' containing: 4 | 5 |

Example {{ title }}

6 | 7 |

This is an example of a Liquid template.

8 | 9 | We can render liquid documents via the +render+ method, as we can any format. 10 | However, becuase Liquid is a template format and not just a markup syntax, 11 | we need to also provide the +render+ function with data for interpolation 12 | into the liquid document. 13 | 14 | data = { :title=>"Document" } 15 | 16 | html = Malt.render(:file=>'test.liquid', :data=>data) 17 | 18 | html.assert.include?('

Example Document

') 19 | 20 | Liquid doesn't actually care what format the document is rendered as, since it 21 | is purely a template engine that can be applied to any other format. 22 | Lets say we have a Liquid document called 'test.liquid' containing: 23 | 24 |

Example {{ title }}

25 | 26 |

This is an example of a Liquid template.

27 | 28 | We can render erb documents to any format we wish. 29 | 30 | liq = Malt.file('test.liquid') 31 | 32 | html = liq.to_html(:title=>"Document") 33 | 34 | We will notice that the output is an instance of Malt::Format::HTML. 35 | 36 | html.class.assert == Malt::Format::HTML 37 | 38 | We will notice that the output is an instance of Malt::Format::HTML. 39 | 40 | html.class.assert == Malt::Format::HTML 41 | 42 | Then by calling #to_s we can get the rendered HTML document. 43 | 44 | html.to_s.assert.include?('

Example Document

') 45 | 46 | Or we can convert the document directly to HTML via the #html method. 47 | 48 | out = liq.html(:title=>"Alternate") 49 | 50 | out.assert.include?('

Example Alternate

') 51 | 52 | Liquid doesn't actually care what format the document is rendered as, since it 53 | is purely a template engine that can be applied to any format. 54 | 55 | -------------------------------------------------------------------------------- /lib/malt/engines/erubis.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Erubis template implementation. 6 | # 7 | # http://www.kuwata-lab.com/erubis/ 8 | # 9 | # Erubis is essentially compatibel with ERB, but it is faster. 10 | # 11 | class Erubis < Abstract 12 | 13 | register :erb, :rhtml, :eruby 14 | 15 | # Render template. 16 | def render(params, &content) 17 | text, file, scope, locals = parameters(params, :text, :file, :scope, :locals) 18 | 19 | # NOTE: Erubis can handle hash data via result(:list=>data). 20 | # Would it be better to use that? 21 | 22 | bind = make_binding(scope, locals, &content) 23 | 24 | prepare_engine(params).result(bind) 25 | end 26 | 27 | # 28 | #def prepare_eninge(params={}) 29 | # create_engine(params) 30 | #end 31 | 32 | # 33 | def create_engine(params={}) 34 | text, file, esc = parameters(params, :text, :file, :escape_html) 35 | 36 | opts = engine_options(params) 37 | 38 | cached(text, file, esc, opts) do 39 | if esc 40 | ::Erubis::EscapedEruby.new(text, opts) 41 | else 42 | ::Erubis::Eruby.new(text, opts) 43 | end 44 | end 45 | end 46 | 47 | # Compile template into Ruby source code. 48 | #def compile(params) 49 | # if cache? 50 | # @source[params] ||= intermediate(params).src 51 | # else 52 | # intermediate(params).src 53 | # end 54 | #end 55 | 56 | private 57 | 58 | # Load ERB library if not already loaded. 59 | def require_engine 60 | return if defined? ::Erubius 61 | require_library('erubis') 62 | end 63 | 64 | # 65 | ENGINE_OPTION_NAMES = %w{safe trim pattern preamble postable} 66 | 67 | # 68 | def engine_option_names 69 | ENGINE_OPTION_NAMES 70 | end 71 | 72 | end 73 | 74 | end 75 | 76 | -------------------------------------------------------------------------------- /demo/03template/05mustache/20_mustache.rdoc: -------------------------------------------------------------------------------- 1 | == Mustache 2 | 3 | Lets say we have a Mustache document called 'test.mustache' containing: 4 | 5 |

Example {{ title }}

6 | 7 |

This is an example of a Mustache template.

8 | 9 | We can render mustache documents via the +render+ method, as we can any format. 10 | However, becuase Mustache is a template format and not just a markup syntax, 11 | we need to also provide the +render+ function with data for interpolation 12 | into the mustache document. 13 | 14 | data = { :title=>"Document" } 15 | 16 | html = Malt.render(:file=>'test.mustache', :data=>data) 17 | 18 | html.assert.include?('

Example Document

') 19 | 20 | Mustache doesn't actually care what format the document is rendered as, 21 | since it is purely a template engine that can be applied to any other format. 22 | Lets say we have a Mustache document called 'test.mustache' containing: 23 | 24 |

Example {{ title }}

25 | 26 |

This is an example of a Mustache template.

27 | 28 | We can render erb documents to any format we wish. 29 | 30 | liq = Malt.file('test.mustache') 31 | 32 | html = liq.to_html(:title=>"Document") 33 | 34 | We will notice that the output is an instance of Malt::Format::HTML. 35 | 36 | html.class.assert == Malt::Format::HTML 37 | 38 | We will notice that the output is an instance of Malt::Format::HTML. 39 | 40 | html.class.assert == Malt::Format::HTML 41 | 42 | Then by calling #to_s we can get the rendered HTML document. 43 | 44 | html.to_s.assert.include?('

Example Document

') 45 | 46 | Or we can convert the document directly to HTML via the #html method. 47 | 48 | out = liq.html(:title=>"Alternate") 49 | 50 | out.assert.include?('

Example Alternate

') 51 | 52 | Mustache doesn't actually care what format the document is rendered as, since it 53 | is purely a template engine that can be applied to any format. 54 | 55 | -------------------------------------------------------------------------------- /lib/malt/engines/markaby.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Markaby 6 | # 7 | # @see http://markaby.rubyforge.org/ 8 | # 9 | # Markaby doesn't support template caching b/c the the initializer 10 | # takes the local variable settings. 11 | # 12 | class Markaby < Abstract 13 | 14 | default :markaby, :mab 15 | register :rbml, :builder 16 | 17 | # 18 | def render(params={}, &content) 19 | into = parameters(params, :to) || :html 20 | 21 | case into 22 | when :html, :xml, :xhtml 23 | prepare_engine(params, &content).to_s 24 | else 25 | super(params, &content) 26 | end 27 | end 28 | 29 | # TODO: Prefix support ? 30 | 31 | # 32 | def prepare_engine(params={}, &content) 33 | prefix, text, file, scope, locals, prefix = parameters(params, :prefix, :text, :file, :scope, :locals) 34 | 35 | file = file || "(markaby)" 36 | 37 | if prefix 38 | raise NotImplmentedError, "Markaby doesn't support prefix templates." 39 | #scope, locals = scope_and_locals(data, &content) 40 | #scope, locals = split_data(data) 41 | 42 | scope ||= Object.new 43 | locals ||= {} 44 | 45 | mab = ::Markaby::Builder.new(locals) #, scope) 46 | 47 | code = %{ 48 | lambda do |#{prefix}| 49 | #{text} 50 | end 51 | } 52 | 53 | eval(code, scope.to_binding, file).call(mab) 54 | else 55 | scope, locals = make_external(scope, locals, &content) 56 | 57 | mab = ::Markaby::Builder.new(locals, scope) 58 | mab.instance_eval(text, file) 59 | mab 60 | end 61 | end 62 | 63 | private 64 | 65 | # Load Markaby library if not already loaded. 66 | def require_engine 67 | return if defined? ::Markaby 68 | require_library 'markaby' 69 | end 70 | 71 | end 72 | 73 | end 74 | -------------------------------------------------------------------------------- /lib/malt/engines/kramdown.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Kramdown Markdown implementation. 6 | # 7 | # http://kramdown.rubyforge.org/ 8 | # 9 | class Kramdown < Abstract 10 | 11 | register :markdown, :md 12 | 13 | # Convert Markdown text to HTML text. 14 | # 15 | # @param [Hash] params 16 | # A hash containing the Markdown extensions which the parser 17 | # will identify. The following extensions are accepted. 18 | # 19 | # @option params [String] :text 20 | # Template text. 21 | # 22 | # @option params [String,Symbol] :to ('html') 23 | # Type or file extension to convert template into. 24 | # 25 | # @see http://kramdown.rubyforge.org/rdoc/Kramdown/Options.html 26 | # 27 | def render(params={}) 28 | into, text = parameters(params, :to, :text) 29 | 30 | case into 31 | when :html, nil 32 | prepare_engine(params).to_html 33 | when :latex 34 | prepare_engine(params).to_latex 35 | else 36 | super(params) 37 | end 38 | end 39 | 40 | # Convert Markdown text to intermediate object. 41 | def create_engine(params={}) 42 | text = parameters(params, :text) 43 | cached(text) do 44 | ::Kramdown::Document.new(text) 45 | end 46 | end 47 | 48 | private 49 | 50 | # Load rdoc makup library if not already loaded. 51 | def require_engine 52 | return if defined? ::Kramdown 53 | require_library 'kramdown' 54 | end 55 | 56 | # Kramdown has lots of options! 57 | ENGINE_OPTION_NAMES = %w{ 58 | auto_id_prefix auto_ids 59 | coderay_bold_every coderay_css coderay_line_number_start 60 | coderay_line_numbers coderay_tab_width coderay_wrap 61 | entity_output footnote_nr html_to_native latex_headers 62 | line_width parse_block_html parse_span_html smart_quotes 63 | template toc_levels 64 | } 65 | 66 | # 67 | def engine_option_names 68 | ENGINE_OPTION_NAMES 69 | end 70 | 71 | end 72 | 73 | end 74 | 75 | 76 | -------------------------------------------------------------------------------- /demo/04sgml/05erector/format_erector.rdoc: -------------------------------------------------------------------------------- 1 | == Erector 2 | 3 | Lets say we have a Erector document called 'test.erector' containing: 4 | 5 | html do 6 | h1 "Example #{@title}" 7 | p "This is an example of a Maraby template." 8 | end 9 | 10 | Notice the use of the instance variable. Erector templates must use instance 11 | variables for data rendering in order to avoid ambiguity with the markup 12 | syntax itself. 13 | 14 | === Rendering 15 | 16 | We can render Erector documents via the +render+ method, as we can any format. 17 | Since Erector is a template format and not just a markup syntax, so we need 18 | to also provide the +render+ function with data for interpolation into the 19 | Erector document. 20 | 21 | data = { :title=>"Document" } 22 | 23 | html = Malt.render(:file=>'test.erector', :data=>data, :engine=>:erector) 24 | 25 | html.assert.include?('

Example Document

') 26 | 27 | === Format Object 28 | 29 | We can get a hold of the Erector document via the Malt.file function. 30 | 31 | erector = Malt.file('test.erector', :engine=>:erector) 32 | 33 | erector.class.assert == Malt::Format::Builder 34 | 35 | We can convert Erector documents to html very easily. 36 | 37 | data = {:title => "Document"} 38 | 39 | html = erector.to_html(data) 40 | 41 | First we will notice that the output is an instance of Malt::Format::HTML. 42 | 43 | html.class.assert == Malt::Format::HTML 44 | 45 | And that by calling #to_s we can get the rendered HTML document. 46 | 47 | html.to_s.assert.include?('

Example Document

') 48 | 49 | Or we can convert the Erector document directly to HTML via the #html method. 50 | 51 | out = erector.html(data) 52 | 53 | out.assert.include?('

Example Document

') 54 | 55 | === Content Block 56 | 57 | Lets say we have an Erector document called 'test.erector' containing: 58 | 59 | html do 60 | h1 'Document' 61 | div @content 62 | end 63 | 64 | Then rendering, 65 | 66 | out = Malt.render(:file=>'test.erector', :engine=>:erector){ 'Content' } 67 | 68 | Should produce, 69 | 70 | out.assert == "

Document

Content
" 71 | 72 | -------------------------------------------------------------------------------- /lib/malt/engines/maruku.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Redcarpet Markdown implementation. 6 | # 7 | # http://maruku.rubyforge.org/ 8 | # 9 | class Maruku < Abstract 10 | 11 | register :markdown, :md 12 | 13 | # Convert Markdown text to HTML text. 14 | # 15 | # @param [Hash] params 16 | # 17 | # @option params [String] :text 18 | # Template text 19 | # 20 | # @option params [String,Symbol] :to ('html') 21 | # Type or file extension to convert template into. 22 | # 23 | def render(params={}) 24 | into, text, part = parameters(params, :to, :text, :partial) 25 | 26 | engine = prepare_engine(params) 27 | 28 | case into 29 | when :html, nil 30 | if part 31 | engine.to_html 32 | else 33 | engine.to_html_document 34 | end 35 | when :latex #, :pdf 36 | if part 37 | engine.to_latex 38 | else 39 | engine.to_latex_document 40 | end 41 | else 42 | super(params) 43 | end 44 | end 45 | 46 | # Convert Markdown text to intermediate object. 47 | # 48 | # @param [Hash] params 49 | # A hash containing the Markdown extensions which the parser 50 | # will identify. The following extensions are accepted. 51 | # 52 | # @option params [Symbol] :on_error 53 | # If :raise, then raise error. 54 | # 55 | def create_engine(params={}) 56 | text = parameters(params, :text) 57 | opts = engine_options(params) 58 | 59 | ::Maruku.new(text, opts) 60 | end 61 | 62 | private 63 | 64 | # Supported engine options. 65 | # 66 | # @todo Add more options. 67 | # 68 | # @see http://maruku.rubyforge.org/exd.html 69 | # 70 | ENGINE_OPTION_NAMES = %w{ 71 | math_enabled 72 | } 73 | 74 | # Load rdoc makup library if not already loaded. 75 | def require_engine 76 | return if defined? ::Maruku 77 | require_library 'maruku' 78 | end 79 | 80 | # 81 | def engine_option_names 82 | ENGINE_OPTION_NAMES 83 | end 84 | 85 | end 86 | 87 | end 88 | 89 | 90 | -------------------------------------------------------------------------------- /work/consider/slim/lib/malt/engines/slim.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Slim 6 | # 7 | class Slim < Abstract 8 | 9 | default :slim 10 | 11 | # 12 | def render(params, &yld) 13 | into = params[:to] 14 | case into 15 | when :html, nil 16 | render_html(params, &yld) 17 | else 18 | super(params, &yld) 19 | end 20 | end 21 | 22 | # 23 | def render_html(params, &yld) 24 | text = params[:text] 25 | file = params[:file] 26 | data = params[:data] 27 | 28 | scope, data = make_object_and_hash(data) 29 | scope ||= Object.new 30 | 31 | engine = intermediate(params) 32 | engine.render(scope, data, &yld) 33 | 34 | #case data 35 | #when Binding 36 | # raise ArgumentError, "redundant scope" if scope 37 | # html = engine.render(make_object(data), &yld) 38 | #when Hash 39 | # scope = scope || Object.new 40 | # scope = scope.self if Binding === scope 41 | # html = engine.render(scope, data, &yld) 42 | #else 43 | # if data.respond_to?(:to_hash) 44 | # data = data.to_hash 45 | # scope = scope || Object.new 46 | # scope = scope.self if Binding === scope 47 | # html = engine.render(scope, data, &yld) 48 | # else 49 | # raise ArgumentError, "redundant scope" if data && scope 50 | # html = engine.render(data || scope, &yld) 51 | # end 52 | #end 53 | #html 54 | end 55 | 56 | # 57 | #def compile(text, file) 58 | # intermediate # ?? 59 | #end 60 | 61 | # 62 | def intermediate(params) 63 | text = params[:text] 64 | file = params[:file] 65 | if text 66 | ::Slim::Engine.new(file) 67 | else 68 | if file 69 | ::Slim::Engine.new(file){ text } 70 | else 71 | ::Slim::Engine.new{ text } 72 | end 73 | end 74 | end 75 | 76 | private 77 | 78 | # Load Slim library if not already loaded. 79 | def initialize_engine 80 | return if defined? ::Slim::Engine 81 | require_library 'slim' 82 | end 83 | 84 | end 85 | 86 | end 87 | 88 | -------------------------------------------------------------------------------- /lib/malt/formats/markdown.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/formats/latex' 4 | require 'malt/engines/rdiscount' 5 | require 'malt/engines/bluecloth' 6 | require 'malt/engines/maruku' 7 | require 'malt/engines/redcarpet' 8 | require 'malt/engines/kramdown' 9 | 10 | module Malt::Format 11 | 12 | # If using the Kramdown engine, then Latex is also a supported output format. 13 | class Markdown < Abstract 14 | 15 | register('markdown', 'md') 16 | 17 | # 18 | def markdown(*) 19 | text 20 | end 21 | 22 | alias_method :md, :markdown 23 | 24 | # 25 | def to_markdown(*) 26 | self 27 | end 28 | 29 | alias_method :to_md, :to_markdown 30 | 31 | # 32 | def html(*data, &context) 33 | #engine.render(:text=>text, :file=>file, :format=>:html) 34 | render_into(:html, *data, &context) 35 | end 36 | 37 | # Convert to HTML. 38 | def to_html(*) 39 | opts = options.merge(:text=>html, :file=>refile(:html), :type=>:html) 40 | HTML.new(opts) 41 | end 42 | 43 | # 44 | def latex(*data, &content) 45 | render_into(:latex, *data, &content) 46 | #render_engine.render(:text=>text, :file=>file, :format=>:latex) 47 | end 48 | 49 | # Latex is only supported by the Kramdown engine. 50 | def to_latex(*) 51 | opts = options.merge(:text=>html, :file=>refile(:latex), :type=>:latex) 52 | Latex.new(opts) 53 | end 54 | 55 | =begin 56 | private 57 | 58 | # Select rendering engine. 59 | def render_engine 60 | @render_engine ||= ( 61 | case engine 62 | when :bluecloth 63 | Malt::Engine::BlueCloth.new(options) 64 | when :kramdown 65 | Malt::Engine::Kramdown.new(options) 66 | when :rdiscount 67 | Malt::Engine::RDiscount.new(options) 68 | when :redcarpet 69 | Malt::Engine::Redcarpet.new(options) 70 | when :maruku 71 | Malt::Engine::Maruku.new(options) 72 | else 73 | #Malt::Engine::Redcarpet.new(options) # TODO: new default ? 74 | Malt::Engine::RDiscount.new(options) 75 | end 76 | ) 77 | end 78 | =end 79 | 80 | end 81 | 82 | end 83 | -------------------------------------------------------------------------------- /demo/04sgml/03nokogiri/nokogiri.rdoc: -------------------------------------------------------------------------------- 1 | == Nokogiri 2 | 3 | Lets say we have a Nokogiri document called 'test.nokogiri' containing: 4 | 5 | html do 6 | h1 "Example #{@title}" 7 | p_ "This is an example of a Nokogiri template." 8 | end 9 | 10 | Notice the use of the instance variable. Nokogiri templates must use instance 11 | variables for data rendering in order to avoid ambiguity with the markup 12 | syntax itself. 13 | 14 | === Rendering 15 | 16 | We can render Nokogiri documents via the +render+ method, as we can any format. 17 | Since Nokogiri is a template format and not just a markup syntax, so we need 18 | to also provide the +render+ function with data for interpolation into the 19 | Nokogiri document. 20 | 21 | data = { :title=>"Document" } 22 | 23 | html = Malt.render(:file=>'test.nokogiri', :data=>data, :engine=>:nokogiri) 24 | 25 | html.assert.include?('

Example Document

') 26 | html.assert.include?('

This is an example of a Nokogiri template.

') 27 | 28 | === Format Object 29 | 30 | We can get a hold of the Nokogiri document via the Malt.file function. 31 | 32 | nokogiri = Malt.file('test.nokogiri', :engine=>:nokogiri) 33 | 34 | nokogiri.class.assert == Malt::Format::Builder 35 | 36 | We can convert Nokogiri documents to html very easily. 37 | 38 | data = {:title => "Document"} 39 | 40 | html = nokogiri.to_html(data) 41 | 42 | First we will notice that the output is an instance of Malt::Format::HTML. 43 | 44 | html.class.assert == Malt::Format::HTML 45 | 46 | And that by calling #to_s we can get the rendered HTML document. 47 | 48 | html.to_s.assert.include?('

Example Document

') 49 | 50 | Or we can convert the Nokogiri document directly to HTML via the #html method. 51 | 52 | out = nokogiri.html(data) 53 | 54 | out.assert.include?('

Example Document

') 55 | 56 | === Content Block 57 | 58 | Lets say we have a Nokogiri document called 'test.nokogiri' containing: 59 | 60 | html do 61 | h1 'Document' 62 | div @content 63 | end 64 | 65 | Then rendering, 66 | 67 | out = Malt.render(:file=>'test.nokogiri', :engine=>:nokogiri){ 'Content' } 68 | 69 | out.gsub!("\n",'') # to remove newlines for ease of testing 70 | 71 | Should produce, 72 | 73 | out.assert == "

Document

Content
" 74 | 75 | -------------------------------------------------------------------------------- /lib/malt/engines/rdoc.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # RDoc template. 6 | # 7 | # http://rdoc.rubyforge.org/ 8 | # 9 | # It's suggested that your program require 'rdoc/markup' and 10 | # 'rdoc/markup/to_html' at load time when using this template 11 | # engine. 12 | class RDoc < Abstract 13 | 14 | default :rdoc 15 | 16 | # Convert rdoc text to html. 17 | def render(params={}) 18 | into, text = parameters(params, :to, :text) 19 | 20 | case into 21 | when :html, nil 22 | prepare_engine(params).convert(text).to_s 23 | else 24 | super(params) 25 | end 26 | end 27 | 28 | # 29 | def create_engine(params={}) 30 | into = parameters(params, :to) 31 | 32 | opts = engine_options(params) 33 | opts['rdoc_include'] = [] 34 | opts['static_path'] = [] 35 | 36 | rdoc_opts = ::RDoc::Options.new 37 | rdoc_opts.init_with(opts) 38 | 39 | # TODO: Do we need to cache on options too (if there ever are any)? 40 | cached(into) do 41 | ::RDoc::Markup::ToHtml.new(rdoc_opts) 42 | end 43 | end 44 | 45 | private 46 | 47 | # Load rdoc makup library if not already loaded. 48 | def require_engine 49 | return if defined?(::RDoc::Markup) 50 | require 'rubygems' # hack 51 | gem 'rdoc', '> 3' 52 | require_library 'rdoc' 53 | #require_library 'rdoc/markup' 54 | #require_library 'rdoc/markup/to_html' 55 | end 56 | 57 | # TODO: Which of these options are actually useful for convert RDoc to HTML? 58 | # 59 | # charset 60 | # exclude 61 | # generator_name 62 | # hyperlink_all 63 | # line_numbers 64 | # locale_name 65 | # locale_dir 66 | # main_page 67 | # markup 68 | # op_dir 69 | # show_hash 70 | # tab_width 71 | # template_dir 72 | # title 73 | # visibility 74 | # webcvs 75 | # 76 | ENGINE_OPTION_NAMES = %w{ 77 | charset 78 | generator_name 79 | hyperlink_all 80 | line_numbers 81 | locale_name 82 | locale_dir 83 | markup 84 | tab_width 85 | title 86 | visibility 87 | webcvs 88 | } 89 | 90 | # 91 | def engine_option_names 92 | ENGINE_OPTION_NAMES 93 | end 94 | 95 | end 96 | 97 | end 98 | 99 | -------------------------------------------------------------------------------- /lib/malt/engines/nokogiri.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Nokogiri builder-like templates. 6 | # 7 | # @see http://nokogiri.org/ 8 | 9 | class Nokogiri < Abstract 10 | 11 | default :nokogiri 12 | register :rbml, :builder 13 | 14 | # 15 | DOCUMENT_HEADER_XML = /^<\?xml version=\"1\.0\"\?>\n?/ 16 | 17 | # 18 | DOCUMENT_HEADER_HTML = /^<\!DOCTYPE html PUBLIC \".*?\">/ 19 | 20 | # 21 | def render(params={}, &content) 22 | into = parameters(params, :to) || :html 23 | 24 | case into.to_sym 25 | when :html 26 | prepare_engine(params, &content).to_html.sub(DOCUMENT_HEADER_HTML,'') 27 | when :xml, :xhtml 28 | prepare_engine(params, &content).to_xml.sub(DOCUMENT_HEADER_XML,'') 29 | else 30 | super(params, &content) 31 | end 32 | end 33 | 34 | # 35 | def prepare_engine(params={}, &content) 36 | text, file, scope, locals = parameters(params, :text, :file, :scope, :locals) 37 | 38 | scope, locals = make_external(scope, locals, &content) 39 | 40 | engine = create_engine(params) 41 | 42 | locals.each do |k,v| 43 | engine.instance_eval("@#{k} = v") 44 | end 45 | 46 | scope.instance_variables.each do |k| 47 | next if k == "@target" 48 | v = scope.instance_variable_get(k) 49 | engine.instance_eval("#{k} = v") 50 | end 51 | 52 | engine.instance_eval(text, file || inspect) 53 | 54 | engine 55 | end 56 | 57 | # Nokogiri engine cannot be cached as it keeps a copy the 58 | # rendering internally. (Unless there is a way to clear it?) 59 | # 60 | def create_engine(params={}) 61 | into = parameters(params, :to) || :html 62 | 63 | opts = engine_options(params) 64 | 65 | #cached(into, opts) do 66 | case into 67 | when :html 68 | ::Nokogiri::HTML::Builder.new(opts) 69 | else 70 | ::Nokogiri::XML::Builder.new(opts) 71 | end 72 | #end 73 | end 74 | 75 | private 76 | 77 | # Load Nokogiri library if not already loaded. 78 | def require_engine 79 | return if defined? ::Nokogiri 80 | require_library 'nokogiri' 81 | 82 | ::Nokogiri::XML::Builder.class_eval do 83 | undef_method :p 84 | end 85 | end 86 | 87 | end 88 | 89 | end 90 | -------------------------------------------------------------------------------- /work/notes/2010-06-22-markup-vs-template.rdoc: -------------------------------------------------------------------------------- 1 | = 2010-06-22 | Markup vs. Template 2 | 3 | One of the things that I wanted to address with Malt that Tilt 4 | essentially glosses over is the distinction between Markup and 5 | Template systems. Markup languages define a set of format 6 | transformations. Usually there is only one output format, HTML, 7 | but there can be other output formats, such as PDF. 8 | Unlike markup, template engines do not handle format conversions 9 | but rather define a "meta-syntax" for injecting an extral data 10 | source into a document. 11 | 12 | Because of these distinctions the two have different interfaces. 13 | For example markups can have multiple output format methods. 14 | 15 | Malt::Markup.file('foo.rdoc').to_html 16 | Malt::Markup.file('foo.rdoc').to_pdf 17 | 18 | While templates have only the ability to be compiled and then 19 | rendered as a string. 20 | 21 | Malt::Template.file('foo.erb').compile(db).to_s 22 | 23 | So how do we merge these two interfaces to provide a single 24 | Malt interface for both type of document that make sense? Well 25 | lets take the two possiblities and consider each in turn. 26 | 27 | For markup, if we encountered: 28 | 29 | Malt.file('foo.erb').to_html 30 | 31 | Obviously things are a miss. Niether has the template been 32 | rendered nor is HTML the necessary output format. 33 | 34 | On the other side of the coin if we encountered: 35 | 36 | Malt.file('foo.rdoc').compile(db).to_s 37 | 38 | Compilation would be meaningless and what format does #to_s 39 | mean --whould it simply be the original document? 40 | 41 | Should we try to reconcile these diferences in someway? Can 42 | we allow #compile simply to pass thru the rdoc document? 43 | Can #to_s be mapped to #to_html becuase that is by far and 44 | away the most common case? 45 | 46 | Or perhaps the better approach is to accept they are different 47 | and simply provide an ability to test for it? 48 | 49 | mdoc = Malt.file(fname) 50 | if mdoc.markup? 51 | mdoc.to_html 52 | else 53 | mdoc.compile(db) 54 | end 55 | 56 | Considering how people might use the library, the best approach 57 | might be a compromise between the two. We allow compile(db), 58 | or perhaps a variant soft_compile(db), to pass thru markup, but 59 | to the end result can not render via #to_html or the like than 60 | an error is raised. 61 | 62 | 63 | 64 | 65 | 66 | -------------------------------------------------------------------------------- /lib/malt/formats/builder.rb: -------------------------------------------------------------------------------- 1 | require 'malt/formats/abstract' 2 | require 'malt/formats/html' 3 | require 'malt/engines/builder' 4 | require 'malt/engines/markaby' 5 | require 'malt/engines/nokogiri' 6 | require 'malt/engines/erector' 7 | 8 | module Malt::Format 9 | 10 | # Builder is the format common to Builder, Markaby, Erector and Nokogiri's Builder. 11 | # Although there are some variant features between them, they all support the 12 | # same general format. The format looks like a Markup format, but is in fact a 13 | # templating system built out of Ruby code for creating XML/HTML documents. 14 | # 15 | # @see http://builder.rubyforge.org/ 16 | # @see http://markaby.rubyforge.org/ 17 | # @see http://erector.rubyforge.org/ 18 | # @see http://nokogiri.org/ 19 | # 20 | # To unite these different engines I have designated them a common file 21 | # extension of `.rbml`. 22 | # 23 | class Builder < Abstract 24 | 25 | file_extension 'rbml', 'builder', 'nokogiri', 'mab', 'markaby', 'erector' 26 | 27 | # 28 | def builder(*) 29 | text 30 | end 31 | alias_method :rbml, :builder 32 | 33 | # 34 | def to_builder(*) 35 | self 36 | end 37 | alias_method :to_rbml, :to_builder 38 | 39 | # 40 | def html(*data, &content) 41 | #render_engine.render(:to=>:html, :text=>text, :file=>file, :data=>data, &yld) 42 | render_into(:html, *data, &content) 43 | end 44 | 45 | # 46 | def to_html(*data, &content) 47 | text = html(*data, &content) 48 | opts = options.merge(:text=>text, :file=>refile(:html), :type=>:html) 49 | HTML.new(opts) 50 | end 51 | 52 | # 53 | #def to_ruby(db, &yld) 54 | # @ruby ||= ( 55 | # source = engine.compile(text, file) 56 | # Ruby.new(:text=>source, :file=>refile(:rb)) 57 | # ) 58 | #end 59 | 60 | private 61 | 62 | # TODO: allow the type to influence the engine selection 63 | # 64 | #def render_engine 65 | # @render_engine ||= ( 66 | # case engine 67 | # when :erector 68 | # Malt::Engine::Erector.new(options) 69 | # when :builder 70 | # Malt::Engine::Builder.new(options) 71 | # when :markaby, :mab 72 | # Malt::Engine::Markaby.new(options) 73 | # else 74 | # Malt::Engine::Nokogiri.new(options) 75 | # end 76 | # ) 77 | #end 78 | 79 | end 80 | 81 | end 82 | 83 | -------------------------------------------------------------------------------- /demo/03template/02erubis/format_erubis.rdoc: -------------------------------------------------------------------------------- 1 | == Erubis 2 | 3 | By default the common ERB library is used to render .erb documents. By setting 4 | the :engine option, Erubis can be used instead. 5 | 6 | Lets say we have a ERB document called 'test.erb' containing: 7 | 8 |

Example <%= title %>

9 | 10 |

This is an example of ERB template.

11 | 12 | And data to supply the template. 13 | 14 | data = { :title=>"Document" } 15 | 16 | 17 | === Engine 18 | 19 | Malt::Engine::Erubis.new(:text=>'

<%= title %>

') 20 | 21 | 22 | === Format 23 | 24 | erb = Malt::Format::Erb.new(:text=>'

<%= title %>

', :engine=>:erbuis) 25 | 26 | 27 | === Malt.file 28 | 29 | We can get an Erb instance via the Malt.file method. 30 | 31 | erb = Malt.file('test.erb', :engine=>:erubis) 32 | 33 | erb.assert.is_a?(Malt::Format::Erb) 34 | 35 | Then we can convert it to HTML using Erubis. 36 | 37 | html = erb.to_html(:title=>"Document", :engine=>:erubis) 38 | 39 | We will notice that the output is an instance of Malt::Format::HTML. 40 | 41 | html.class.assert == Malt::Format::HTML 42 | 43 | And that by calling #to_s we can get the rendered HTML document. 44 | 45 | html.to_s.assert.include?('

Example Document

') 46 | 47 | Or we can convert the document directly to HTML via the #html method. 48 | 49 | out = erb.html(:title=>"Alternate") 50 | 51 | out.assert.include?('

Example Alternate

') 52 | 53 | 54 | === Malt.text 55 | 56 | When using `Malt.text` without supplying a `:file` setting, then we must supply 57 | the `:type`. 58 | 59 | erb = Malt.text('

<%= title %>

', :type=>:erb, :engine=>:erubis) 60 | 61 | erb.assert.is_a?(Malt::Format::Erb) 62 | 63 | 64 | === Malt.render 65 | 66 | We can render via Erubis using the `Malt.render` method. Malt will 67 | automatically recognize the format and the engine to use by the file 68 | extensions. 69 | 70 | html = Malt.render(:file=>'test.erb', :data=>data, :engine=>:erubis) 71 | 72 | And as we can see the document rendered as expected. 73 | 74 | html.assert.include?('

Example Document

') 75 | 76 | 77 | ==== Content Block 78 | 79 | Lets say we have an ERB document called 'test.erb' containing: 80 | 81 | Hello <%= content %>! 82 | 83 | Then 84 | 85 | data = { :title=>"Document" } 86 | 87 | text = Malt.render(:file=>'test.erb',:engine=>:erubis){ 'world' } 88 | 89 | Then 90 | 91 | text.strip #=> "Hello world!" 92 | 93 | -------------------------------------------------------------------------------- /lib/malt/engines/erector.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # The Erector template engine handles a builder-style template format. 6 | # 7 | # @see http://erector.rubyforge.org/userguide.html 8 | # 9 | # For Erector templates the data is passed in as attribute variables. 10 | # 11 | # A simple example template: 12 | # 13 | # div do 14 | # h1 @name 15 | # div @state, :id=>'state' 16 | # div @content, :id=>'yield' 17 | # end 18 | # 19 | # IMPORTANT! Erecotor templates do not currently support scope. 20 | # 21 | class Erector < Abstract 22 | 23 | default :erector 24 | register :rbml, :builder 25 | 26 | # 27 | def render(params={}, &content) 28 | into = params[:to] || :html 29 | 30 | case into 31 | when :html, :xhtml 32 | prepare_engine(params, &content).to_html 33 | else 34 | super(params, &content) 35 | end 36 | end 37 | 38 | # Return Erector parser, ready to render results. 39 | def prepare_engine(params={}, &content) 40 | file, scope, locals = parameters(params, :file, :scope, :locals) 41 | 42 | scope, locals = make_external(scope, locals, &content) 43 | 44 | unless scope.respond_to?(:to_struct) 45 | scope_locals = {} 46 | scope.instance_variables.each do |k| 47 | next if k == "@target" 48 | name = k.to_s.sub('@','').to_sym 49 | v = scope.instance_variable_get(k) 50 | scope_locals[name] = v 51 | end 52 | locals = scope_locals.merge(locals) 53 | end 54 | 55 | create_engine(params).new(locals) 56 | end 57 | 58 | # TODO: how to support scope ? 59 | 60 | # Erector constructor support caching. 61 | # 62 | def create_engine(params={}) 63 | text, prefix = parameters(params, :text, :prefix) 64 | 65 | cached(prefix, text) do 66 | Class.new(::Erector::Widget) do 67 | module_eval %{ 68 | def #{prefix}; self; end 69 | } if prefix 70 | 71 | module_eval %{ 72 | def content 73 | #{text} 74 | end 75 | } 76 | end 77 | end 78 | end 79 | 80 | private 81 | 82 | # Load Erector library if not already loaded. 83 | def require_engine 84 | return if defined? ::Erector 85 | require_library 'erector' 86 | end 87 | 88 | end 89 | 90 | end 91 | -------------------------------------------------------------------------------- /work/trash/render.rb: -------------------------------------------------------------------------------- 1 | raise "not used anymore" 2 | 3 | require 'malt/kernel' 4 | require 'malt/config' 5 | require 'malt/core_ext' 6 | 7 | module Malt 8 | 9 | extend Kernel 10 | 11 | # 12 | def self.config 13 | @config ||= Config.new 14 | end 15 | 16 | # Render template. 17 | # 18 | # parameters[:file] - File name of template. Used to read text. 19 | # parameters[:text] - Text of template document. 20 | # parameters[:type] - File type/extension used to look up engine. 21 | # parameters[:pass] - If not a supported type return text rather than raise an error. 22 | # parameters[:engine] - Force the use of a this specific engine. 23 | # parameters[:to] - Format to convert to (usual default is `html`). 24 | # 25 | def self.render(parameters={}, &body) 26 | type = parameters[:type] 27 | file = parameters[:file] 28 | text = parameters[:text] 29 | engine = parameters[:engine] 30 | 31 | type = file_type(file, type) 32 | text = file_read(file) unless text 33 | 34 | engine_class = engine(type, engine) 35 | 36 | if engine_class 37 | parameters[:type] = type 38 | parameters[:text] = text 39 | 40 | engine = engine_class.new 41 | engine.render(parameters, &body) 42 | else 43 | if parameters[:pass] 44 | text 45 | else 46 | raise "no engine to handle `#{type}' format" 47 | end 48 | end 49 | end 50 | 51 | # 52 | def self.engine(type, engine=nil) 53 | type = ext_to_type(type) 54 | engine = engine || config.engine[type] 55 | case engine 56 | when Class 57 | #raise unless Engine.registry[type].include?(engine) 58 | engine 59 | when String, Symbol 60 | match = engine.to_s.downcase 61 | Engine.registry[type].find{ |e| e.basename.downcase == match } 62 | else 63 | if Engine.registry[type] 64 | Engine.registry[type].first 65 | else 66 | nil 67 | end 68 | end 69 | end 70 | 71 | # 72 | def self.file_type(file, type=nil) 73 | ext = type || File.extname(file) 74 | ext = ext.to_s.downcase 75 | if ext.empty? 76 | nil 77 | elsif ext[0,1] == '.' 78 | ext[1..-1].to_sym 79 | else 80 | ext.to_sym 81 | end 82 | end 83 | 84 | # 85 | #def self.ext_type(type) 86 | # type.to_s.downcase.sub(/^\./,'').to_sym 87 | #end 88 | 89 | # TODO: Handle File objects and URLs. 90 | def self.file_read(file) 91 | File.read(file) 92 | end 93 | 94 | end 95 | 96 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # [Malt](http://rubyworks.github.io/malt) 2 | 3 | [![Version](https://img.shields.io/gem/v/malt.svg)](https://rubygems.org/gems/malt) 4 | [![Build Status](https://secure.travis-ci.org/rubyworks/malt.png)](http://travis-ci.org/rubyworks/malt) 5 | [![Issues](https://img.shields.io/github/issues-raw/rubyworks/malt.svg)](https://github.com/rubyworks/malt/issues) 6 | 7 | Malt provides a factory framework for rendering a variety of template and 8 | markup document formats. Malt has a very object-oriented design 9 | utilizing separate engine adapter classes and format classes. This makes 10 | Malt easy to maintain, debug and extend, and thus more robust. In fact, 11 | Malt supports template caching and ERB compilation by default, which was 12 | very easy to implement thanks to it's clean design. 13 | 14 | 15 | ## Usage 16 | 17 | ### Functional API 18 | 19 | Malt.render(:file=>'foo.erb', :to=>:html, :data=>data) 20 | 21 | Where `data` is a data source of some type. Malt will see 22 | that the file is an ERB template and render it accordingly. 23 | 24 | The output of this call will be the HTML String. 25 | 26 | ### Object-Oriented API 27 | 28 | Malt.file('foo.erb').to_html(data).to_s 29 | 30 | Where +data+ is a data source of some type. Malt will see 31 | that the file is an ERB template and render it accordingly. 32 | 33 | To get the render text you simple need to provide the template 34 | or markup type. 35 | 36 | Malt.text(text, :type=>:erb).to_html(data).to_s 37 | 38 | Notice the `#to_s` method call. This is needed because #to_html 39 | returns a `Malt::Format::HTML` object. 40 | 41 | 42 | ## Limitations 43 | 44 | *JRuby* and *Rubinus* users: Not all template systems work with your Ruby. 45 | Consequently not all of Malt will work either. Thankfully Malt only 46 | requires template engines as they are needed, so it will work fine 47 | in most cases. But, you will need to avoid engines that depend on compiled 48 | code, such as `less` and `coffee-script`. 49 | 50 | 51 | ## Installation 52 | 53 | To install with RubyGems simply open a console and type: 54 | 55 | $ gem install 56 | 57 | Usiong Bundler add to your gem file. 58 | 59 | gem 'malt' 60 | 61 | For a site install you will need Ruby Setup and the compressed 62 | packages (tar.gz or zip usually). Uncompress the package cd into 63 | it and run setup.rb, e.g. 64 | 65 | $ tar -xvzf malt-x.y.z.tgz 66 | $ cd malt-x.y.z.tgz 67 | $ sudo setup.rb 68 | 69 | 70 | ## Copyrights 71 | 72 | Copyright (c) 2010 Rubyworks 73 | 74 | This program is ditributed under the terms of the *BSD-2-Clause* license. 75 | 76 | See the LICENSE.txt file for details. 77 | -------------------------------------------------------------------------------- /demo/04sgml/scope.rdoc: -------------------------------------------------------------------------------- 1 | === Scope Redering 2 | 3 | Builder formats, such as Builder, Markaby, Nokogiri and Erector, can only 4 | support evaluation scopes by externalizing them, since they must evaluate 5 | templates from within their own evaluation scopes in order to work. To 6 | compensate, the scope is made availabe via the `@scope` variable. 7 | 8 | To demonstrate, lets say we the following @template: 9 | 10 | html do 11 | h1 "Example #{@scope.title}" 12 | p "This is an example of a Markaby template." 13 | end 14 | 15 | Then for each engine we will see 16 | 17 | %w{markaby builder erector nokogiri}.each do |engine| 18 | 19 | data = Struct.new(:title).new('Document') 20 | 21 | html = Malt.render(:text=>@template, :type=>:rbml, :data=>data, :engine=>engine) 22 | 23 | html.assert.include?('

Example Document

') 24 | html.assert.include?('

This is an example of a Markaby template.

') 25 | 26 | end 27 | 28 | In additions to this, any instancnce variables defined within the scope are also 29 | made available as instance_variables in the template. 30 | 31 | To demonstrate lets say we have the following @template: 32 | 33 | html do 34 | h1 "Example #{@title}" 35 | p "This is an example of a Markaby template." 36 | end 37 | 38 | Then 39 | 40 | %w{markaby builder erector nokogiri}.each do |engine| 41 | 42 | data = Class.new do 43 | def initialize 44 | @title = 'Document' 45 | end 46 | end.new 47 | 48 | html = Malt.render(:text=>@template, :type=>:builder, :data=>data, :engine=>engine) 49 | 50 | html.assert.include?('

Example Document

') 51 | html.assert.include?('

This is an example of a Markaby template.

') 52 | 53 | end 54 | 55 | The @scope variable is actually a special wrapper around the actual scope 56 | that allows calls to draw from private methods, which makes it more like 57 | evaluation from within the scope --as it would be for other template engines. 58 | 59 | To demonstrate lets say we have the following @template: 60 | 61 | html do 62 | h1 "Example #{@scope.title}" 63 | p "This is an example of a Markaby template." 64 | end 65 | 66 | Then 67 | 68 | %w{markaby builder erector nokogiri}.each do |engine| 69 | 70 | data = Class.new do 71 | private 72 | def title 73 | 'Document' 74 | end 75 | end.new 76 | 77 | html = Malt.render(:text=>@template, :type=>:builder, :data=>data, :engine=>engine) 78 | 79 | html.assert.include?('

Example Document

') 80 | html.assert.include?('

This is an example of a Markaby template.

') 81 | 82 | end 83 | 84 | -------------------------------------------------------------------------------- /demo/04sgml/04markaby/format_markaby.rdoc: -------------------------------------------------------------------------------- 1 | == Markaby 2 | 3 | Lets say we have a Markaby document called 'test.markaby' containing: 4 | 5 | html do 6 | h1 "Example #{@title}" 7 | p "This is an example of a Markaby template." 8 | end 9 | 10 | Notice the use of the instance variable. Markaby templates use instance 11 | variables for data rendering in order to avoid ambiguity with the markup 12 | syntax itself. 13 | 14 | === Rendering 15 | 16 | We can render Markaby documents via the +render+ method, as we can any format. 17 | Since Markaby is a template format and not just a markup syntax, so we need 18 | to also provide the +render+ function with data for interpolation into the 19 | Markaby document. 20 | 21 | data = { :title=>"Document" } 22 | 23 | html = Malt.render(:file=>'test.markaby', :data=>data, :engine=>:markaby) 24 | 25 | html.assert.include?('

Example Document

') 26 | html.assert.include?('

This is an example of a Markaby template.

') 27 | 28 | === Format Object 29 | 30 | Markaby object's are represented by the `Malt::Format::Builder` class. 31 | We can get a hold of such an object via the Malt.file function. 32 | 33 | markaby = Malt.file('test.markaby', :engine=>:markaby) 34 | 35 | markaby.class.assert == Malt::Format::Builder 36 | 37 | We can convert this to another format, such as html, 38 | 39 | data = {:title => "Document"} 40 | 41 | html = markaby.to_html(data) 42 | 43 | We can see that the output is an instance of Malt::Format::HTML. 44 | 45 | html.class.assert == Malt::Format::HTML 46 | 47 | And then by calling #to_s we can get the rendered HTML document. 48 | 49 | html.to_s.assert.include?('

Example Document

') 50 | 51 | Alternately, we can take a shortcut, and convert the Builder object directly 52 | to an HTML document via the `#html` method. 53 | 54 | out = markaby.html(data) 55 | 56 | out.assert.include?('

Example Document

') 57 | 58 | === Content Block 59 | 60 | Lets say we have a Markaby document called 'test.markaby' containing: 61 | 62 | html do 63 | h1 'Document' 64 | div @content 65 | end 66 | 67 | Then rendering, 68 | 69 | out = Malt.render(:file=>'test.markaby', :engine=>:markaby){ 'Content' } 70 | 71 | Should produce, 72 | 73 | out.assert == "

Document

Content
" 74 | 75 | IMPORTANT NOTE! Markaby will not render trailing data instance varaibles, 76 | e.g. the following @template would have no content: 77 | 78 | html do 79 | h1 "Document" 80 | @content 81 | end 82 | 83 | As can be shown, 84 | 85 | out = Malt.render(:text=>@template, :type=>:markaby, :engine=>:markaby){ 'Content' } 86 | 87 | out.assert == "

Document

" 88 | 89 | -------------------------------------------------------------------------------- /lib/malt/engines/tenjin.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Tenjin 6 | # 7 | # @see http://www.kuwata-lab.com/tenjin/ 8 | # 9 | # Let to it's own designs, Tenjin renders data as template instance variables. 10 | # But that will not work for Malt, so use regular variables instead. 11 | # 12 | class Tenjin < Abstract 13 | 14 | default :tenjin, :rbhtml 15 | 16 | # Render Tenjin. 17 | # 18 | # @option params [String] :escapefunc 19 | # Defaults to 'CGI.escapeHTML'. 20 | # 21 | def render(params, &content) 22 | into, text, file, type, scope, locals = parameters(params, :to, :text, :file, :type, :scope, :locals) 23 | 24 | into ||= :html 25 | 26 | if type == :rbhtml && into != :html 27 | super(params, &content) 28 | else 29 | scope, locals = make_ready(scope, locals, &content) 30 | 31 | engine = prepare_engine(params) 32 | 33 | engine.call(scope, locals) 34 | end 35 | end 36 | 37 | # TODO: is there a way to split this out to a #compile method? 38 | 39 | # 40 | def prepare_engine(params={}, &content) 41 | text, file = parameters(params, :text, :file) 42 | 43 | file ||= "(tenjin)" 44 | 45 | engine = create_engine(params) 46 | script = engine.convert(text, file) 47 | 48 | lambda do |scope, locals| 49 | vars, vals = [], [] 50 | locals.each do |k,v| 51 | vars << k 52 | vals << v 53 | end 54 | 55 | code = %{ 56 | lambda do |#{vars.join(',')}| 57 | _buf = '' 58 | #{script} 59 | _buf 60 | end 61 | } 62 | 63 | eval(code, scope.to_binding, file, 2).call(*vals) 64 | end 65 | end 66 | 67 | # 68 | def create_engine(params={}) 69 | file, text = parameters(params, :file, :text) 70 | 71 | opts = engine_options(params) 72 | 73 | opts[:escapefunc] ||= 'CGI.escapeHTML' 74 | 75 | cached(text, file, opts) do 76 | ::Tenjin::Template.new(nil, opts) 77 | end 78 | end 79 | 80 | # Compile Tenjin document into Ruby source code. 81 | #def compile(params) 82 | # text, file = parameters(params, :text, :file) 83 | # code = intermediate(params).convert(text, file) 84 | # "_buf = ''\n#{code}\n_buf" 85 | #end 86 | 87 | private 88 | 89 | # Load Tenjin library if not already loaded. 90 | def require_engine 91 | return if defined? ::Tenjin::Engine 92 | require_library 'tenjin' 93 | require 'cgi' 94 | end 95 | 96 | # 97 | def engine_option_names 98 | [:escapefunc] 99 | end 100 | 101 | end 102 | 103 | end 104 | 105 | -------------------------------------------------------------------------------- /lib/malt/core_ext.rb: -------------------------------------------------------------------------------- 1 | require 'ostruct' 2 | require 'facets/module/basename' 3 | #require 'facets/to_hash' 4 | require 'facets/hash/rekey' 5 | 6 | =begin 7 | class Hash 8 | # 9 | def to_hash 10 | dup 11 | end unless method_defined?(:to_hash) 12 | 13 | # 14 | def rekey(&block) 15 | h = {} 16 | if block 17 | each{|k,v| h[block[k]] = v } 18 | else 19 | each{|k,v| h[k.to_sym] = v } 20 | end 21 | h 22 | end unless method_defined?(:rekey) 23 | end 24 | =end 25 | 26 | 27 | class Binding 28 | # Conversion for bindings. 29 | # 30 | # @todo Is there any way to integrate the optional data and block? 31 | def to_binding 32 | self 33 | end 34 | 35 | # 36 | def itself 37 | eval('self') 38 | end 39 | 40 | # Create a new binding incorporating the current binding and 41 | # the given local settings hash and yield block. 42 | # 43 | # The yield code was neccessary b/c Ruby does not respect the use 44 | # of yield in a lambda (boo hiss). 45 | def with(_hash, &_yield) 46 | _hash = (_hash || {}).to_h #ash 47 | 48 | if _yield 49 | vars = eval('local_variables') 50 | vals = eval("[#{vars.join(',')}]") 51 | 52 | vars += _hash.keys 53 | vals += _hash.values 54 | 55 | code = <<-END 56 | def self.___with(#{vars.join(',')}) 57 | binding 58 | end 59 | method(:___with) 60 | END 61 | eval(code).call(*vals, &_yield) 62 | 63 | #_args = _hash.empty? ? '' : '|' + _hash.keys.join(',') + ',&y|' 64 | #lamb = eval("lambda{#{_args} binding}") 65 | #(class << self; self; end).send(:define_method, :__temp__, &lamb) 66 | #method(:__temp__).call(*_hash.values, &_yield) 67 | else 68 | _args = _hash.empty? ? '' : '|' + _hash.keys.join(',') + '|' 69 | eval("lambda{#{_args} binding}").call(*_hash.values) 70 | end 71 | end 72 | end 73 | 74 | class Object 75 | def to_binding 76 | binding 77 | end 78 | end 79 | 80 | class Struct 81 | def to_struct 82 | self 83 | end 84 | 85 | def to_h 86 | Hash[members.zip(values)] 87 | end unless method_defined?(:to_h) 88 | 89 | #def to_hash 90 | # Hash[members.zip(values)] 91 | #end 92 | end 93 | 94 | #class Array 95 | #def to_struct 96 | # h = to_h 97 | # Struct.new(h.keys) 98 | #end 99 | 100 | #def to_h 101 | # Hash[*self] 102 | #end unless method_defined?(:to_h) 103 | #end 104 | 105 | class OpenStruct 106 | def to_struct 107 | self 108 | end 109 | 110 | # 111 | def to_h #ash 112 | @table.dup 113 | end unless method_defined?(:to_h) 114 | end 115 | 116 | unless defined?(::BasicObject) 117 | require 'blankslate' 118 | ::BasicObject = ::BlankSlate 119 | end 120 | 121 | -------------------------------------------------------------------------------- /demo/02markup/01rdoc/rdoc/format_rdoc.rdoc: -------------------------------------------------------------------------------- 1 | == RDoc 2 | 3 | Lets say we have a RDoc document called 'test.rdoc' containing: 4 | 5 | = Example 6 | 7 | This is an example of RDoc rendering. 8 | 9 | We can convert the 'test.rdoc' document to html via +Malt.render+. 10 | 11 | Malt.render(:file=>'test.rdoc', :to=>:html) 12 | 13 | And the result should be: 14 | 15 |

Example

16 | 17 |

This is an example of RDoc rendering.

18 | 19 | (Note, newer versions of RDoc include `class="label-Example"`, while older 20 | versions do not.) 21 | 22 | Malt recognizes the type of file by the '.rdoc' extension and renders it using 23 | the default redering engine (in this case RDoc itself). By default the engine 24 | renders to HTML, so we did not need to specify the output `:to` option to 25 | the +render+ method. 26 | 27 | Malt.render(:file=>'test.rdoc') 28 | 29 | And again the result should be: 30 | 31 |

Example

32 | 33 |

This is an example of RDoc rendering.

34 | 35 | If we have a file that has a different extension, but is in fact an RDoc 36 | document, we can inform Malt. For instance, lets say we have an RDoc document 37 | called 'test.txt' containing: 38 | 39 | = Example 40 | 41 | This is an example of RDoc rendering. 42 | 43 | We can inform Malt as the actual type using the `:type` option. 44 | 45 | Malt.render(:file=>'test.txt', :type=>:rdoc) 46 | 47 | And here again the result will be: 48 | 49 |

Example

50 | 51 |

This is an example of RDoc rendering.

52 | 53 | 54 | === Malt.file 55 | 56 | Alternately we can use the object-oriented interface. Again, lets say we have 57 | an RDoc document called 'test.rdoc' containing: 58 | 59 | = Example 60 | 61 | This is an example of RDOC rendering. 62 | 63 | Then we can use the `Malt.file` method to instantiate an RDoc object. 64 | 65 | rdoc = Malt.file('test.rdoc') 66 | 67 | We will notice that the output is an instance of Malt::Formats::HTML. 68 | 69 | rdoc.class.assert == Malt::Format::RDoc 70 | 71 | While we could have used `Malt::Formats::RDoc.new` to create the object directly, 72 | Malt provides the #file, as well as #text, methods for convience. We can convert 73 | the rdoc to html with the #to_html method. 74 | 75 | html = rdoc.to_html 76 | 77 | Again notice that the output is an instance of Malt::Format::HTML. 78 | 79 | html.class.assert == Malt::Format::HTML 80 | 81 | And that by calling #to_s we can get the rendered HTML document. 82 | 83 | html.to_s.assert.include?('Example') 84 | 85 | We can convert rdoc documents to html very easily. 86 | 87 | rdoc = Malt.file('test.rdoc') 88 | 89 | html = rdoc.to_html 90 | 91 | First we will notice that the output is an instance of Malt::Format::HTML. 92 | 93 | html.class.assert == Malt::Format::HTML 94 | 95 | And that by calling #to_s we can get the rendered HTML document. 96 | 97 | html.to_s.assert.include?('Example') 98 | 99 | Or we can convert the RDoc document directly to HTML via the #html method. 100 | 101 | out = rdoc.html 102 | 103 | out.assert.include?('Example') 104 | 105 | -------------------------------------------------------------------------------- /demo/applique/consitent.rb: -------------------------------------------------------------------------------- 1 | When "an equivalent template for each engine" do 2 | require 'malt' 3 | require 'ostruct' 4 | 5 | @templates = {} 6 | @templates[:erb] = File.dirname(__FILE__) + "/../samples/consistent/sample.erb" 7 | @templates[:erubis] = File.dirname(__FILE__) + "/../samples/consistent/sample.erb" 8 | @templates[:liquid] = File.dirname(__FILE__) + "/../samples/consistent/sample.liquid" 9 | #@templates[:mustache] = File.dirname(__FILE__) + "/../samples/consistent/sample.mustache" 10 | @templates[:radius] = File.dirname(__FILE__) + "/../samples/consistent/sample.radius" 11 | @templates[:tenjin] = File.dirname(__FILE__) + "/../samples/consistent/sample.rbhtml" 12 | @templates[:string] = File.dirname(__FILE__) + "/../samples/consistent/sample.str" 13 | 14 | #template_types = %w{.erb .erubis} # .liquid .radius} #.mustache 15 | #@templates = {} 16 | #template_types.each do |ext| 17 | # @templates[ext] = File.dirname(__FILE__) + "/../samples/sample#{ext}" 18 | #end 19 | end 20 | 21 | When "an equivalent template for each html engine" do 22 | require 'malt' 23 | require 'ostruct' 24 | require 'nokogiri' 25 | 26 | @template_mode = :html 27 | 28 | @templates = {} 29 | @templates[:haml] = File.dirname(__FILE__) + "/../samples/consistent/sample.haml" 30 | @templates[:ragtag] = File.dirname(__FILE__) + "/../samples/consistent/sample.ragtag" 31 | @templates[:builder] = File.dirname(__FILE__) + "/../samples/consistent/sample.builder" 32 | @templates[:erector] = File.dirname(__FILE__) + "/../samples/consistent/sample.erector" 33 | @templates[:markaby] = File.dirname(__FILE__) + "/../samples/consistent/sample.markaby" 34 | @templates[:nokogiri] = File.dirname(__FILE__) + "/../samples/consistent/sample.nokogiri" 35 | end 36 | 37 | When /a (.*?) for a data source/ do |source_type| 38 | @source = lambda do 39 | case source_type 40 | when 'Binding' 41 | name = "Tom" 42 | state = "Maryland" 43 | binding 44 | when 'Object' 45 | SampleObject.new("Tom","Maryland") 46 | when 'Struct' 47 | Struct.new(:name, :state).new("Tom", "Maryland") 48 | when 'OpenStruct' 49 | OpenStruct.new(:name=>"Tom", :state=>"Maryland") 50 | when 'Hash' 51 | {:name=>"Tom", :state=>"Maryland"} 52 | end 53 | end 54 | end 55 | 56 | When "the equivalent template is rendered" do 57 | @results = {} 58 | @templates.each do |engine, file| 59 | file = Malt.file(file, :engine=>engine) #Tilt[ext].new(file) 60 | @results[engine] = file.render(@source.call){ 'yielded' }.to_s 61 | end 62 | end 63 | 64 | When "the result is the same for each" do 65 | case @template_mode 66 | when :html 67 | @results.each do |ea, a| 68 | @results.each do |eb, b| 69 | # $stdout.puts " #{ea} == #{eb}" 70 | a = a.gsub("\n",'').gsub(/\s\s+/,'') 71 | b = b.gsub("\n",'').gsub(/\s\s+/,'') 72 | na = Nokogiri.XML("#{a}").to_xml(:indent=>2) 73 | nb = Nokogiri.XML("#{b}").to_xml(:indent=>2) 74 | na.assert == nb 75 | end 76 | end 77 | else 78 | @results.each do |ea, a| 79 | @results.each do |eb, b| 80 | a.assert == b 81 | end 82 | end 83 | end 84 | end 85 | 86 | -------------------------------------------------------------------------------- /lib/malt.rb: -------------------------------------------------------------------------------- 1 | require 'malt/core_ext' 2 | require 'malt/version' 3 | require 'malt/kernel' 4 | require 'malt/machine' 5 | 6 | module Malt 7 | class << self 8 | include Malt::Kernel 9 | end 10 | 11 | # 12 | def self.machine 13 | @machine ||= Machine.new 14 | end 15 | 16 | # Render a file. 17 | def self.file(file, options={}) 18 | machine.file(file, options) 19 | end 20 | 21 | # Render text string. 22 | def self.text(text, options={}) 23 | machine.text(text, options) 24 | end 25 | 26 | # Render a URL. 27 | def self.open(url, options={}) 28 | machine.open(url, options) 29 | end 30 | 31 | # Render a document. 32 | # 33 | # param [Hash] params 34 | # Rendering parameters. 35 | # 36 | # option params [Symbol] :to 37 | # The format to which the file/text is to be rendered. 38 | # 39 | # option params [String] :file 40 | # The file to be rendered. If `:text` is not given, this file must exist on disk 41 | # so it can be read-in to fill in the `:text` option. If text is given, the file 42 | # is only used to help determine type and clarify error messages. 43 | # 44 | # option params [String] :text 45 | # The text to render. This option is required unless `:file` is given. 46 | # 47 | # option params [Symbol] :type 48 | # The format of the text. This will be determined automatically by the `:file` 49 | # option if it is given and has a recognized extension. Otherwise it needs 50 | # be explicitly provided. 51 | # 52 | # option params [Hash,Object,Binding,Array] :data 53 | # The data source used for evaluation. This can be a locals hash, a scope 54 | # object or binding, or an array of a scope object/binding and locals hash. 55 | # This option is split-up into :scope and :locals before passing on to 56 | # the redering engine. 57 | # 58 | # option params [Boolean] :pass 59 | # If not a supported type return text rather than raise an error. 60 | # 61 | def self.render(params, &body) 62 | machine.render(params, &body) 63 | end 64 | 65 | # Returns `true` if the extension given is a recognized format. 66 | def self.format?(ext) 67 | machine.format?(ext) 68 | end 69 | 70 | # Returns `true` if the extension given is renderable. 71 | def self.engine?(ext) 72 | machine.engine?(ext) 73 | end 74 | 75 | # 76 | def self.cli(*args) 77 | require 'optparse' 78 | itype, otype = nil, nil 79 | OptionParser.new{|o| 80 | o.on('-t TYPE', 'input type'){ |t| itype = t } 81 | o.on('-o TYPE', 'output type'){ |t| otype = t } 82 | o.on('--help', '-h' , 'display this help message'){ puts o; exit } 83 | }.parse! 84 | db, files = *args.partition{ |x| x.index('=') } 85 | db = db.inject({}){ |h,kv| k,v = kv.split('='); h[k] = v; h} 86 | files.each do |file| 87 | puts Malt.render(:file=>file, :type=>itype, :format=>otype) 88 | #file = itype ? Malt.file(file, :type=>itype) : Malt.file(file) 89 | #if otype 90 | # puts file.render(otype, db) 91 | #else 92 | # puts file.render(db) 93 | #end 94 | end 95 | end 96 | 97 | end 98 | 99 | require 'malt/engines' 100 | require 'malt/formats' 101 | -------------------------------------------------------------------------------- /lib/malt/engines/erb.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # ERB template implementation. 6 | # 7 | # http://www.ruby-doc.org/stdlib/libdoc/erb/rdoc/classes/ERB.html 8 | # 9 | # ERB templates accept two options. +safe+ sets the safe mode for 10 | # rendering the template and +trim+ is a weird string that controls 11 | # a few rendering options --it can be '%' and/or '>' or '<>'. 12 | class Erb < Abstract 13 | 14 | default :erb, :rhtml 15 | 16 | # Render ERB template. 17 | # 18 | # @param [Hash] params 19 | # 20 | # @option params [String] :text 21 | # Text of document. 22 | # 23 | # @option params [String] :file 24 | # The file name where text was read (or nil). 25 | # 26 | # @option params [Object,Binding] :scope 27 | # Scope from within which to render, serves as data source for 28 | # template interpolation. 29 | # 30 | # @option params [Object,Binding] :locals 31 | # Direct key/value data for template interpolation. 32 | # 33 | # @option params [Boolean] :safe 34 | # Run in separate thread. 35 | # 36 | # @option params [String] :trim 37 | # Trim mode, can be either of the following: 38 | # a) `%` enables Ruby code processing for lines beginning with `%`. 39 | # b) `<>` omit newline for lines starting with `<%` and ending in `%>`. 40 | # c) `>` omit newline for lines ending in `%>`. 41 | # 42 | # @option params [Boolean] :precompile (true) 43 | # Precompile the ERB template. Default is `true`. 44 | # Note that `yield` currently does work with non-compiled tempaltes. 45 | # 46 | # @return [String] Rendered output. 47 | # 48 | def render(params={}, &content) 49 | text, file, scope, locals = parameters(params, :text, :file, :scope, :locals) 50 | 51 | #if settings[:compile] == true 52 | #else 53 | bind = make_binding(scope, locals, &content) 54 | prepare_engine(params).result(bind) 55 | #end 56 | end 57 | 58 | # Returns instance of underlying ::ERB class. 59 | #def prepare_engine(params={}) 60 | # create_engine(params) 61 | #end 62 | 63 | # 64 | def create_engine(params={}) 65 | text = parameters(params, :text) 66 | 67 | opts = engine_options(params) 68 | safe = opts[:safe] 69 | trim = opts[:trim] 70 | 71 | cached(text,safe,trim) do 72 | ::ERB.new(text, safe, trim) 73 | end 74 | end 75 | 76 | private 77 | 78 | # Load ERB library if not already loaded. 79 | def require_engine 80 | return if defined? ::ERB 81 | require_library('erb') 82 | end 83 | 84 | # 85 | def engine_option_names 86 | [:safe, :trim] 87 | end 88 | 89 | #def engine_options(params) 90 | # opts = {} 91 | # opts[:safe] = params[:safe] || settings[:safe] 92 | # opts[:trim] = params[:trim] || settings[:trim] 93 | # opts 94 | #end 95 | 96 | # Compile ERB template into Ruby source code. 97 | # 98 | # @return [String] Ruby source code. 99 | #def compile(params={}) 100 | # if cache? 101 | # @source[params] ||= ( 102 | # intermediate(params).src 103 | # ) 104 | # else 105 | # intermediate(params).src 106 | # end 107 | #end 108 | 109 | end 110 | 111 | end 112 | -------------------------------------------------------------------------------- /MANIFEST: -------------------------------------------------------------------------------- 1 | #!mast -x Syckfile -x Profile .ruby bin features lib man spec test [A-Z]* 2 | .ruby 3 | bin/malt 4 | lib/malt/conversions.rb 5 | lib/malt/core_ext.rb 6 | lib/malt/engines/abstract.rb 7 | lib/malt/engines/bluecloth.rb 8 | lib/malt/engines/builder.rb 9 | lib/malt/engines/coffee.rb 10 | lib/malt/engines/creole.rb 11 | lib/malt/engines/erb.rb 12 | lib/malt/engines/erector.rb 13 | lib/malt/engines/erubis.rb 14 | lib/malt/engines/haml.rb 15 | lib/malt/engines/kramdown.rb 16 | lib/malt/engines/less.rb 17 | lib/malt/engines/liquid.rb 18 | lib/malt/engines/markaby.rb 19 | lib/malt/engines/maruku.rb 20 | lib/malt/engines/mustache.rb 21 | lib/malt/engines/nokogiri.rb 22 | lib/malt/engines/radius.rb 23 | lib/malt/engines/ragtag.rb 24 | lib/malt/engines/rdiscount.rb 25 | lib/malt/engines/rdoc.rb 26 | lib/malt/engines/redcarpet.rb 27 | lib/malt/engines/redcloth.rb 28 | lib/malt/engines/ruby.rb 29 | lib/malt/engines/sass.rb 30 | lib/malt/engines/string.rb 31 | lib/malt/engines/tenjin.rb 32 | lib/malt/engines/wikicloth.rb 33 | lib/malt/engines.rb 34 | lib/malt/formats/abstract.rb 35 | lib/malt/formats/abstract_template.rb 36 | lib/malt/formats/builder.rb 37 | lib/malt/formats/coffee.rb 38 | lib/malt/formats/css.rb 39 | lib/malt/formats/erb.rb 40 | lib/malt/formats/haml.rb 41 | lib/malt/formats/html.rb 42 | lib/malt/formats/javascript.rb 43 | lib/malt/formats/latex.rb 44 | lib/malt/formats/less.rb 45 | lib/malt/formats/liquid.rb 46 | lib/malt/formats/markdown.rb 47 | lib/malt/formats/mediawiki.rb 48 | lib/malt/formats/mustache.rb 49 | lib/malt/formats/pdf.rb 50 | lib/malt/formats/radius.rb 51 | lib/malt/formats/ragtag.rb 52 | lib/malt/formats/rbhtml.rb 53 | lib/malt/formats/rdoc.rb 54 | lib/malt/formats/rhtml.rb 55 | lib/malt/formats/ruby.rb 56 | lib/malt/formats/sass.rb 57 | lib/malt/formats/scss.rb 58 | lib/malt/formats/string.rb 59 | lib/malt/formats/tenjin.rb 60 | lib/malt/formats/text.rb 61 | lib/malt/formats/textile.rb 62 | lib/malt/formats/xml.rb 63 | lib/malt/formats/yaml.rb 64 | lib/malt/formats.rb 65 | lib/malt/kernel.rb 66 | lib/malt/machine.rb 67 | lib/malt/markup.rb 68 | lib/malt/template.rb 69 | lib/malt/tilted.rb 70 | lib/malt/version.rb 71 | lib/malt.rb 72 | lib/malt.yml 73 | test/benchmarks/malt_vs_tilt.rb 74 | test/fixtures/sample.erb 75 | test/fixtures/sample.rdoc 76 | test/helper.rb 77 | test/unit/engines/case_engine_bluecloth.rb 78 | test/unit/engines/case_engine_builder.rb 79 | test/unit/engines/case_engine_coffee.rb 80 | test/unit/engines/case_engine_creole.rb 81 | test/unit/engines/case_engine_erb.rb 82 | test/unit/engines/case_engine_erector.rb 83 | test/unit/engines/case_engine_erubis.rb 84 | test/unit/engines/case_engine_haml.rb 85 | test/unit/engines/case_engine_kramdown.rb 86 | test/unit/engines/case_engine_less.rb 87 | test/unit/engines/case_engine_liquid.rb 88 | test/unit/engines/case_engine_markaby.rb 89 | test/unit/engines/case_engine_maruku.rb 90 | test/unit/engines/case_engine_mustache.rb 91 | test/unit/engines/case_engine_nokogiri.rb 92 | test/unit/engines/case_engine_radius.rb 93 | test/unit/engines/case_engine_ragtag.rb 94 | test/unit/engines/case_engine_rdiscount.rb 95 | test/unit/engines/case_engine_rdoc.rb 96 | test/unit/engines/case_engine_redcarpet.rb 97 | test/unit/engines/case_engine_redcloth.rb 98 | test/unit/engines/case_engine_ruby.rb 99 | test/unit/engines/case_engine_sass.rb 100 | test/unit/engines/case_engine_string.rb 101 | test/unit/engines/case_engine_tenjin.rb 102 | test/unit/engines/case_engine_wikicloth.rb 103 | test/unit/machine.rb 104 | test/unit/malt.rb 105 | Reapfile 106 | HISTORY.rdoc 107 | README.rdoc 108 | Gemfile 109 | Assembly 110 | COPYING.rdoc 111 | -------------------------------------------------------------------------------- /lib/malt/engines/radius.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Radius Template 6 | # 7 | # http://github.com/jlong/radius/ 8 | # 9 | class Radius < Abstract 10 | 11 | default :radius 12 | 13 | # 14 | def render(params={}, &content) 15 | into, text = parameters(params, :to, :text) 16 | 17 | case into 18 | when :html, :xml, nil 19 | context = prepare_engine(params, &content) 20 | options = engine_options(params) 21 | 22 | parser = ::Radius::Parser.new(context, options) 23 | parser.parse(text) 24 | else 25 | super(params, &content) 26 | end 27 | end 28 | 29 | # 30 | def prepare_engine(params={}, &content) 31 | scope, locals = parameters(params, :scope, :locals) 32 | 33 | locals ||= {} 34 | 35 | # convert string keys to symbols w/o rewriting the hash 36 | string_keys = locals.keys.select{ |k| String === k } 37 | string_keys.each do |k| 38 | locals[k.to_sym] = locals[k] 39 | locals.delete(k) 40 | end 41 | 42 | make_context(scope, locals, &content) 43 | end 44 | 45 | private 46 | 47 | # Load Radius library if not already loaded. 48 | def require_engine 49 | return if defined? ::Radius 50 | require_library 'radius' 51 | end 52 | 53 | # Radius templates have a very special data source. 54 | def make_context(scope, locals, &content) 55 | case scope 56 | when nil 57 | context = make_context_from_hash(locals, &content) 58 | when Binding 59 | context = make_context_from_binding(scope, locals, &content) 60 | else 61 | context = make_context_from_object(scope, locals, &content) 62 | end 63 | context 64 | end 65 | 66 | # 67 | def make_context_from_binding(scope, locals, &content) 68 | context_class = Class.new(::Radius::Context) 69 | context_class.class_eval do 70 | define_method :tag_missing do |tag, attr| 71 | if locals.key?(tag.to_sym) 72 | locals[tag.to_sym] 73 | else 74 | scope.eval(tag) 75 | end 76 | end 77 | end 78 | context = context_class.new 79 | context.define_tag("content") do 80 | content ? content.call : '' 81 | end 82 | context 83 | end 84 | 85 | # 86 | def make_context_from_object(scope, locals, &content) 87 | context_class = Class.new(::Radius::Context) 88 | context_class.class_eval do 89 | define_method :tag_missing do |tag, attr| 90 | if locals.key?(tag.to_sym) 91 | locals[tag.to_sym] 92 | else 93 | scope.__send__(tag) # any way to support attr as args? 94 | end 95 | end 96 | end 97 | context = context_class.new 98 | context.define_tag("content") do 99 | content ? content.call : '' 100 | end 101 | context 102 | end 103 | 104 | # 105 | def make_context_from_hash(locals, &content) 106 | context_class = Class.new(::Radius::Context) 107 | context_class.class_eval do 108 | define_method :tag_missing do |tag, attr| 109 | locals[tag.to_sym] 110 | end 111 | end 112 | context = context_class.new 113 | context.define_tag("content") do 114 | content ? content.call : '' 115 | end 116 | context 117 | end 118 | 119 | # 120 | def engine_options(params) 121 | opts = {} 122 | opts[:tag_prefix] = params[:tag_prefix] || settings[:tag_prefix] #|| 'r' 123 | opts 124 | end 125 | 126 | end 127 | 128 | end 129 | -------------------------------------------------------------------------------- /lib/malt/engines/builder.rb: -------------------------------------------------------------------------------- 1 | require 'malt/engines/abstract' 2 | 3 | module Malt::Engine 4 | 5 | # Builder 6 | # 7 | # http://builder.rubyforge.org/ 8 | # 9 | class Builder < Abstract 10 | 11 | default :builder, :rbml 12 | 13 | # 14 | def render(params={}, &content) 15 | into = parameters(params, :to) || :html 16 | 17 | case into 18 | when :xml, :html, :xhtml 19 | prepare_engine(params, &content) #.target! 20 | else 21 | super(params, &content) 22 | end 23 | end 24 | 25 | #private 26 | 27 | # Prepare engine for rendering. 28 | def prepare_engine(params={}, &content) 29 | prefix = parameters(params, :prefix) 30 | 31 | if prefix 32 | prepare_engine_prefix(params, &content) 33 | else 34 | prepare_engine_scope(params, &content) 35 | end 36 | end 37 | 38 | # TODO: Can Builder be cached? 39 | 40 | # 41 | def create_engine(params={}) 42 | opts = engine_options(params) 43 | 44 | #cached(opts) do 45 | ::Builder::XmlMarkup.new(opts) 46 | #end 47 | end 48 | 49 | # 50 | def prepare_engine_prefix(params, &content) 51 | prefix, text, file, scope, locals = parameters(params, :prefix, :text, :file, :scope, :locals) 52 | 53 | bind = make_binding(scope, locals, &content) 54 | 55 | #scope, locals = split_data(data) 56 | 57 | #scope ||= Object.new 58 | #locals ||= {} 59 | 60 | engine = create_engine(params) 61 | 62 | code = %{ 63 | lambda do |#{prefix}| 64 | #{text} 65 | end 66 | } 67 | 68 | eval(code, bind, file || '(builder)').call(engine) 69 | end 70 | 71 | # TODO: woud rather set instance variable via #instance_variable_set 72 | # but it is not defined. 73 | 74 | # 75 | def prepare_engine_scope(params, &content) 76 | text, file, scope, locals = parameters(params, :text, :file, :scope, :locals) 77 | 78 | scope, locals = make_external(scope, locals, &content) 79 | 80 | engine = create_engine 81 | 82 | locals.each do |k,v| 83 | next if k.to_sym == :target 84 | engine.instance_eval("@#{k} = v") 85 | end 86 | 87 | unless scope.respond_to?(:to_struct) 88 | scope.instance_variables.each do |k| 89 | next if k == "@target" 90 | v = scope.instance_variable_get(k) 91 | engine.instance_eval("#{k} = v") 92 | end 93 | end 94 | 95 | engine.instance_eval(text, file || '(builder)') 96 | 97 | engine.target! 98 | end 99 | 100 | private 101 | 102 | # Load Builder library if not already loaded. 103 | def require_engine 104 | return if defined? ::Builder 105 | require_library 'builder' 106 | 107 | # Inexplicably Ruby 1.8 acts like the p method is present 108 | # if undef_method is not used, but acts like it isn't if 109 | # undef_method is used (raising an error). 110 | ::Builder::XmlBase.class_eval do 111 | undef_method :p rescue nil 112 | end 113 | end 114 | 115 | # 116 | # :target=>target_object: Object receiving the markup. target_object must 117 | # respond to the <<(a_string) operator and return itself. 118 | # The default target is a plain string target. 119 | # 120 | # :indent=>indentation: Number of spaces used for indentation. The default 121 | # is no indentation and no line breaks. 122 | # 123 | # :margin=>initial_indentation_level: Amount of initial indentation 124 | # (specified in levels, not spaces). 125 | # 126 | def engine_option_names 127 | [:target, :indent, :margin] 128 | end 129 | 130 | end 131 | 132 | end 133 | 134 | -------------------------------------------------------------------------------- /.index: -------------------------------------------------------------------------------- 1 | --- 2 | revision: 2013 3 | type: ruby 4 | sources: 5 | - INDEX.yml 6 | - Gemfile 7 | authors: 8 | - name: trans 9 | email: transfire@gmail.com 10 | organizations: 11 | - name: Rubyworks 12 | requirements: 13 | - version: '>= 0' 14 | name: blankslate 15 | - groups: 16 | - build 17 | - development 18 | version: '>= 0' 19 | name: detroit 20 | - groups: 21 | - test 22 | - development 23 | version: '>= 0' 24 | name: qed 25 | - groups: 26 | - test 27 | - development 28 | version: '>= 0' 29 | name: rubytest 30 | - groups: 31 | - test 32 | - development 33 | version: '>= 0' 34 | name: rubytest-cli 35 | - groups: 36 | - test 37 | - development 38 | version: '>= 0' 39 | name: lemon 40 | - groups: 41 | - test 42 | - development 43 | version: '>= 0' 44 | name: ae 45 | - groups: 46 | - test 47 | - development 48 | version: '>= 3' 49 | name: rdoc 50 | - groups: 51 | - test 52 | - development 53 | version: '>= 0' 54 | name: RedCloth 55 | - groups: 56 | - test 57 | - development 58 | version: '>= 0' 59 | name: bluecloth 60 | - groups: 61 | - test 62 | - development 63 | version: '>= 0' 64 | name: kramdown 65 | - groups: 66 | - test 67 | - development 68 | version: '>= 0' 69 | name: rdiscount 70 | - groups: 71 | - test 72 | - development 73 | version: '>= 0' 74 | name: haml 75 | - groups: 76 | - test 77 | - development 78 | version: '>= 0' 79 | name: sass 80 | - groups: 81 | - test 82 | - development 83 | version: '>= 0' 84 | name: less 85 | - groups: 86 | - test 87 | - development 88 | version: '>= 0' 89 | name: tenjin 90 | - groups: 91 | - test 92 | - development 93 | version: '>= 0' 94 | name: liquid 95 | - groups: 96 | - test 97 | - development 98 | version: '>= 0' 99 | name: erubis 100 | - groups: 101 | - test 102 | - development 103 | version: '>= 0' 104 | name: mustache 105 | - groups: 106 | - test 107 | - development 108 | version: '>= 0' 109 | name: markaby 110 | - groups: 111 | - test 112 | - development 113 | version: '>= 0' 114 | name: builder 115 | - groups: 116 | - test 117 | - development 118 | version: '>= 0' 119 | name: radius 120 | - groups: 121 | - test 122 | - development 123 | version: '>= 0' 124 | name: ragtag 125 | - groups: 126 | - test 127 | - development 128 | version: '>= 0' 129 | name: redcarpet 130 | - groups: 131 | - test 132 | - development 133 | version: '>= 0' 134 | name: wikicloth 135 | - groups: 136 | - test 137 | - development 138 | version: '>= 0' 139 | name: maruku 140 | - groups: 141 | - test 142 | - development 143 | version: '>= 0' 144 | name: creole 145 | - groups: 146 | - test 147 | - development 148 | version: '>= 0' 149 | name: erector 150 | - groups: 151 | - test 152 | - development 153 | version: '>= 0' 154 | name: coffee-script 155 | conflicts: [] 156 | alternatives: [] 157 | resources: 158 | - type: home 159 | uri: http://rubyworks.github.com/malt 160 | label: Homepage 161 | - type: code 162 | uri: http://github.com/rubyworks/malt 163 | label: Source Code 164 | - type: wiki 165 | uri: http://wiki.github.com/rubyworks/malt 166 | label: User Guide 167 | - type: docs 168 | uri: http://rubyworks.github.com/malt/docs/api 169 | label: Documentation 170 | - type: bugs 171 | uri: http://github.com/rubyworks/malt/issues 172 | label: Issue Tracker 173 | repositories: [] 174 | categories: [] 175 | copyrights: 176 | - holder: Rubyworks 177 | year: '2010' 178 | license: BSD-2-Clause 179 | customs: [] 180 | paths: 181 | lib: 182 | - lib 183 | name: malt 184 | title: Malt 185 | version: 0.4.1 186 | summary: Multi-template/multi-markup rendering engine. 187 | description: Malt provides a factory framework for rendering a variety of template 188 | and markup document formats. 189 | respositories: 190 | upstream: git@github.com:rubyworks/malt.git 191 | created: '2010-06-22' 192 | date: '2015-03-27' 193 | -------------------------------------------------------------------------------- /HISTORY.md: -------------------------------------------------------------------------------- 1 | # RELEASE HISTORY 2 | 3 | ## 0.4.0 | 2011-11-27 4 | 5 | This release of Malt is a major improvement over the previous release. 6 | Where as before not all formats behaved consistently --for instance, 7 | not all templating engines handled block yielding, this release has 8 | ensured consistent functionality across all engines. A couple of 9 | significant changes were made to do this. 10 | 11 | Most important to the end user, templating formats can no longer 12 | use `yield` to insert block content, but rather must use `content`. 13 | This was done to avoid unnecessary implementation complexity due 14 | to Ruby's limitation on the use of yield within Proc objects. 15 | The code is much cleaner and subsequently more robust thanks to 16 | this change. 17 | 18 | The builder-style engines (Builder, Markaby, Erector and Nokogiri) 19 | have all been united under a single `Builder` format class. The 20 | common extension for such files is `.rbml`. These engines have been 21 | tweaked to behave uniformly, supporting explicit and implicit 22 | evaluation modes and using instance variables and externalized 23 | scope. 24 | 25 | In addition to these changes, a few new formats/engines have been 26 | added, including Creole, Maruku, WikiCloth, CoffeeScript and 27 | Nokogiri Builder. 28 | 29 | Changes: 30 | 31 | * Add Creole, Maruku and WikiCloth markup engine/formats. 32 | * Add CoffeeScript transpiler engine/formats. 33 | * Add Nokogiri Builder format. 34 | * Support `scope and `locals` style data, as well as `data` option. 35 | * Unified builder engines under one .rbml/.builder format. 36 | * Use #content instead of #yield for block content! 37 | * Add :multi option for multi-format rendering. 38 | * Overhaul internal engine API, for better overall design. 39 | * Formats delegate to master Malt.render method. 40 | 41 | 42 | ## 0.3.0 | 2010-11-04 43 | 44 | New release adds a Malt::Machine class that encapsulates all 45 | Malt's class level functionality. This allow Malt to be 46 | be more finally controlled. For example an instance of 47 | Malt::Machine can be used to limit rendering to a select 48 | set of formats. 49 | 50 | Changes: 51 | 52 | * Add Machine class to encapsulate toplevel functions. 53 | * Add feature via Machine options to select available formats. 54 | * Add `#to_default` to for converting to default format. 55 | * Add `Malt.engine?` to test for supported engine types. 56 | * Rename `Malt.support?` to `Malt.format?`. 57 | * Rename `Malt.main` to `Malt.cli`. 58 | 59 | 60 | ## 0.2.0 | 2010-10-22 61 | 62 | Malt now support Erector, Markaby, Builder and Mustache templates. 63 | Erector, Markaby and Builder are Ruby-based formats --templates 64 | are simply Ruby code. This requires them to use instance variables 65 | in templates rather than local variables/methods. Something to keep 66 | in mind. 67 | 68 | Changes: 69 | 70 | * Add support for Erector templates. 71 | * Add support for Markaby templates. 72 | * Add support for Builder templates. 73 | * Add support for Mustache templates. 74 | * Add `:pass` option to render method. 75 | * Rename `:format` option to `:to` for render method. 76 | 77 | 78 | ## 0.1.1 | 2010-09-21 79 | 80 | This release simple fixes two bugs. One to handle variant arity 81 | in format class #render methods. Currently the interface can vary 82 | dependent on whether they accept interpolation data or not (this will 83 | probably be uniform in the future). The other fix raises an error if 84 | no engine exists to handle a given format. 85 | 86 | Changes: 87 | 88 | * Bug fix to raise error if format not handled by any engine. 89 | * Bug fix to underlying #render calls to handle variant arities. 90 | 91 | 92 | ## 0.1.0 | 2010-08-23 93 | 94 | This if the initial release of Malt. I have no doubt the code base 95 | still needs some fine-tuning --hence the 0.1 version, but I have put 96 | it to good use with the latest version of Brite, my static website 97 | generator, so I know that it is at least is a working state. 98 | 99 | Changes: 100 | 101 | * Initial release. 102 | 103 | --------------------------------------------------------------------------------