isaac-malline 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (73) hide show
  1. data/COPYING +674 -0
  2. data/COPYING.LESSER +165 -0
  3. data/History.txt +34 -0
  4. data/Manifest.txt +72 -0
  5. data/README +24 -0
  6. data/README.txt +33 -0
  7. data/Rakefile +74 -0
  8. data/bin/malline +20 -0
  9. data/github.rb +6 -0
  10. data/init.rb +2 -0
  11. data/lib/malline.rb +109 -0
  12. data/lib/malline/adapters/rails-2.0.rb +72 -0
  13. data/lib/malline/adapters/rails-2.1.rb +103 -0
  14. data/lib/malline/erb_out.rb +34 -0
  15. data/lib/malline/form_builder.rb +44 -0
  16. data/lib/malline/plugin.rb +34 -0
  17. data/lib/malline/plugins/xhtml.rb +77 -0
  18. data/lib/malline/rails.rb +46 -0
  19. data/lib/malline/template.rb +185 -0
  20. data/lib/malline/view_proxy.rb +87 -0
  21. data/lib/malline/view_wrapper.rb +95 -0
  22. data/malline.gemspec +34 -0
  23. data/scripts/html2mn.rb +93 -0
  24. data/test/examples/_action.mn +4 -0
  25. data/test/examples/_action.target +1 -0
  26. data/test/examples/_one.mn +1 -0
  27. data/test/examples/_one.target +1 -0
  28. data/test/examples/_partial.mn +2 -0
  29. data/test/examples/_partial.target +1 -0
  30. data/test/examples/_three.rhtml +2 -0
  31. data/test/examples/_two.mn +1 -0
  32. data/test/examples/_two.target +1 -0
  33. data/test/examples/capture.mn +13 -0
  34. data/test/examples/capture.target +1 -0
  35. data/test/examples/class.mn +6 -0
  36. data/test/examples/class.target +1 -0
  37. data/test/examples/escape.mn +4 -0
  38. data/test/examples/escape.target +1 -0
  39. data/test/examples/frontpage.mn +6 -0
  40. data/test/examples/frontpage.target +1 -0
  41. data/test/examples/hello_world.mn +2 -0
  42. data/test/examples/hello_world.target +1 -0
  43. data/test/examples/helper.mn +5 -0
  44. data/test/examples/helper.target +1 -0
  45. data/test/examples/helper2.mn +5 -0
  46. data/test/examples/helper2.target +1 -0
  47. data/test/examples/helper_shortcut.mn +5 -0
  48. data/test/examples/helper_shortcut.target +1 -0
  49. data/test/examples/id.mn +3 -0
  50. data/test/examples/id.target +1 -0
  51. data/test/examples/layout.mn +8 -0
  52. data/test/examples/layout.target +4 -0
  53. data/test/examples/lists.mn +13 -0
  54. data/test/examples/lists.target +1 -0
  55. data/test/examples/nested.mn +6 -0
  56. data/test/examples/nested.target +1 -0
  57. data/test/examples/options.mn +10 -0
  58. data/test/examples/options.target +1 -0
  59. data/test/examples/partials.mn +5 -0
  60. data/test/examples/partials.target +1 -0
  61. data/test/examples/self.mn +2 -0
  62. data/test/examples/self.target +1 -0
  63. data/test/examples/text.mn +4 -0
  64. data/test/examples/text.target +1 -0
  65. data/test/examples/whitespace.mn +9 -0
  66. data/test/examples/whitespace.target +1 -0
  67. data/test/examples/xhtml.mn +11 -0
  68. data/test/examples/xhtml.target +4 -0
  69. data/test/kernel.org.html +107 -0
  70. data/test/kernel.org.mn +657 -0
  71. data/test/malline_test.rb +171 -0
  72. data/test/malline_test_helpers.rb +82 -0
  73. metadata +136 -0
@@ -0,0 +1,72 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ ActionView::Base.register_template_handler 'rb', Malline::Base
19
+ module ActionView
20
+ # We need to redefine some ActionView::Base methods, Since Rails 2.0 doesn't
21
+ # offer any better way to do some things.
22
+ class Base
23
+ alias_method :orig_render_template, :render_template
24
+ # We want to save the name of the current file to @current_tpl_path,
25
+ # because then the error backtrace from Rails will include the
26
+ # name of the file. I didn't find better way to get this
27
+ def render_template template_extension, template, file_path = nil, *rest
28
+ @current_tpl_path = file_path
29
+ orig_render_template(template_extension, template, file_path, *rest)
30
+ end
31
+
32
+ alias_method :orig_compile_and_render_template, :compile_and_render_template
33
+ def compile_and_render_template handler, *rest
34
+ if self.respond_to? :is_malline?
35
+ old, @malline_is_active = is_malline?, false
36
+ output = orig_compile_and_render_template handler, *rest
37
+ @malline_is_active = old
38
+ output
39
+ else
40
+ @malline_is_active = false
41
+ orig_compile_and_render_template handler, *rest
42
+ end
43
+ end
44
+
45
+ alias_method :orig_delegate_render, :delegate_render
46
+ # Update the current file to malline and tell Malline to be deactivated
47
+ # if there is a non-Malline partial inside Malline template.
48
+ def delegate_render(handler, template, local_assigns)
49
+ old = is_malline?
50
+ tmp = if handler == Malline::Base
51
+ h = handler.new(self)
52
+ h.path = @current_tpl_path if @current_tpl_path
53
+ @malline_is_active = true
54
+ h.render(template, local_assigns)
55
+ else
56
+ @malline_is_active = false
57
+ orig_delegate_render(handler, template, local_assigns)
58
+ end
59
+ @malline_is_active = old
60
+ tmp
61
+ end
62
+ end
63
+ end
64
+
65
+ module Malline::ViewWrapper
66
+ # Activate Malline if we are not using ActionView::Base or if
67
+ # the current template is a Malline template
68
+ def is_malline?
69
+ @malline_is_active.nil? ? true : @malline_is_active
70
+ end
71
+ end
72
+
@@ -0,0 +1,103 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Malline
19
+ # Malline template handler for Rails 2.1
20
+ #
21
+ # We use Compilable-interface, even though Malline templates really doesn't
22
+ # compile into anything, but at least template files won't always be re-read
23
+ # from files. Builder templates (.builder|.rxml) also use this interface.
24
+ class RailsHandler < ActionView::TemplateHandler
25
+ include ActionView::TemplateHandlers::Compilable
26
+
27
+ # We have three lines framework code before real template code in
28
+ # 'compiled code'
29
+ def self.line_offset
30
+ 3
31
+ end
32
+
33
+ # Compiles the template, i.e. return a runnable ruby code that initializes
34
+ # a new Malline::Base objects and renders the template.
35
+ def compile template
36
+ path = template.path.gsub('\\', '\\\\\\').gsub("'", "\\\\'")
37
+ "__malline_handler = Malline::Base.new self
38
+ malline.path = '#{path}'
39
+ __malline_handler.render do
40
+ #{template.source}
41
+ end"
42
+ end
43
+
44
+ # Get the rendered fragment contents
45
+ def cache_fragment block, name = {}, options = nil
46
+ @view.fragment_for(block, name, options) do
47
+ eval("__malline_handler.rendered", block.binding)
48
+ end
49
+ end
50
+ end
51
+ end
52
+
53
+ module Malline::ViewWrapper
54
+ # Activate Malline if we are not using ActionView::Base or if
55
+ # the current template is a Malline template
56
+ def is_malline?
57
+ !(is_a?(ActionView::Base) && ActionView::Template.handler_class_for_extension(
58
+ current_render_extension) != Malline::RailsHandler)
59
+ end
60
+ end
61
+
62
+ # Rails has a bug with current_render_extension, lets fix it
63
+ if ActionView.const_defined?('Renderer')
64
+ module ActionView::Renderer
65
+ alias_method :orig_render, :render
66
+ def render *args
67
+ out = orig_render *args
68
+ @view.current_render_extension = @prev_extension
69
+ out
70
+ end
71
+
72
+ alias_method :orig_prepare!, :prepare!
73
+ def prepare! *args
74
+ @prev_extension = @view.current_render_extension
75
+ orig_prepare! *args
76
+ end
77
+ end
78
+ else
79
+ class ActionView::Template
80
+ alias_method :orig_render, :render
81
+ def render *args
82
+ out = orig_render *args
83
+ @view.current_render_extension = @prev_extension
84
+ out
85
+ end
86
+
87
+ alias_method :orig_prepare!, :prepare!
88
+ def prepare! *args
89
+ @prev_extension = @view.current_render_extension
90
+ orig_prepare! *args
91
+ end
92
+ end
93
+ class ActionView::PartialTemplate
94
+ alias_method :orig_render, :render
95
+ def render *args
96
+ out = orig_render *args
97
+ @view.current_render_extension = @prev_extension
98
+ out
99
+ end
100
+ end
101
+ end
102
+
103
+ ActionView::Template.register_template_handler 'rb', Malline::RailsHandler
@@ -0,0 +1,34 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Malline
19
+ # Since some parts of Rails use ERB directly instead of current template
20
+ # handler, we have to capture all that data.
21
+ #
22
+ # In practice the erb buffer object (named ActiveView::Base.erb_variable)
23
+ # is a string, where data is simply concatted.
24
+ class ErbOut
25
+ def initialize view
26
+ @view = view
27
+ end
28
+ # Redirect all data to view
29
+ def concat value
30
+ @view << value
31
+ end
32
+ alias_method :<<, :concat
33
+ end
34
+ end
@@ -0,0 +1,44 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Malline
19
+ # Capture form elements directly from FormBuilder, so that there is no
20
+ # need to specially render any elements.
21
+ # In other words, with our own FormBuilder-wrapper we can do this:
22
+ # form_for :comment, Comment.new, :url => edit_url do |f|
23
+ # f.text_field :name
24
+ # end
25
+ # instead of
26
+ # ..
27
+ # self << f.text_field(:name)
28
+ class FormBuilder
29
+ # Wrap the Rails FormBuilder in @builder
30
+ def initialize *args, &block
31
+ @view = eval('self', args.last)
32
+ @builder = ::ActionView::Helpers::FormBuilder.new(*args, &block)
33
+ end
34
+ # Render every f.foo -method to view, unless we aren't using
35
+ # Malline template now
36
+ def method_missing *args, &block
37
+ if @view && @view.is_malline?
38
+ @view << @builder.send(*args, &block)
39
+ else
40
+ @builder.send(*args, &block)
41
+ end
42
+ end
43
+ end
44
+ end
@@ -0,0 +1,34 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # Malline very incomplete Plugin interface.
19
+ class Malline::Plugin
20
+ # Install a new plugin: Malline::WhatEverPlugin.install view
21
+ def self.install view
22
+ return if view.malline.plugins.include? self
23
+ self.do_install view
24
+ view.malline.plugins << self
25
+ end
26
+
27
+ protected
28
+ def self.do_install view
29
+ raise NotImplementedError.new
30
+ end
31
+ def self.do_uninstall view
32
+ raise NotImplementedError.new("#{self} cannot be uninstalled")
33
+ end
34
+ end
@@ -0,0 +1,77 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ # Quite stupid plugin for XHTML, we should be able to do this only with a DTD
19
+ # or similar.
20
+ #
21
+ # Defines all usable tags, list which one can be self-close, defines a short
22
+ # cut tag *xhtml*. Also makes sure that there is some necessary elements in
23
+ # the document.
24
+ class Malline::XHTML < Malline::Plugin
25
+ CUSTOM_TAGS = %w{head title meta}
26
+
27
+ # grep ELEMENT xhtml1-transitional.dtd | cut -d' ' -f2 | tr "\n" " "
28
+ XHTML_TAGS = %w{html head title base meta link style script noscript iframe
29
+ noframes body div p h1 h2 h3 h4 h5 h6 ul ol menu dir li dl dt dd address
30
+ hr pre blockquote center ins del a span bdo br em strong dfn code samp
31
+ kbd var cite abbr acronym q sub sup tt i b big small u s strike basefont
32
+ font object param applet img map area form label input select optgroup
33
+ option textarea fieldset legend button isindex table caption thead tfoot
34
+ tbody colgroup col tr th td} - CUSTOM_TAGS
35
+
36
+ # grep 'ELEMENT.*EMPTY' xhtml1-transitional.dtd | cut -d' ' -f2 | tr "\n" " "
37
+ SHORT_TAG_EXCLUDES = XHTML_TAGS + CUSTOM_TAGS - %w{base meta link hr br
38
+ basefont param img area input isindex col}
39
+
40
+ module Tags
41
+ def xhtml *args, &block
42
+ attrs = { :xmlns => 'http://www.w3.org/1999/xhtml', 'xml:lang' => malline.options[:lang] }
43
+ attrs.merge!(args.pop) if args.last.is_a?(Hash)
44
+
45
+ self << "<?xml version=\"1.0\" encoding=\"#{malline.options[:encoding] || 'UTF-8'}\"?>\n"
46
+ self << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 #{malline.options[:xhtml_dtd] || 'Transitional'}//EN\"\n"
47
+ self << " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-#{(malline.options[:xhtml_dtd] || 'Transitional').downcase}.dtd\">\n"
48
+
49
+ tag! 'html', args.join(''), attrs, &block
50
+ end
51
+
52
+ def title *args, &block
53
+ @__xhtml_title = true
54
+ tag! 'title', *args, &block
55
+ end
56
+
57
+ def meta *args, &block
58
+ @__xhtml_meta = true
59
+ tag! 'meta', *args, &block
60
+ end
61
+
62
+ def head *args, &block
63
+ @__xhtml_title = false
64
+ proxy = tag! 'head', *args, &block
65
+ proxy.__yld { title } unless @__xhtml_title
66
+ proxy.__yld do
67
+ meta :content => "text/html; charset=#{malline.options[:encoding] || 'UTF-8'}", 'http-equiv' => 'Content-Type'
68
+ end unless @__xhtml_meta
69
+ end
70
+ end
71
+
72
+ def self.do_install view
73
+ view.malline.definetags! XHTML_TAGS
74
+ view.malline.short_tag_excludes += SHORT_TAG_EXCLUDES
75
+ view.extend Tags
76
+ end
77
+ end
@@ -0,0 +1,46 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ require 'malline' unless Kernel.const_defined?('Malline')
19
+ require 'malline/form_builder.rb'
20
+
21
+ if Rails::VERSION::STRING <= "2.0.z"
22
+ require 'malline/adapters/rails-2.0'
23
+ else
24
+ require 'malline/adapters/rails-2.1'
25
+ end
26
+
27
+ # Activate our FormBuilder wrapper, so we can use forms more easily
28
+ ActionView::Base.default_form_builder = Malline::FormBuilder
29
+
30
+ module Malline::ViewWrapper
31
+ @@malline_methods << 'cache'
32
+
33
+ # Rails caching
34
+ def _malline_cache name = {}, options = {}, &block
35
+ return block.call unless @controller.perform_caching
36
+ cache = @controller.read_fragment(name, options)
37
+
38
+ unless cache
39
+ cache = _malline_capture { block.call }
40
+ @controller.write_fragment(name, cache, options)
41
+ end
42
+ @malline.add_unescaped_text cache
43
+ end
44
+ end
45
+
46
+
@@ -0,0 +1,185 @@
1
+ # Copyright © 2007,2008 Riku Palomäki
2
+ #
3
+ # This file is part of Malline.
4
+ #
5
+ # Malline is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU Lesser General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Malline is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU Lesser General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU Lesser General Public License
16
+ # along with Malline. If not, see <http://www.gnu.org/licenses/>.
17
+
18
+ module Malline
19
+ # This is the class that really evaluates the template and is accessible
20
+ # from the view by "malline", for example:
21
+ # malline.path = 'File name'
22
+ class Template
23
+ # Current options (like @@options in Base)
24
+ attr_accessor :options
25
+ # List of every tag that doesn't support self-closing syntax
26
+ attr_accessor :short_tag_excludes
27
+ # Current state of :whitespace-modifier (bool)
28
+ attr_accessor :whitespace
29
+ # Current file name
30
+ attr_accessor :path
31
+ # Every overriden (in definetags!) helper method (:name => method)
32
+ attr_accessor :helper_overrides
33
+ # Every available tag, excluding the specific methods (:name => bool)
34
+ attr_accessor :tags
35
+ # Render result of the last #render
36
+ attr_reader :rendered
37
+ # List all installed plugins
38
+ attr_accessor :plugins
39
+
40
+ def initialize view, opts
41
+ @view = view
42
+ @whitespace = false
43
+ @path = 'Malline template'
44
+ @options = opts
45
+ @short_tag_excludes = []
46
+ @helper_overrides = {}
47
+ @tags = {}
48
+ @plugins = []
49
+ @inited = false
50
+ end
51
+
52
+ # Install plugins and do every thing that cannot be done in initialize
53
+ # Plugin install will use @view.malline, that will create a duplicate
54
+ # Template instance, if it's called from initialize.
55
+ def init
56
+ return if @inited
57
+ XHTML.install @view if @options[:xhtml]
58
+ end
59
+
60
+ # Stolen from ERB, © 1999-2000,2002,2003 Masatoshi SEKI
61
+ def self.html_escape(s)
62
+ s.to_s.gsub(/&/, "&amp;").gsub(/\"/, "&quot;").gsub(/>/, "&gt;").gsub(/</, "&lt;")
63
+ end
64
+ # Stolen from ERB, © 1999-2000,2002,2003 Masatoshi SEKI
65
+ def self.url_encode(s)
66
+ s.to_s.gsub(/[^a-zA-Z0-9_\-.]/n){ sprintf("%%%02X", $&.unpack("C")[0]) }
67
+ end
68
+
69
+ # Changes dom to active @dom, and executes tpl / block
70
+ def execute dom, tpl = nil, &block
71
+ tmp = @dom
72
+ @dom = dom
73
+ if block_given?
74
+ @view.instance_eval &block
75
+ else
76
+ @view.instance_eval tpl, @path
77
+ end
78
+ @dom = tmp
79
+ end
80
+
81
+ # Add escaped string to @dom
82
+ def add_text *values
83
+ @dom << ' ' if @whitespace
84
+ @dom << Template.html_escape(values.join(' '))
85
+ end
86
+
87
+ # Add unescaped string to @dom
88
+ def add_unescaped_text value
89
+ @dom << ' ' if @whitespace
90
+ @dom << value.to_s unless value.nil?
91
+ end
92
+
93
+ # Call a helper (a method defined outside malline whose
94
+ # output is stored to @dom)
95
+ def helper helper, *args, &block
96
+ helper = helper.to_sym
97
+ tmp = if h = @helper_overrides[helper]
98
+ h.call *args, &block
99
+ else
100
+ @view.send helper, *args, &block
101
+ end
102
+ @dom << ' ' if @whitespace
103
+ @dom << tmp.to_s
104
+ tmp
105
+ end
106
+
107
+ # Add a tag to @dom
108
+ def tag s, *args, &block
109
+ tag = { :name => s.to_s, :attrs => {}, :children => [] }
110
+
111
+ tag[:whitespace] = true if @whitespace
112
+ whitespace = @whitespace
113
+ @whitespace = true if args.delete(:whitespace)
114
+
115
+ if args.last.is_a?(Hash)
116
+ tag[:attrs].merge!(args.pop)
117
+ end
118
+
119
+ txt = args.flatten.join('')
120
+ tag[:children] << Template.html_escape(txt) unless txt.empty?
121
+
122
+ @dom << tag
123
+ execute tag[:children], &block if block_given?
124
+ @whitespace = whitespace
125
+
126
+ ViewProxy.new self, tag
127
+ end
128
+
129
+ # Render the XML tree at dom or @dom
130
+ def render dom = nil
131
+ @rendered = (dom || @dom).inject('') do |out, tag|
132
+ if tag.is_a?(String)
133
+ out << tag
134
+ else
135
+ out << ' ' if tag[:whitespace]
136
+ out << "<#{tag[:name]}"
137
+ out << tag[:attrs].inject(''){|s, a| s + " #{a.first}=\"#{Template.html_escape(a.last)}\""}
138
+
139
+ if tag[:children].empty?
140
+ if @short_tag_excludes.include?(tag[:name])
141
+ out << "></#{tag[:name]}>"
142
+ else
143
+ out << '/>'
144
+ end
145
+ else
146
+ out << '>'
147
+ out << render(tag[:children])
148
+ out << "</#{tag[:name]}>"
149
+ end
150
+ end
151
+ end
152
+ end
153
+
154
+ # Execute and render a text or block
155
+ def run tpl = nil, &block
156
+ init
157
+ tmp = []
158
+ execute tmp, tpl, &block
159
+ render tmp
160
+ end
161
+
162
+ # Define tags as a methods, overriding all same named methods
163
+ def definetags! *tags
164
+ tags.flatten.each do |tag|
165
+ tag = tag.to_sym
166
+ @helper_overrides[tag] = @view.method(tag) if @view.respond_to?(tag)
167
+ define_tag! tag
168
+ end
169
+ end
170
+
171
+ # Marking tags as usable, but not overriding anything
172
+ def definetags *tags
173
+ tags.flatten.each{|tag| @tags[tag] = true }
174
+ end
175
+
176
+ # Define a method tag
177
+ def define_tag! tag
178
+ eval %{
179
+ def @view.#{tag}(*args, &block)
180
+ tag!('#{tag}', *args, &block)
181
+ end
182
+ }
183
+ end
184
+ end
185
+ end