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
data/test/element_test.rb CHANGED
@@ -1,57 +1,28 @@
1
1
  require "assert"
2
-
3
- require 'undies/node'
4
- require "undies/output"
5
- require "undies/template"
6
-
2
+ require 'undies/io'
7
3
  require "undies/element"
8
4
 
9
5
 
10
- class Undies::Element
11
-
12
- class BasicTests < Assert::Context
13
- desc 'an element'
14
- before do
15
- @e = Undies::Element.new(:div)
16
- end
17
- subject { @e }
18
-
19
- should have_class_methods :hash_attrs
20
- should have_instance_method :prefix, :to_str
21
-
22
- should "be a Node" do
23
- assert_kind_of Undies::Node, subject
24
- end
6
+ module Undies::Element
25
7
 
26
- should "store its name as a string" do
27
- assert_equal "div", subject.instance_variable_get("@name")
28
- end
8
+ class ElementBasicTests < Assert::Context
9
+ desc 'a element'
10
+ subject { Undies::Element }
29
11
 
30
- should "know its name" do
31
- assert_equal "div", subject.class.node_name(subject)
32
- end
12
+ should have_instance_methods :hash_attrs, :escape_attr_value
13
+ should have_instance_methods :open, :closed
33
14
 
34
- should "know its start/end tags" do
35
- assert_equal "<div />", subject.class.start_tag(subject)
36
- assert_empty subject.class.end_tag(subject)
15
+ should "build an open element with the `open` method" do
16
+ assert_kind_of Undies::Element::Open, subject.open(:div)
37
17
  end
38
18
 
39
- should "have no content itself" do
40
- assert_empty subject.class.content(subject)
41
- end
42
-
43
- should "have no builds by default" do
44
- assert_empty subject.class.builds(subject)
45
- assert_empty subject.class.builds(nil)
46
- end
47
-
48
- should "have no children by default" do
49
- assert_equal false, subject.class.children(subject)
19
+ should "build a closed element with the `closed` method" do
20
+ assert_kind_of Undies::Element::Closed, subject.closed(:br)
50
21
  end
51
22
 
52
23
  end
53
24
 
54
- class HashAttrsTest < BasicTests
25
+ class HashAttrsTest < ElementBasicTests
55
26
  desc "the element class hash_attrs util"
56
27
 
57
28
  should "convert an empty hash to element attrs" do
@@ -83,6 +54,17 @@ class Undies::Element
83
54
  assert_includes 'escaped="not &amp; escaped"', attrs
84
55
  end
85
56
 
57
+ should "convert a nested array to element attrs" do
58
+ attrs = Undies::Element.hash_attrs({
59
+ :class => "testing", :id => "test_2",
60
+ :nested => [:something, 'is_awesome', 1]
61
+ })
62
+ assert_match /^\s{1}/, attrs
63
+ assert_included 'class="testing"', attrs
64
+ assert_included 'id="test_2"', attrs
65
+ assert_included 'nested="something is_awesome 1"', attrs
66
+ end
67
+
86
68
  should "convert a nested hash to element attrs" do
87
69
  attrs = Undies::Element.hash_attrs({
88
70
  :class => "testing", :id => "test_2",
@@ -95,159 +77,4 @@ class Undies::Element
95
77
  end
96
78
  end
97
79
 
98
-
99
- class CSSProxyTests < BasicTests
100
-
101
- should "respond to any method ending in '!' as an id proxy" do
102
- assert subject.respond_to?(:asdgasdg!)
103
- end
104
-
105
- should "proxy id attr with methods ending in '!'" do
106
- assert_equal({
107
- :id => 'thing1'
108
- }, subject.class.attrs(subject.thing1!))
109
- end
110
-
111
- should "proxy id attr with last method call ending in '!'" do
112
- assert_equal({
113
- :id => 'thing2'
114
- }, subject.class.attrs(subject.thing1!.thing2!))
115
- end
116
-
117
- should "set id attr to explicit if called last " do
118
- assert_equal({
119
- :id => 'thing3'
120
- }, subject.class.attrs(subject.thing1!.thing2!(:id => 'thing3')))
121
- end
122
-
123
- should "set id attr to proxy if called last" do
124
- assert_equal({
125
- :id => 'thing1'
126
- }, subject.class.attrs(subject.thing2!(:id => 'thing3').thing1!))
127
- end
128
-
129
- should "respond to any other method as a class proxy" do
130
- assert_respond_to :asdgasdg, subject
131
- end
132
-
133
- should "proxy single html class attr" do
134
- assert_equal({
135
- :class => 'thing'
136
- }, subject.class.attrs(subject.thing))
137
- end
138
-
139
- should "proxy multi html class attrs" do
140
- assert_equal({
141
- :class => 'list thing awesome'
142
- }, subject.class.attrs(subject.list.thing.awesome))
143
- end
144
-
145
- should "set class attr with explicit if called last " do
146
- assert_equal({
147
- :class => 'list'
148
- }, subject.class.attrs(subject.thing.awesome(:class => "list")))
149
- end
150
-
151
- should "update class attr with proxy if called last" do
152
- assert_equal({
153
- :class => 'list is good'
154
- }, subject.class.attrs(subject.thing.awesome(:class => "list is").good))
155
- end
156
-
157
- should "proxy mixed class and id selector attrs" do
158
- subject.thing1!.awesome({:class => "list is", :id => "thing2"}).good.thing3!
159
-
160
- assert_equal({
161
- :class => 'list is good',
162
- :id => "thing3"
163
- }, subject.class.attrs(subject))
164
- end
165
-
166
- end
167
-
168
- class SerializeTests < BasicTests
169
- before do
170
- @output = Undies::Output.new(StringIO.new(@out = ""))
171
- end
172
-
173
- should "serialize with no child elements" do
174
- Undies::Template.new(Undies::Source.new do
175
- element(:br)
176
- end, {}, @output)
177
-
178
- assert_equal "<br />", @out
179
- end
180
-
181
- should "serialize with attrs" do
182
- Undies::Template.new(Undies::Source.new do
183
- element(:br, :class => 'big')
184
- end, {}, @output)
185
-
186
- assert_equal '<br class="big" />', @out
187
- end
188
-
189
- should "serialize with attrs that have double-quotes" do
190
- Undies::Template.new(Undies::Source.new do
191
- element(:br, :class => '"this" is double-quoted')
192
- end, {}, @output)
193
-
194
- assert_equal '<br class="&quot;this&quot; is double-quoted" />', @out
195
- end
196
-
197
- should "serialize with attrs and content" do
198
- Undies::Template.new(Undies::Source.new do
199
- element(:strong, {:class => 'big'}) { __ "Loud Noises!" }
200
- end, {}, @output)
201
-
202
- assert_equal '<strong class="big">Loud Noises!</strong>', @out
203
- end
204
-
205
- should "serialize element proxy id call" do
206
- Undies::Template.new(Undies::Source.new do
207
- element(:div).thing1! { _ "stuff" }
208
- end, {}, @output)
209
-
210
- assert_equal "<div id=\"thing1\">stuff</div>", @out
211
- end
212
-
213
- should "serialize element proxy class call" do
214
- Undies::Template.new(Undies::Source.new do
215
- element(:div).thing { _ "stuff" }
216
- end, {}, @output)
217
-
218
- assert_equal "<div class=\"thing\">stuff</div>", @out
219
- end
220
-
221
- should "serialize content from separate content blocks" do
222
- Undies::Template.new(Undies::Source.new do
223
- element(:div){ _ "stuff" }.thing1!{ _ " and more stuff" }
224
- end, {}, @output)
225
-
226
- assert_equal "<div id=\"thing1\">stuff and more stuff</div>", @out
227
- end
228
-
229
- should "serialize nested elements with pp" do
230
- output = Undies::Output.new(StringIO.new(@out = ""), :pp => 4)
231
- src = Undies::Source.new do
232
- element(:div) {
233
- element(:span) { _ "Content!" }
234
- __ "Raw"
235
- element(:span) { _ "More content" }
236
- element(:div).hi {
237
- _ "first build"
238
- }.there.you! {
239
- _ "second build"
240
- }
241
- }
242
- end
243
- templ = Undies::Template.new(src, {}, output)
244
- assert_equal "<div>
245
- <span>Content!</span>Raw
246
- <span>More content</span>
247
- <div class=\"hi there\" id=\"you\">first buildsecond build</div>
248
- </div>", @out
249
- end
250
-
251
- end
252
-
253
80
  end
@@ -2,19 +2,19 @@ class WriteThing
2
2
 
3
3
  # this is used in testing the write buffer
4
4
 
5
- def self.hi(thing)
5
+ def __hi
6
6
  'hi'
7
7
  end
8
8
 
9
- def self.hello(thing)
9
+ def __hello
10
10
  'hello'
11
11
  end
12
12
 
13
- def self.hithere(thing)
13
+ def __hithere
14
14
  'hithere'
15
15
  end
16
16
 
17
- def self.prefix(thing, meth, level, indent)
17
+ def __prefix(meth, level, indent)
18
18
  "#{level > 0 ? "\n": ''}#{' '*level*indent}"
19
19
  end
20
20
 
data/test/helper.rb CHANGED
@@ -2,3 +2,87 @@
2
2
 
3
3
  # add root dir to the load path
4
4
  $LOAD_PATH.unshift(File.expand_path("../..", __FILE__))
5
+
6
+ require 'undies'
7
+
8
+ module Undies
9
+ module Element
10
+
11
+ module CSSProxyMacro
12
+
13
+ def proxy_css_methods
14
+ called_from = caller.first
15
+ Assert::Macro.new("have style attributes") do
16
+
17
+ should "respond to any method ending in '!' as an id proxy", called_from do
18
+ assert subject.respond_to?(:asdgasdg!)
19
+ end
20
+
21
+ should "proxy id attr with methods ending in '!'", called_from do
22
+ assert_equal({
23
+ :id => 'thing1'
24
+ }, subject.thing1!.instance_variable_get("@attrs"))
25
+ end
26
+
27
+ should "proxy id attr with last method call ending in '!'", called_from do
28
+ assert_equal({
29
+ :id => 'thing2'
30
+ }, subject.thing1!.thing2!.instance_variable_get("@attrs"))
31
+ end
32
+
33
+ should "set id attr to explicit if called last ", called_from do
34
+ assert_equal({
35
+ :id => 'thing3'
36
+ }, subject.thing1!.thing2!(:id => 'thing3').instance_variable_get("@attrs"))
37
+ end
38
+
39
+ should "set id attr to proxy if called last", called_from do
40
+ assert_equal({
41
+ :id => 'thing1'
42
+ }, subject.thing2!(:id => 'thing3').thing1!.instance_variable_get("@attrs"))
43
+ end
44
+
45
+ should "respond to any other method as a class proxy", called_from do
46
+ assert_respond_to :asdgasdg, subject
47
+ end
48
+
49
+ should "proxy single html class attr", called_from do
50
+ assert_equal({
51
+ :class => 'thing'
52
+ }, subject.thing.instance_variable_get("@attrs"))
53
+ end
54
+
55
+ should "proxy multi html class attrs", called_from do
56
+ assert_equal({
57
+ :class => 'list thing awesome'
58
+ }, subject.list.thing.awesome.instance_variable_get("@attrs"))
59
+ end
60
+
61
+ should "set class attr with explicit if called last ", called_from do
62
+ assert_equal({
63
+ :class => 'list'
64
+ }, subject.thing.awesome(:class => "list").instance_variable_get("@attrs"))
65
+ end
66
+
67
+ should "update class attr with proxy if called last", called_from do
68
+ assert_equal({
69
+ :class => 'list is good'
70
+ }, subject.thing.awesome(:class => "list is").good.instance_variable_get("@attrs"))
71
+ end
72
+
73
+ should "proxy mixed class and id selector attrs", called_from do
74
+ subject.thing1!.awesome({:class => "list is", :id => "thing2"}).good.thing3!
75
+
76
+ assert_equal({
77
+ :class => 'list is good',
78
+ :id => "thing3"
79
+ }, subject.instance_variable_get("@attrs"))
80
+ end
81
+
82
+ end
83
+ end
84
+
85
+ end
86
+
87
+ end
88
+ end
data/test/io_test.rb ADDED
@@ -0,0 +1,104 @@
1
+ require "assert"
2
+ require "undies/io"
3
+
4
+ class Undies::IO
5
+
6
+ class BasicTests < Assert::Context
7
+ desc 'render data'
8
+ before do
9
+ @io = Undies::IO.new(@out = "")
10
+ end
11
+ subject { @io }
12
+
13
+ should have_readers :stream, :indent, :newline
14
+ should have_writer :options
15
+ should have_accessor :level
16
+ should have_instance_methods :line_indent, :<<
17
+
18
+ should have_readers :node_stack, :current
19
+ should have_instance_methods :push, :push!, :pop, :empty?
20
+
21
+ should "know its stream" do
22
+ assert_same @out, subject.stream
23
+ end
24
+
25
+ should "default to no pretty printing" do
26
+ assert_equal 0, subject.indent
27
+ assert_equal "", subject.newline
28
+ end
29
+
30
+ should "default to level 0" do
31
+ assert_equal 0, subject.level
32
+ end
33
+
34
+ should "default with an empty node_stack" do
35
+ assert_empty subject.node_stack
36
+ assert_nil subject.current
37
+ end
38
+
39
+ should "write raw data directly to the stream" do
40
+ subject << "Raw data"
41
+ assert_equal "Raw data", @out
42
+ end
43
+
44
+ end
45
+
46
+
47
+
48
+ class PrettyPrintTests < BasicTests
49
+ desc "when pretty printing"
50
+ before do
51
+ subject.options = {:pp => 2, :level => 1}
52
+ end
53
+
54
+ should "know its pp settings" do
55
+ assert_equal 2, subject.indent
56
+ assert_equal 1, subject.level
57
+ assert_equal "\n", subject.newline
58
+ end
59
+
60
+ should "pretty print line indents" do
61
+ assert_equal " hi", subject.line_indent + "hi"
62
+
63
+ subject.level += 1
64
+ assert_equal " hello", subject.line_indent + "hello"
65
+ assert_equal "manual level down", subject.line_indent(-2) + "manual level down"
66
+
67
+ subject.level -= 1
68
+ assert_equal " implicit level down", subject.line_indent + 'implicit level down'
69
+ end
70
+
71
+ end
72
+
73
+
74
+
75
+ class NodeStackTests < BasicTests
76
+
77
+ should "push to, pop from, and refer to the current thing on the stack" do
78
+ subject.push("lala")
79
+ assert_equal "lala", subject.current
80
+ assert_equal 1, subject.level
81
+
82
+ subject.pop
83
+ assert_nil subject.current
84
+ assert_equal 0, subject.level
85
+
86
+ subject.push!("boohoo")
87
+ assert_equal "boohoo", subject.current
88
+ assert_equal 0, subject.level
89
+ end
90
+
91
+ should "be empty if its node stack is empty" do
92
+ assert_empty subject.node_stack
93
+ assert_empty subject
94
+
95
+ subject.push("lala")
96
+
97
+ assert_not_empty subject.node_stack
98
+ assert_not_empty subject
99
+ end
100
+
101
+
102
+ end
103
+
104
+ end
@@ -1,6 +1,6 @@
1
1
  require "assert"
2
2
 
3
- require "undies/named_source"
3
+ require "undies/source"
4
4
 
5
5
  class Undies::NamedSource
6
6
 
data/test/raw_test.rb ADDED
@@ -0,0 +1,25 @@
1
+ require 'assert'
2
+ require 'undies/template'
3
+ require 'undies/element'
4
+
5
+ module Undies
6
+
7
+ class RawTests < Assert::Context
8
+ desc 'the Raw class'
9
+ before do
10
+ @rs = Raw.new "ab&<>'\"/yz"
11
+ end
12
+ subject { @rs }
13
+
14
+ should "be a String" do
15
+ assert_kind_of ::String, subject
16
+ end
17
+
18
+ should "ignore any gsubbing" do
19
+ assert_equal subject.to_s, subject.gsub('ab', '__').gsub('yz', '--')
20
+ assert_equal subject.to_s, Template.escape_html(subject)
21
+ end
22
+
23
+ end
24
+
25
+ end
@@ -0,0 +1,108 @@
1
+ require "assert"
2
+ require 'undies/io'
3
+ require 'undies/element_node'
4
+ require 'undies/element'
5
+ require "undies/root_node"
6
+
7
+ class Undies::RootNode
8
+
9
+ class BasicTests < Assert::Context
10
+ desc 'a root node'
11
+ before do
12
+ @io = Undies::IO.new(@out = "", :pp => 1)
13
+ @rn = Undies::RootNode.new(@io)
14
+
15
+ @e = Undies::Element::Closed.new(:br)
16
+ @en = Undies::ElementNode.new(@io, @e)
17
+ end
18
+ subject { @rn }
19
+
20
+ should have_readers :io, :cached
21
+ should have_instance_methods :attrs, :text, :element_node
22
+ should have_instance_methods :partial, :flush, :push, :pop
23
+
24
+ should "know its IO" do
25
+ assert_equal @io, subject.io
26
+ end
27
+
28
+ should "have nothing cached by default" do
29
+ assert_nil subject.cached
30
+ end
31
+
32
+ should "complain if trying to specify attrs" do
33
+ assert_raises Undies::RootAPIError do
34
+ subject.attrs({:blah => 'whatever'})
35
+ end
36
+ end
37
+
38
+ should "cache any raw text given" do
39
+ subject.text "some raw markup"
40
+ assert_equal "some raw markup#{@io.newline}", subject.cached
41
+ end
42
+
43
+ should "write out any cached value when new markup is given" do
44
+ subject.text "some raw markup"
45
+ assert_empty @out
46
+
47
+ subject.text "more raw markup"
48
+ assert_equal "some raw markup\n", @out
49
+ end
50
+
51
+ should "cache any element node given" do
52
+ subject.element_node(@en)
53
+ assert_equal @en, subject.cached
54
+ end
55
+
56
+ should "return the element when given" do
57
+ assert_equal @en, subject.element_node(@en)
58
+ end
59
+
60
+ should "write out any cached value when a new element is given" do
61
+ subject.element_node(@en)
62
+ assert_empty @out
63
+
64
+ subject.element_node(@en)
65
+ assert_equal "<br />#{@io.newline}", @out
66
+ end
67
+
68
+ should "cache any partial markup given" do
69
+ subject.partial "some partial markup"
70
+ assert_equal "some partial markup#{@io.newline}", subject.cached
71
+ end
72
+
73
+ should "write out any cached value when new partial markup is given" do
74
+ subject.partial "some partial markup"
75
+ assert_empty @out
76
+
77
+ subject.partial "more partial markup"
78
+ assert_equal "some partial markup\n", @out
79
+ end
80
+
81
+ should "write out any cached value when flushed" do
82
+ subject.flush
83
+ assert_empty @out
84
+
85
+ subject.text "some raw markup"
86
+ subject.flush
87
+ assert_equal "some raw markup\n", @out
88
+ end
89
+
90
+ should "only flush if popped" do
91
+ io_level = @io.level
92
+ subject.text "some raw markup"
93
+ subject.pop
94
+ assert_equal "some raw markup\n", @out
95
+ assert_equal io_level, @io.level
96
+ end
97
+
98
+ should "push the cached content to the IO handler" do
99
+ io_level = @io.level
100
+ subject.text "some raw markup"
101
+ subject.push
102
+ assert_equal io_level+1, @io.level
103
+ assert_equal "some raw markup#{@io.newline}", @io.current
104
+ end
105
+
106
+ end
107
+
108
+ end
@@ -1,6 +1,6 @@
1
1
  require "assert"
2
2
 
3
- require "undies/source_stack"
3
+ require "undies/source"
4
4
 
5
5
  class Undies::SourceStack
6
6
 
@@ -1,7 +1,4 @@
1
1
  require "assert"
2
- require "stringio"
3
- require 'undies/node_stack'
4
-
5
2
  require "undies/template"
6
3
 
7
4
  class Undies::Template
@@ -10,17 +7,15 @@ class Undies::Template
10
7
  desc 'a template rendered using the builder approach'
11
8
  before do
12
9
  @src = Undies::Source.new(Proc.new {})
13
- @output = Undies::Output.new(@outstream = StringIO.new(@out = ""))
14
- @t = Undies::Template.new(@src, {}, @output)
10
+ @io = Undies::IO.new(@out = "")
11
+ @t = Undies::Template.new(@src, {}, @io)
15
12
  end
16
13
  subject { @t }
17
14
 
18
15
  should "maintain scope throughout the build blocks" do
19
- templ = Undies::Template.new(@output)
16
+ templ = Undies::Template.new(@io)
20
17
  templ._div {
21
- templ._div {
22
- templ.__ self.object_id
23
- }
18
+ templ._div self.object_id
24
19
  }
25
20
  templ.__flush
26
21