undies 2.2.1 → 3.0.0.rc.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/ARCH.md +116 -0
  2. data/Gemfile +3 -0
  3. data/Gemfile.lock +20 -4
  4. data/LICENSE +22 -0
  5. data/README.md +343 -0
  6. data/Rakefile +25 -17
  7. data/bench/bench_runner.rb +132 -12
  8. data/bench/large.html.erb +9 -13
  9. data/bench/large.html.haml +11 -0
  10. data/bench/large.html.rb +8 -12
  11. data/bench/profiler +1 -1
  12. data/bench/profiler_runner.rb +2 -5
  13. data/bench/small.html.erb +9 -13
  14. data/bench/small.html.haml +11 -0
  15. data/bench/small.html.rb +8 -12
  16. data/bench/verylarge.html.erb +9 -13
  17. data/bench/verylarge.html.haml +11 -0
  18. data/bench/verylarge.html.rb +8 -12
  19. data/lib/undies/api.rb +163 -0
  20. data/lib/undies/element.rb +160 -80
  21. data/lib/undies/element_node.rb +116 -0
  22. data/lib/undies/io.rb +43 -0
  23. data/lib/undies/root_node.rb +62 -0
  24. data/lib/undies/source.rb +78 -2
  25. data/lib/undies/template.rb +17 -131
  26. data/lib/undies/version.rb +1 -1
  27. data/lib/undies.rb +3 -2
  28. data/test/element_closed_test.rb +69 -0
  29. data/test/element_node_test.rb +274 -0
  30. data/test/element_open_test.rb +101 -0
  31. data/test/element_test.rb +23 -196
  32. data/test/fixtures/write_thing.rb +4 -4
  33. data/test/helper.rb +84 -0
  34. data/test/io_test.rb +104 -0
  35. data/test/named_source_test.rb +1 -1
  36. data/test/raw_test.rb +25 -0
  37. data/test/root_node_test.rb +108 -0
  38. data/test/source_stack_test.rb +1 -1
  39. data/test/template_builder_render_test.rb +4 -9
  40. data/test/template_source_render_test.rb +16 -20
  41. data/test/template_test.rb +87 -80
  42. data/test/templates/content.html.rb +1 -1
  43. data/test/templates/test.html.rb +1 -1
  44. data/undies.gemspec +1 -0
  45. metadata +52 -23
  46. data/README.rdoc +0 -203
  47. data/lib/undies/named_source.rb +0 -54
  48. data/lib/undies/node.rb +0 -87
  49. data/lib/undies/node_stack.rb +0 -111
  50. data/lib/undies/output.rb +0 -31
  51. data/lib/undies/source_stack.rb +0 -22
  52. data/test/node_stack_test.rb +0 -109
  53. data/test/node_test.rb +0 -91
  54. data/test/output_test.rb +0 -69
@@ -1,8 +1,10 @@
1
1
  require 'whysoslow'
2
- require 'stringio'
3
2
 
4
3
  require 'erb'
5
4
  require 'erubis'
5
+ require 'haml'
6
+ require 'markaby'
7
+ require 'erector'
6
8
  require 'undies'
7
9
 
8
10
  class UndiesBenchResults
@@ -37,18 +39,130 @@ end
37
39
  class UndiesResults < UndiesBenchResults
38
40
 
39
41
  def initialize(size='large')
40
- @outstream = StringIO.new(@out = "")
41
42
  super(:undies, '.rb', size, Proc.new do
42
43
  Undies::Template.new(
43
44
  Undies::Source.new(self.file),
44
45
  {},
45
- Undies::Output.new(@outstream, :pp => 2)
46
+ Undies::IO.new(@out = "", :pp => 2)
46
47
  )
47
48
  end)
48
49
  end
49
50
 
50
51
  end
51
52
 
53
+ class MarkabyResults < UndiesBenchResults
54
+
55
+ BUILDS = {}
56
+
57
+ BUILDS['small'] = Proc.new do
58
+ head {}
59
+ body do
60
+ 100.times do |n|
61
+ span "Yo", :id => "cool-#{n}!"
62
+ p "Yo", :class => "awesome"
63
+
64
+ br
65
+
66
+ div :class => 'last' do
67
+ span "Hi " + em('there') + '!!'
68
+ end
69
+ end
70
+ end
71
+ end
72
+
73
+ BUILDS['large'] = Proc.new do
74
+ head {}
75
+ body do
76
+ 1000.times do |n|
77
+ span "Yo", :id => "cool-#{n}!"
78
+ p "Yo", :class => "awesome"
79
+
80
+ br
81
+
82
+ div :class => 'last' do
83
+ span "Hi " + em('there') + '!!'
84
+ end
85
+ end
86
+ end
87
+ end
88
+
89
+ BUILDS['verylarge'] = Proc.new do
90
+ head {}
91
+ body do
92
+ 10000.times do |n|
93
+ span "Yo", :id => "cool-#{n}!"
94
+ p "Yo", :class => "awesome"
95
+
96
+ br
97
+
98
+ div :class => 'last' do
99
+ span "Hi " + em('there') + '!!'
100
+ end
101
+ end
102
+ end
103
+ end
104
+
105
+ def initialize(size='large')
106
+ @out = ""
107
+ super(:markaby, '.mab', size, Proc.new do
108
+ mab = Markaby::Builder.new
109
+ mab.html &BUILDS[size.to_s]
110
+ @out = mab.to_s
111
+ end)
112
+ end
113
+
114
+ end
115
+
116
+ class ErectorResults < UndiesBenchResults
117
+
118
+ class Build < Erector::Widget
119
+ def content
120
+ head {}
121
+ body do
122
+ @num.times do |n|
123
+ span "Yo", :id => "cool-#{n}!"
124
+ p "Yo", :class => "awesome"
125
+
126
+ br
127
+
128
+ div :class => 'last' do
129
+ span do
130
+ text "Hi "
131
+ em "there"
132
+ text "!!"
133
+ end
134
+ end
135
+ end
136
+ end
137
+ end
138
+ end
139
+
140
+ BUILDS = {}
141
+
142
+ BUILDS['small'] = Build.new(:num => 100)
143
+ BUILDS['large'] = Build.new(:num => 1000)
144
+ BUILDS['verylarge'] = Build.new(:num => 10000)
145
+
146
+ def initialize(size='large')
147
+ @out = ""
148
+ super(:erector, '.erc', size, Proc.new do
149
+ @out = BUILDS[size.to_s].to_html(:prettyprint => true)
150
+ end)
151
+ end
152
+
153
+ end
154
+
155
+ class HamlResults < UndiesBenchResults
156
+
157
+ def initialize(size='large')
158
+ @out = ""
159
+ super(:haml, '.haml', size, Proc.new do
160
+ @out = ::Haml::Engine.new(File.read(self.file)).to_html
161
+ end)
162
+ end
163
+
164
+ end
165
+
52
166
  class ErbResults < UndiesBenchResults
53
167
 
54
168
  def initialize(size='large')
@@ -75,23 +189,29 @@ end
75
189
 
76
190
  class UndiesBenchRunner
77
191
 
78
- SIZES = {
79
- # :small => "~20 nodes",
80
- # :large => "~2000 nodes",
81
- :verylarge => "~20000 nodes"
82
- }
192
+ SIZES = [
193
+ # [:small , "~500 nodes"],
194
+ # [:large , "~5000 nodes"],
195
+ [:verylarge, "~50000 nodes"]
196
+ ]
83
197
 
84
198
 
85
199
  def initialize
86
200
  puts "Benchmark Results:"
87
201
  puts
88
- SIZES.each do |size, desc|
89
- ErbResults.new(size).run
202
+ SIZES.each do |size_desc|
203
+ UndiesResults.new(size_desc.first).run
90
204
  puts
91
- ErubisResults.new(size).run
205
+ ErectorResults.new(size_desc.first).run
92
206
  puts
93
- UndiesResults.new(size).run
207
+ MarkabyResults.new(size_desc.first).run
94
208
  puts
209
+ # HamlResults.new(size_desc.first).run
210
+ # puts
211
+ # ErbResults.new(size_desc.first).run
212
+ # puts
213
+ # ErubisResults.new(size_desc.first).run
214
+ # puts
95
215
  end
96
216
  puts
97
217
  end
data/bench/large.html.erb CHANGED
@@ -1,19 +1,15 @@
1
1
  <html>
2
2
  <head></head>
3
3
  <body>
4
- <% 100.times do %>
5
- <% 5.times do %>
6
- Yo
7
- <% end %>
8
- <% 5.times do %>
9
- YoYo
10
- <% end %>
11
- <% 5.times do %>
12
- <br />
13
- <% end %>
14
- <% 5.times do %>
15
- <div>Hi</div>
16
- <% end %>
4
+ <% 1000.times do %>
5
+ <span id="cool">Yo</span>
6
+ <p class="awesome">Yo</p>
7
+
8
+ <br />
9
+
10
+ <div class="last">
11
+ <span>Hi</span>
12
+ </div>
17
13
  <% end %>
18
14
  </body>
19
15
  </html>
@@ -0,0 +1,11 @@
1
+ %html
2
+ %head
3
+ %body
4
+ - 1000.times do
5
+ %span#cool "Yo"
6
+ %p.awesome "Yo"
7
+
8
+ %br
9
+
10
+ %div.last
11
+ %span "Hi "
data/bench/large.html.rb CHANGED
@@ -1,18 +1,14 @@
1
1
  _html {
2
2
  _head {}
3
3
  _body {
4
- 100.times do
5
- 5.times do
6
- _ "Yo"
7
- end
8
- 5.times do
9
- __ "YoYo"
10
- end
11
- 5.times do
12
- _br
13
- end
14
- 5.times do
15
- _div { _ "Hi" }
4
+ 1000.times do |n|
5
+ _span "Yo", :id => "cool-#{n}!"
6
+ _p "Yo", :class => "awesome"
7
+
8
+ _br
9
+
10
+ _div :class => 'last' do
11
+ _span "Hi ", em('there'), '!!'
16
12
  end
17
13
  end
18
14
  }
data/bench/profiler CHANGED
@@ -3,4 +3,4 @@
3
3
  require 'bench/profiler_runner'
4
4
 
5
5
  runner = UndiesProfilerRunner.new(ARGV[0] || 'large')
6
- runner.print_flat(STDOUT, :min_percent => 1)
6
+ runner.print_flat(STDOUT)
@@ -1,4 +1,3 @@
1
- require 'stringio'
2
1
  require 'ruby-prof'
3
2
  require 'undies'
4
3
  require 'bench/procs'
@@ -11,12 +10,10 @@ class UndiesProfilerRunner
11
10
  file = "bench/#{size || 'large'}.html.rb"
12
11
  @source = Undies::Source.new(File.expand_path(file))
13
12
  @data = {}
14
- @output = Undies::Output.new(StringIO.new(@out = ""))
13
+ @io = Undies::IO.new(@out = "")
15
14
 
16
15
  @result = RubyProf.profile do
17
- 10.times do
18
- Undies::Template.new(@source, @data, @output)
19
- end
16
+ Undies::Template.new(@source, @data, @io)
20
17
  end
21
18
 
22
19
  end
data/bench/small.html.erb CHANGED
@@ -1,19 +1,15 @@
1
1
  <html>
2
2
  <head></head>
3
3
  <body>
4
- <% 1.times do %>
5
- <% 5.times do %>
6
- Yo
7
- <% end %>
8
- <% 5.times do %>
9
- YoYo
10
- <% end %>
11
- <% 5.times do %>
12
- <br />
13
- <% end %>
14
- <% 5.times do %>
15
- <div>Hi</div>
16
- <% end %>
4
+ <% 100.times do %>
5
+ <span id="cool">Yo</span>
6
+ <p class="awesome">Yo</p>
7
+
8
+ <br />
9
+
10
+ <div class="last">
11
+ <span>Hi</span>
12
+ </div>
17
13
  <% end %>
18
14
  </body>
19
15
  </html>
@@ -0,0 +1,11 @@
1
+ %html
2
+ %head
3
+ %body
4
+ - 100.times do
5
+ %span#cool "Yo"
6
+ %p.awesome "Yo"
7
+
8
+ %br
9
+
10
+ %div.last
11
+ %span "Hi "
data/bench/small.html.rb CHANGED
@@ -1,18 +1,14 @@
1
1
  _html {
2
2
  _head {}
3
3
  _body {
4
- 1.times do
5
- 5.times do
6
- _ "Yo"
7
- end
8
- 5.times do
9
- __ "YoYo"
10
- end
11
- 5.times do
12
- _br
13
- end
14
- 5.times do
15
- _div { _ "Hi" }
4
+ 100.times do |n|
5
+ _span "Yo", :id => "cool-#{n}!"
6
+ _p "Yo", :class => "awesome"
7
+
8
+ _br
9
+
10
+ _div :class => 'last' do
11
+ _span "Hi ", em('there'), '!!'
16
12
  end
17
13
  end
18
14
  }
@@ -1,19 +1,15 @@
1
1
  <html>
2
2
  <head></head>
3
3
  <body>
4
- <% 1000.times do %>
5
- <% 5.times do %>
6
- Yo
7
- <% end %>
8
- <% 5.times do %>
9
- YoYo
10
- <% end %>
11
- <% 5.times do %>
12
- <br />
13
- <% end %>
14
- <% 5.times do %>
15
- <div>Hi</div>
16
- <% end %>
4
+ <% 10000.times do %>
5
+ <span id="cool">Yo</span>
6
+ <p class="awesome">Yo</p>
7
+
8
+ <br />
9
+
10
+ <div class="last">
11
+ <span>Hi</span>
12
+ </div>
17
13
  <% end %>
18
14
  </body>
19
15
  </html>
@@ -0,0 +1,11 @@
1
+ %html
2
+ %head
3
+ %body
4
+ - 10000.times do
5
+ %span#cool "Yo"
6
+ %p.awesome "Yo"
7
+
8
+ %br
9
+
10
+ %div.last
11
+ %span "Hi "
@@ -1,18 +1,14 @@
1
1
  _html {
2
2
  _head {}
3
3
  _body {
4
- 1000.times do
5
- 5.times do
6
- _ "Yo"
7
- end
8
- 5.times do
9
- __ "YoYo"
10
- end
11
- 5.times do
12
- _br
13
- end
14
- 5.times do
15
- _div { _ "Hi" }
4
+ 10000.times do |n|
5
+ _span "Yo", :id => "cool-#{n}!"
6
+ _p "Yo", :class => "awesome"
7
+
8
+ _br
9
+
10
+ _div :class => 'last' do
11
+ _span "Hi ", em('there'), '!!'
16
12
  end
17
13
  end
18
14
  }
data/lib/undies/api.rb ADDED
@@ -0,0 +1,163 @@
1
+ require 'undies/element_node'
2
+ require 'undies/element'
3
+
4
+ module Undies
5
+
6
+ module API
7
+
8
+ # HTML tag helpers
9
+
10
+ SELF_CLOSING_TAGS = [
11
+ :area,
12
+ :base, :br,
13
+ :col,
14
+ :embed,
15
+ :frame,
16
+ :hr,
17
+ :img, :input,
18
+ :link,
19
+ :meta,
20
+ :param
21
+ ]
22
+
23
+ OPEN_TAGS = [
24
+ :a, :abbr, :acronym, :address, :article, :aside, :audio,
25
+ :b, :bdo, :big, :blockquote, :body, :button,
26
+ :canvas, :caption, :center, :cite, :code, :colgroup, :command,
27
+ :datalist, :dd, :del, :details, :dfn, :dialog, :div, :dl, :dt,
28
+ :em,
29
+ :fieldset, :figure, :footer, :form, :frameset,
30
+ :h1, :h2, :h3, :h4, :h5, :h6, :head, :header, :hgroup, :html,
31
+ :i, :iframe, :ins,
32
+ :keygen, :kbd,
33
+ :label, :legend, :li,
34
+ :map, :mark, :meter,
35
+ :nav, :noframes, :noscript,
36
+ :object, :ol, :optgroup, :option,
37
+ :p, :pre, :progress,
38
+ :q,
39
+ :ruby, :rt, :rp,
40
+ :s, :samp, :script, :section, :select, :small, :source, :span, :strike, :strong, :style, :sub, :sup,
41
+ :table, :tbody, :td, :textarea, :tfoot, :th, :thead, :time, :title, :tr, :tt,
42
+ :u, :ul,
43
+ :v, :video
44
+ ]
45
+
46
+ # capture methods
47
+
48
+ def raw(string)
49
+ Raw.new(string)
50
+ end
51
+
52
+ def open_element(name, *args)
53
+ Raw.new(Element::Open.new(name, *args).to_s)
54
+ end
55
+ alias_method :open_tag, :open_element
56
+ alias_method :element, :open_element
57
+ alias_method :tag, :open_element
58
+
59
+ def closed_element(name, *args)
60
+ Raw.new(Element::Closed.new(name, *args).to_s)
61
+ end
62
+ alias_method :closed_tag, :closed_element
63
+
64
+ SELF_CLOSING_TAGS.each do |tag|
65
+ define_method(tag){ |*args| closed_element(tag, *args, &build) }
66
+ end
67
+
68
+ OPEN_TAGS.each do |tag|
69
+ define_method(tag){ |*args| open_element(tag, *args) }
70
+ end
71
+
72
+ # streaming methods
73
+
74
+ # Add a text node (data escaped) to the nodes of the current node
75
+ def _(data="")
76
+ @_undies_io.current.text(self.class.escape_html(data.to_s))
77
+ end
78
+
79
+ def __open_element(name, *args, &build)
80
+ @_undies_io.
81
+ current.
82
+ element_node(ElementNode.new(@_undies_io, Element::Open.new(name, *args, &build))).
83
+ element
84
+ end
85
+ alias_method :__open_tag, :__open_element
86
+ alias_method :__element, :__open_element
87
+ alias_method :__tag, :__open_element
88
+
89
+ def __closed_element(name, *args, &build)
90
+ @_undies_io.
91
+ current.
92
+ element_node(ElementNode.new(@_undies_io, Element::Closed.new(name, *args, &build))).
93
+ element
94
+ end
95
+ alias_method :__closed_tag, :__closed_element
96
+
97
+ SELF_CLOSING_TAGS.each do |tag|
98
+ define_method("_#{tag}") do |*args, &build|
99
+ __closed_element(tag, *args, &build)
100
+ end
101
+ end
102
+
103
+ OPEN_TAGS.each do |tag|
104
+ define_method("_#{tag}") do |*args, &build|
105
+ __open_element(tag, *args, &build)
106
+ end
107
+ end
108
+
109
+ # Manual Builder methods
110
+
111
+ # call this method to manually push the current scope to the previously
112
+ # cached element (if any)
113
+ # - changes the context of template method calls to operate on that element
114
+ def __push
115
+ @_undies_io.current.push
116
+ end
117
+
118
+ # call this method to manually pop the current scope to the previous scope
119
+ # - changes the context of template method calls to operate on the parent
120
+ # element or root node
121
+ def __pop
122
+ @_undies_io.current.pop
123
+ end
124
+
125
+ # call this to manually flush a template
126
+ def __flush
127
+ @_undies_io.current.flush
128
+ end
129
+
130
+ # call this to modify element attrs inside a build block. Once content
131
+ # or child elements have been added, any '__attr' directives will
132
+ # be ignored b/c the elements start_tag has already been flushed
133
+ # to the output
134
+ def __attrs(attrs_hash={})
135
+ @_undies_io.current.attrs(attrs_hash)
136
+ end
137
+
138
+ # Source handling methods
139
+
140
+ # call this to render template source
141
+ # use this method in layouts to insert a layout's content source
142
+ def __yield
143
+ return if (source = @_undies_source_stack.pop).nil?
144
+ if source.file?
145
+ instance_eval(source.data, source.source, 1)
146
+ else
147
+ instance_eval(&source.data)
148
+ end
149
+ end
150
+
151
+ # call this to render partial source embedded in a template
152
+ # partial source is rendered with its own scope/data but shares
153
+ # its parent template's output object
154
+ def __partial(source, data={})
155
+ if source.kind_of?(Source)
156
+ Undies::Template.new(source, data, @_undies_io)
157
+ else
158
+ @_undies_io.current.partial(source.to_s)
159
+ end
160
+ end
161
+
162
+ end
163
+ end