', '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 | [](https://rubygems.org/gems/malt)
4 | [](http://travis-ci.org/rubyworks/malt)
5 | [](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 |
--------------------------------------------------------------------------------