undies 2.2.1 → 3.0.0.rc.1

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