isaac-malline 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,87 @@
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
+ # Every tag returns a ViewProxy object that binds the tag to the template.
20
+ # ViewProxy also chains the process by returning itself.
21
+ #
22
+ # This Proxy object then makes possible the attribute syntax:
23
+ # div.foo.bar! { stuff }
24
+ #
25
+ # div returns new ViewProxy instance, so div.foo actually calls
26
+ # ViewProxy#foo, which is then generated to class="foo" -attribute to the
27
+ # original tag div. div.foo returns the same ViewProxy, and foo.bar! calls
28
+ # ViewProxy#bar!, which is interpreted as a id="bar" -attribute.
29
+ #
30
+ # Finally the given block { stuff } is evaluated the same way than it would
31
+ # be evaluated without the ViewProxy:
32
+ # div { stuff }
33
+ class ViewProxy
34
+ def initialize template, tag
35
+ @tpl = template
36
+ @tag = tag
37
+ end
38
+
39
+ # Allows to add new content to already closed tag, for example:
40
+ # t = div do
41
+ # _'text'
42
+ # end
43
+ # t.__yld :whitespace { stuff }
44
+ #
45
+ # Intended for internal use only
46
+ def __yld *args, &block
47
+ # div :title => 'data'
48
+ if args.last.is_a?(Hash)
49
+ @tag[:attrs].merge!(args.pop)
50
+ end
51
+
52
+ # Modifiers
53
+ whitespace = @tpl.whitespace
54
+ @tpl.whitespace = true if args.delete(:whitespace)
55
+
56
+ # Rest is just content separated by a space
57
+ txt = args.flatten.join ' '
58
+ @tag[:children] << txt unless txt.empty?
59
+
60
+ # Block
61
+ @tpl.execute @tag[:children], &block if block_given?
62
+
63
+ # Restore modifiers
64
+ @tpl.whitespace = whitespace
65
+
66
+ # Chain the calls, for example: div.foo.bar!.yeah.boring
67
+ self
68
+ end
69
+
70
+ # Capture attribute definitions, special modifiers and blocks
71
+ def method_missing s, *args, &block
72
+ # div.id!
73
+ if /^(.*)!$/ =~ s.to_s
74
+ @tag[:attrs]['id'] = $1
75
+ elsif s
76
+ # div.class
77
+ if @tag[:attrs]['class']
78
+ @tag[:attrs]['class'] << " #{s}"
79
+ else
80
+ @tag[:attrs]['class'] = s.to_s
81
+ end
82
+ end
83
+
84
+ __yld *args, &block
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,95 @@
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
+ # ViewWrapper is extended into used view object, like ActiveView::Base.
20
+ # Every method in ViewWrapper will pollute the original namespace.
21
+ module ViewWrapper
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 capture _ tag! << txt!}
25
+
26
+ # Initialize @@malline_methods
27
+ def init_malline_methods
28
+ @malline_methods_inited = true
29
+ @@malline_methods.each do |m|
30
+ mf = m.gsub('<', 'lt')
31
+ eval %{def #{m}(*x, &b) is_malline? ? _malline_#{mf}(*x, &b) : super; end}
32
+ end
33
+ end
34
+
35
+ # Returns a current Template instance, makes a new if called first time
36
+ # Can also be used to set options to Template by giving them as hash opts:
37
+ # malline :whitespace => true
38
+ def malline opts = nil
39
+ if @malline
40
+ @malline.options.merge!(opts) if opts.is_a?(Hash)
41
+ else
42
+ @malline = Template.new(self, opts || {})
43
+ end
44
+ init_malline_methods unless @malline_methods_inited
45
+ @malline
46
+ end
47
+
48
+ # erbout emulator
49
+ def _malline__erbout
50
+ @_erbout ||= ErbOut.new(self)
51
+ end
52
+
53
+ # capture and return the output of the block
54
+ def _malline_capture &block
55
+ @malline.run &block
56
+ end
57
+
58
+ # _'escaped text'
59
+ def _malline__ *args
60
+ @malline.add_text(*args)
61
+ end
62
+ alias_method :_malline_txt!, :_malline__
63
+
64
+ # self << "<unescaped text>"
65
+ def _malline_ltlt *args
66
+ @malline.add_unescaped_text *args
67
+ end
68
+
69
+ # Define a new tag of call a helper (if _prefixed)
70
+ def method_missing s, *args, &block
71
+ return super unless is_malline?
72
+ if @malline.tags[s]
73
+ @malline.tag s, *args, &block
74
+ else
75
+ helper = ((s.to_s[0] == ?_) ? s.to_s[1..-1] : s).to_sym
76
+ if respond_to?(helper)
77
+ @malline.helper(helper, *args, &block)
78
+ else
79
+ return super if @malline.options[:strict]
80
+ _malline_tag! s, *args, &block
81
+ end
82
+ end
83
+ end
84
+
85
+ # Define a new tag
86
+ def _malline_tag! *args, &block
87
+ @malline.tag *args, &block
88
+ end
89
+
90
+ # Are we in a Malline template
91
+ def is_malline?
92
+ true
93
+ end
94
+ end
95
+ end
@@ -0,0 +1,34 @@
1
+ Gem::Specification.new do |s|
2
+ s.name = %q{malline}
3
+ s.version = "1.1.0"
4
+
5
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
6
+ s.authors = ["Riku Palom\303\244ki"]
7
+ s.date = %q{2008-09-06}
8
+ s.default_executable = %q{malline}
9
+ s.description = %q{Malline is a full-featured template system designed to be a replacement for ERB views in Rails or any other framework. It also includes standalone bin/malline to compile Malline templates to XML in commandline. All Malline templates are pure Ruby, see http://www.malline.org/ for more info. See documentation on http://www.malline.org/ Copyright © 2007,2008 Riku Palomäki, riku@palomaki.fi Malline is released under GNU Lesser General Public License. Example Rails template file images.html.mn: xhtml do _render :partial => 'head' body do div.images! "There are some images:" do images.each do |im| a(:href => img_path(im)) { img :src => im.url } span.caption im.caption end _"No more images" end div.footer! { _render :partial => 'footer' } end end}
10
+ s.email = ["riku@palomaki.fi"]
11
+ s.executables = ["malline"]
12
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
13
+ s.files = ["COPYING", "COPYING.LESSER", "History.txt", "Manifest.txt", "README", "README.txt", "Rakefile", "bin/malline", "github.rb", "init.rb", "lib/malline.rb", "lib/malline/adapters/rails-2.0.rb", "lib/malline/adapters/rails-2.1.rb", "lib/malline/erb_out.rb", "lib/malline/form_builder.rb", "lib/malline/plugin.rb", "lib/malline/plugins/xhtml.rb", "lib/malline/rails.rb", "lib/malline/template.rb", "lib/malline/view_proxy.rb", "lib/malline/view_wrapper.rb", "malline.gemspec", "scripts/html2mn.rb", "test/examples/_action.mn", "test/examples/_action.target", "test/examples/_one.mn", "test/examples/_one.target", "test/examples/_partial.mn", "test/examples/_partial.target", "test/examples/_three.rhtml", "test/examples/_two.mn", "test/examples/_two.target", "test/examples/capture.mn", "test/examples/capture.target", "test/examples/class.mn", "test/examples/class.target", "test/examples/escape.mn", "test/examples/escape.target", "test/examples/frontpage.mn", "test/examples/frontpage.target", "test/examples/hello_world.mn", "test/examples/hello_world.target", "test/examples/helper.mn", "test/examples/helper.target", "test/examples/helper2.mn", "test/examples/helper2.target", "test/examples/helper_shortcut.mn", "test/examples/helper_shortcut.target", "test/examples/id.mn", "test/examples/id.target", "test/examples/layout.mn", "test/examples/layout.target", "test/examples/lists.mn", "test/examples/lists.target", "test/examples/nested.mn", "test/examples/nested.target", "test/examples/options.mn", "test/examples/options.target", "test/examples/partials.mn", "test/examples/partials.target", "test/examples/self.mn", "test/examples/self.target", "test/examples/text.mn", "test/examples/text.target", "test/examples/whitespace.mn", "test/examples/whitespace.target", "test/examples/xhtml.mn", "test/examples/xhtml.target", "test/kernel.org.html", "test/kernel.org.mn", "test/malline_test.rb", "test/malline_test_helpers.rb"]
14
+ s.has_rdoc = true
15
+ s.homepage = %q{http://www.malline.org/}
16
+ s.rdoc_options = ["--main", "README.txt"]
17
+ s.require_paths = ["lib"]
18
+ s.rubyforge_project = %q{malline}
19
+ s.rubygems_version = %q{1.2.0}
20
+ s.summary = %q{Malline is a full-featured template system designed to be a replacement for ERB views in Rails or any other framework}
21
+
22
+ if s.respond_to? :specification_version then
23
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
24
+ s.specification_version = 2
25
+
26
+ if current_version >= 3 then
27
+ s.add_runtime_dependency(%q<hoe>, [">= 1.5.3"])
28
+ else
29
+ s.add_dependency(%q<hoe>, [">= 1.5.3"])
30
+ end
31
+ else
32
+ s.add_dependency(%q<hoe>, [">= 1.5.3"])
33
+ end
34
+ end
@@ -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('&amp;', '&').gsub('&quot;', '"').gsub('&gt;', '>').gsub('&lt;', '<')
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,4 @@
1
+ @title = 'Data'
2
+ ul.data! do
3
+ 3.times {|i| li "Data #{i}" }
4
+ end
@@ -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,2 @@
1
+ # This is just a stupid partial
2
+ div 'I always thought something was fundamentally wrong with the universe.'
@@ -0,0 +1 @@
1
+ <div>I always thought something was fundamentally wrong with the universe.</div>
@@ -0,0 +1,2 @@
1
+ Blop, <%= 'this is rhtml'.upcase %>.
2
+ <%= render :partial => 'examples/two' %>
@@ -0,0 +1 @@
1
+ img :src => image_path('second')
@@ -0,0 +1 @@
1
+ <img src="/images/img"/>
@@ -0,0 +1,13 @@
1
+ div do
2
+ @foo = capture do
3
+ div do
4
+ img :src => '/images/image.png'
5
+ br
6
+ span.caption 'Taken at the location of the event'
7
+ end
8
+ end
9
+
10
+ h4 'Captured'
11
+ self << @foo
12
+ _'EOF'
13
+ end
@@ -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,6 @@
1
+ # These two things are the same
2
+ div :class => 'page'
3
+ div.page
4
+
5
+ # You can even give more than one class
6
+ div.foo.bar.many
@@ -0,0 +1 @@
1
+ <div class="page"></div><div class="page"></div><div class="foo bar many"></div>
@@ -0,0 +1,4 @@
1
+ p 'Do you know, that 2 < 5?', :title => '2 < 5'
2
+ p do
3
+ _'Me & Myself & Malline'
4
+ end
@@ -0,0 +1 @@
1
+ <p title="2 &lt; 5">Do you know, that 2 &lt; 5?</p><p>Me &amp; Myself &amp; Malline</p>
@@ -0,0 +1,6 @@
1
+ div.page do
2
+ h1 'Header one'
3
+ ul.list! do
4
+ li { a 'Link to somewhere', :href => '/foo' }
5
+ end
6
+ end
@@ -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,2 @@
1
+ # Lets say hello to the world
2
+ div 'Hello world', :title => 'Hello'
@@ -0,0 +1 @@
1
+ <div title="Hello">Hello world</div>
@@ -0,0 +1,5 @@
1
+ def rot13 name
2
+ '<div>' + (name.tr "A-Za-z", "N-ZA-Mn-za-m") + '</div>'
3
+ end
4
+
5
+ self << rot13('secret stuff')
@@ -0,0 +1 @@
1
+ <div>frperg fghss</div>
@@ -0,0 +1,5 @@
1
+ def rot13 name
2
+ div name.tr("A-Za-z", "N-ZA-Mn-za-m")
3
+ end
4
+
5
+ rot13('frperg fghss')
@@ -0,0 +1 @@
1
+ <div>secret stuff</div>
@@ -0,0 +1,5 @@
1
+ p do
2
+ # These two do exactly the same
3
+ self << link_to('Frontpage', '/')
4
+ _link_to('Frontpage', '/')
5
+ end
@@ -0,0 +1 @@
1
+ <p>linklink</p>
@@ -0,0 +1,3 @@
1
+ # id:s are given by shouting loud enough
2
+ div.page!
3
+ div.foo.page!.bar
@@ -0,0 +1 @@
1
+ <div id="page"></div><div class="foo bar" id="page"></div>
@@ -0,0 +1,8 @@
1
+ xhtml do
2
+ head do
3
+ title @title
4
+ end
5
+ body do
6
+ self << @content_for_layout
7
+ end
8
+ end