malline 1.0.2
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.
- data/COPYING +674 -0
- data/COPYING.LESSER +165 -0
- data/README +24 -0
- data/bin/malline +20 -0
- data/lib/malline.rb +108 -0
- data/lib/malline/erb_out.rb +29 -0
- data/lib/malline/form_builder.rb +33 -0
- data/lib/malline/rails.rb +45 -0
- data/lib/malline/template.rb +124 -0
- data/lib/malline/view_proxy.rb +54 -0
- data/lib/malline/view_wrapper.rb +91 -0
- data/lib/malline/view_xhtml.rb +71 -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/fragment_cache.mn +10 -0
- data/test/examples/fragment_cache.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 +192 -0
- data/test/malline_test_helpers.rb +57 -0
- metadata +110 -0
@@ -0,0 +1,54 @@
|
|
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
|
+
class ViewProxy
|
20
|
+
def initialize template, tag
|
21
|
+
@tpl = template
|
22
|
+
@tag = tag
|
23
|
+
end
|
24
|
+
|
25
|
+
def __yld &block
|
26
|
+
@tpl.execute @tag[:children], &block
|
27
|
+
end
|
28
|
+
|
29
|
+
def method_missing(s, *args, &block)
|
30
|
+
if args.last.is_a?(Hash)
|
31
|
+
@tag[:attrs].merge!(args.pop)
|
32
|
+
end
|
33
|
+
|
34
|
+
if /\!$/ =~ s.to_s
|
35
|
+
@tag[:attrs]['id'] = s.to_s.chomp('!')
|
36
|
+
else
|
37
|
+
if @tag[:attrs]['class']
|
38
|
+
@tag[:attrs]['class'] << " #{s}"
|
39
|
+
else
|
40
|
+
@tag[:attrs]['class'] = s.to_s
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
whitespace = @tpl.whitespace
|
45
|
+
@tpl.whitespace = true if args.delete(:whitespace)
|
46
|
+
txt = args.flatten.join('')
|
47
|
+
@tag[:children] << txt unless txt.empty?
|
48
|
+
|
49
|
+
@tpl.execute @tag[:children], &block if block_given?
|
50
|
+
@tpl.whitespace = whitespace
|
51
|
+
self
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,91 @@
|
|
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
|
+
module ViewWrapper
|
20
|
+
attr_accessor :malline_is_active
|
21
|
+
|
22
|
+
# List of all methods that may override some custom view methods
|
23
|
+
# If is_malline?, then their _malline_ -prefix versions are called
|
24
|
+
@@malline_methods = %w{_erbout cache capture _ tag! << txt!}
|
25
|
+
|
26
|
+
def init_malline_methods
|
27
|
+
@malline_methods_inited = true
|
28
|
+
@@malline_methods.each do |m|
|
29
|
+
mf = m.gsub('<', 'lt')
|
30
|
+
eval %{def #{m}(*x, &b) is_malline? ? _malline_#{mf}(*x, &b) : super; end}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def malline opts = nil
|
35
|
+
if @malline
|
36
|
+
@malline.options.merge!(opts) if opts.is_a?(Hash)
|
37
|
+
else
|
38
|
+
@malline = Template.new(self, opts)
|
39
|
+
end
|
40
|
+
init_malline_methods unless @malline_methods_inited
|
41
|
+
@malline
|
42
|
+
end
|
43
|
+
|
44
|
+
def _malline__erbout
|
45
|
+
@_erbout ||= ErbOut.new(self)
|
46
|
+
end
|
47
|
+
|
48
|
+
def _malline_cache name = {}, options = {}, &block
|
49
|
+
return block.call unless @controller.perform_caching
|
50
|
+
cache = @controller.read_fragment(name, options)
|
51
|
+
|
52
|
+
unless cache
|
53
|
+
cache = _malline_capture { block.call }
|
54
|
+
@controller.write_fragment(name, cache, options)
|
55
|
+
end
|
56
|
+
@malline.add_unescaped_text cache
|
57
|
+
end
|
58
|
+
|
59
|
+
def _malline_capture &block
|
60
|
+
@malline.run &block
|
61
|
+
end
|
62
|
+
|
63
|
+
def _malline__ *args
|
64
|
+
@malline.add_text(*args)
|
65
|
+
end
|
66
|
+
alias_method :_malline_txt!, :_malline__
|
67
|
+
|
68
|
+
def _malline_ltlt *args
|
69
|
+
@malline.add_unescaped_text *args
|
70
|
+
end
|
71
|
+
|
72
|
+
def method_missing s, *args, &block
|
73
|
+
return super unless is_malline?
|
74
|
+
helper = (s.to_s[0].chr == '_') ? s.to_s[1..255].to_sym : s.to_sym
|
75
|
+
if respond_to?(helper)
|
76
|
+
@malline.helper(helper, *args, &block)
|
77
|
+
else
|
78
|
+
return super if @malline.options[:strict]
|
79
|
+
_malline_tag! s, *args, &block
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def _malline_tag! *args, &block
|
84
|
+
@malline.tag *args, &block
|
85
|
+
end
|
86
|
+
|
87
|
+
def is_malline?
|
88
|
+
@malline_is_active
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
@@ -0,0 +1,71 @@
|
|
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::XHTML
|
19
|
+
CUSTOM_TAGS = %w{head title meta}
|
20
|
+
|
21
|
+
# grep ELEMENT xhtml1-transitional.dtd | cut -d' ' -f2 | tr "\n" " "
|
22
|
+
XHTML_TAGS = %w{html head title base meta link style script noscript iframe
|
23
|
+
noframes body div p h1 h2 h3 h4 h5 h6 ul ol menu dir li dl dt dd address
|
24
|
+
hr pre blockquote center ins del a span bdo br em strong dfn code samp
|
25
|
+
kbd var cite abbr acronym q sub sup tt i b big small u s strike basefont
|
26
|
+
font object param applet img map area form label input select optgroup
|
27
|
+
option textarea fieldset legend button isindex table caption thead tfoot
|
28
|
+
tbody colgroup col tr th td} - CUSTOM_TAGS
|
29
|
+
|
30
|
+
# grep 'ELEMENT.*EMPTY' xhtml1-transitional.dtd | cut -d' ' -f2 | tr "\n" " "
|
31
|
+
SHORT_TAG_EXCLUDES = XHTML_TAGS + CUSTOM_TAGS - %w{base meta link hr br
|
32
|
+
basefont param img area input isindex col}
|
33
|
+
|
34
|
+
module Tags
|
35
|
+
def xhtml *args, &block
|
36
|
+
attrs = { :xmlns => 'http://www.w3.org/1999/xhtml', 'xml:lang' => malline.options[:lang] }
|
37
|
+
attrs.merge!(args.pop) if args.last.is_a?(Hash)
|
38
|
+
|
39
|
+
self << "<?xml version=\"1.0\" encoding=\"#{malline.options[:encoding] || 'UTF-8'}\"?>\n"
|
40
|
+
self << "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 #{malline.options[:xhtml_dtd] || 'Transitional'}//EN\"\n"
|
41
|
+
self << " \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-#{(malline.options[:xhtml_dtd] || 'Transitional').downcase}.dtd\">\n"
|
42
|
+
|
43
|
+
tag! 'html', args.join(''), attrs, &block
|
44
|
+
end
|
45
|
+
|
46
|
+
def title *args, &block
|
47
|
+
@__xhtml_title = true
|
48
|
+
tag! 'title', *args, &block
|
49
|
+
end
|
50
|
+
|
51
|
+
def meta *args, &block
|
52
|
+
@__xhtml_meta = true
|
53
|
+
tag! 'meta', *args, &block
|
54
|
+
end
|
55
|
+
|
56
|
+
def head *args, &block
|
57
|
+
@__xhtml_title = false
|
58
|
+
proxy = tag! 'head', *args, &block
|
59
|
+
proxy.__yld { title } unless @__xhtml_title
|
60
|
+
proxy.__yld do
|
61
|
+
meta :content => "text/html; charset=#{malline.options[:encoding] || 'UTF-8'}", 'http-equiv' => 'Content-Type'
|
62
|
+
end unless @__xhtml_meta
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def self.load_plugin base
|
67
|
+
base.definetags *XHTML_TAGS
|
68
|
+
base.view.malline.short_tag_excludes += SHORT_TAG_EXCLUDES
|
69
|
+
base.view.extend Tags
|
70
|
+
end
|
71
|
+
end
|
data/scripts/html2mn.rb
ADDED
@@ -0,0 +1,93 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# Copyright © 2007,2008 Riku Palomäki
|
3
|
+
#
|
4
|
+
# This file is part of Malline.
|
5
|
+
#
|
6
|
+
# Malline is free software: you can redistribute it and/or modify
|
7
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
8
|
+
# the Free Software Foundation, either version 3 of the License, or
|
9
|
+
# (at your option) any later version.
|
10
|
+
#
|
11
|
+
# Malline is distributed in the hope that it will be useful,
|
12
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
13
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
14
|
+
# GNU Lesser General Public License for more details.
|
15
|
+
#
|
16
|
+
# You should have received a copy of the GNU Lesser General Public License
|
17
|
+
# along with Malline. If not, see <http://www.gnu.org/licenses/>.
|
18
|
+
|
19
|
+
require "rexml/document"
|
20
|
+
include REXML
|
21
|
+
|
22
|
+
def html_unescape str
|
23
|
+
str.to_s.gsub('&', '&').gsub('"', '"').gsub('>', '>').gsub('<', '<')
|
24
|
+
end
|
25
|
+
|
26
|
+
def esc str
|
27
|
+
if str =~ /["#]/ || !(str =~ /'/)
|
28
|
+
"'"+(str.split("'").join("\\'"))+"'"
|
29
|
+
else
|
30
|
+
"\"#{str}\""
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
def attributes element
|
35
|
+
element.attributes.keys.collect {|k| "#{esc k} => #{esc html_unescape(element.attributes[k])}" }.join(', ')
|
36
|
+
end
|
37
|
+
|
38
|
+
def txtize txt
|
39
|
+
#txt.gsub(/(\s)\s*$/, '\1').gsub(/^(\s)\s*/, '\1')
|
40
|
+
txt.gsub(/\s*$/, '').gsub(/^\s*/, '')
|
41
|
+
end
|
42
|
+
|
43
|
+
def convert element, prefix=''
|
44
|
+
valid_method = /^[A-Za-z][\w_]*$/
|
45
|
+
output = ''
|
46
|
+
if element.is_a?(Array)
|
47
|
+
element.each {|e| output << convert(e) }
|
48
|
+
elsif element.is_a?(Element)
|
49
|
+
output << prefix << element.name
|
50
|
+
attrs = []
|
51
|
+
element.attributes['class'].to_s.split.uniq.each do |cl|
|
52
|
+
if valid_method =~ cl
|
53
|
+
output << ".#{cl}"
|
54
|
+
else
|
55
|
+
attrs << cl
|
56
|
+
end
|
57
|
+
end
|
58
|
+
element.attributes.delete('class')
|
59
|
+
element.attributes['class'] = attrs.join(' ') unless attrs.empty?
|
60
|
+
if element.attributes['id'].to_s =~ valid_method
|
61
|
+
output << ".#{element.attributes['id']}!"
|
62
|
+
element.attributes.delete('id')
|
63
|
+
end
|
64
|
+
txt = ''
|
65
|
+
children = element.children
|
66
|
+
unless children.empty?
|
67
|
+
if children.first.is_a?(Text)
|
68
|
+
txt = txtize children.shift.to_s
|
69
|
+
output << " #{esc html_unescape(txt)}" unless txt.empty?
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
output << (txt.empty? ? ' ' : ', ') << attributes(element) if element.has_attributes?
|
74
|
+
unless children.empty?
|
75
|
+
output << " do\n"
|
76
|
+
children.each {|e| output << convert(e, prefix + "\t") }
|
77
|
+
output << prefix << "end"
|
78
|
+
end
|
79
|
+
output << "\n"
|
80
|
+
elsif element.is_a?(Text)
|
81
|
+
txt = txtize(element.to_s)
|
82
|
+
output << prefix << "txt! #{esc html_unescape(txt)}\n" unless txt.empty?
|
83
|
+
end
|
84
|
+
output
|
85
|
+
end
|
86
|
+
|
87
|
+
input = File.open(ARGV.shift, 'r') rescue $stdin
|
88
|
+
output = File.open(ARGV.shift, 'w') rescue $stdout
|
89
|
+
|
90
|
+
doc = Document.new input
|
91
|
+
|
92
|
+
|
93
|
+
output.puts convert(doc.children)
|
@@ -0,0 +1 @@
|
|
1
|
+
<ul id="data"><li>Data 0</li><li>Data 1</li><li>Data 2</li></ul>
|
@@ -0,0 +1 @@
|
|
1
|
+
span.one 'This is the first'
|
@@ -0,0 +1 @@
|
|
1
|
+
<span class="one">This is the first</span>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div>I always thought something was fundamentally wrong with the universe.</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
img :src => image_path('second')
|
@@ -0,0 +1 @@
|
|
1
|
+
<img src="/images/img"/>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div><h4>Captured</h4><div><img src="/images/image.png"/><br/><span class="caption">Taken at the location of the event</span></div>EOF</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div class="page"></div><div class="page"></div><div class="foo bar many"></div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<p title="2 < 5">Do you know, that 2 < 5?</p><p>Me & Myself & Malline</p>
|
@@ -0,0 +1,10 @@
|
|
1
|
+
div do
|
2
|
+
cache "stuff" do
|
3
|
+
# This block is evaluated only if no cache with keyword stuff is found
|
4
|
+
# After evaluation the block is saved to cache
|
5
|
+
# If caching is not enabled, the cache block is transparent
|
6
|
+
h4 'Some partial stuff'
|
7
|
+
_render :partial => 'examples/partial'
|
8
|
+
end
|
9
|
+
_'dynamic content'
|
10
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
<div><h4>Some partial stuff</h4><div>I always thought something was fundamentally wrong with the universe.</div>dynamic content</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div class="page"><h1>Header one</h1><ul id="list"><li><a href="/foo">Link to somewhere</a></li></ul></div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div title="Hello">Hello world</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div>frperg fghss</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<div>secret stuff</div>
|
@@ -0,0 +1 @@
|
|
1
|
+
<p>linklink</p>
|
data/test/examples/id.mn
ADDED