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,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