isaac-malline 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/History.txt +34 -0
- data/Manifest.txt +72 -0
- data/README +24 -0
- data/README.txt +33 -0
- data/Rakefile +74 -0
- data/bin/malline +20 -0
- data/github.rb +6 -0
- data/init.rb +2 -0
- data/lib/malline.rb +109 -0
- data/lib/malline/adapters/rails-2.0.rb +72 -0
- data/lib/malline/adapters/rails-2.1.rb +103 -0
- data/lib/malline/erb_out.rb +34 -0
- data/lib/malline/form_builder.rb +44 -0
- data/lib/malline/plugin.rb +34 -0
- data/lib/malline/plugins/xhtml.rb +77 -0
- data/lib/malline/rails.rb +46 -0
- data/lib/malline/template.rb +185 -0
- data/lib/malline/view_proxy.rb +87 -0
- data/lib/malline/view_wrapper.rb +95 -0
- data/malline.gemspec +34 -0
- data/scripts/html2mn.rb +93 -0
- data/test/examples/_action.mn +4 -0
- data/test/examples/_action.target +1 -0
- data/test/examples/_one.mn +1 -0
- data/test/examples/_one.target +1 -0
- data/test/examples/_partial.mn +2 -0
- data/test/examples/_partial.target +1 -0
- data/test/examples/_three.rhtml +2 -0
- data/test/examples/_two.mn +1 -0
- data/test/examples/_two.target +1 -0
- data/test/examples/capture.mn +13 -0
- data/test/examples/capture.target +1 -0
- data/test/examples/class.mn +6 -0
- data/test/examples/class.target +1 -0
- data/test/examples/escape.mn +4 -0
- data/test/examples/escape.target +1 -0
- data/test/examples/frontpage.mn +6 -0
- data/test/examples/frontpage.target +1 -0
- data/test/examples/hello_world.mn +2 -0
- data/test/examples/hello_world.target +1 -0
- data/test/examples/helper.mn +5 -0
- data/test/examples/helper.target +1 -0
- data/test/examples/helper2.mn +5 -0
- data/test/examples/helper2.target +1 -0
- data/test/examples/helper_shortcut.mn +5 -0
- data/test/examples/helper_shortcut.target +1 -0
- data/test/examples/id.mn +3 -0
- data/test/examples/id.target +1 -0
- data/test/examples/layout.mn +8 -0
- data/test/examples/layout.target +4 -0
- data/test/examples/lists.mn +13 -0
- data/test/examples/lists.target +1 -0
- data/test/examples/nested.mn +6 -0
- data/test/examples/nested.target +1 -0
- data/test/examples/options.mn +10 -0
- data/test/examples/options.target +1 -0
- data/test/examples/partials.mn +5 -0
- data/test/examples/partials.target +1 -0
- data/test/examples/self.mn +2 -0
- data/test/examples/self.target +1 -0
- data/test/examples/text.mn +4 -0
- data/test/examples/text.target +1 -0
- data/test/examples/whitespace.mn +9 -0
- data/test/examples/whitespace.target +1 -0
- data/test/examples/xhtml.mn +11 -0
- data/test/examples/xhtml.target +4 -0
- data/test/kernel.org.html +107 -0
- data/test/kernel.org.mn +657 -0
- data/test/malline_test.rb +171 -0
- data/test/malline_test_helpers.rb +82 -0
- 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(/&/, "&").gsub(/\"/, """).gsub(/>/, ">").gsub(/</, "<")
|
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
|