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.
- data/ARCH.md +116 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +20 -4
- data/LICENSE +22 -0
- data/README.md +343 -0
- data/Rakefile +25 -17
- data/bench/bench_runner.rb +132 -12
- data/bench/large.html.erb +9 -13
- data/bench/large.html.haml +11 -0
- data/bench/large.html.rb +8 -12
- data/bench/profiler +1 -1
- data/bench/profiler_runner.rb +2 -5
- data/bench/small.html.erb +9 -13
- data/bench/small.html.haml +11 -0
- data/bench/small.html.rb +8 -12
- data/bench/verylarge.html.erb +9 -13
- data/bench/verylarge.html.haml +11 -0
- data/bench/verylarge.html.rb +8 -12
- data/lib/undies/api.rb +163 -0
- data/lib/undies/element.rb +160 -80
- data/lib/undies/element_node.rb +116 -0
- data/lib/undies/io.rb +43 -0
- data/lib/undies/root_node.rb +62 -0
- data/lib/undies/source.rb +78 -2
- data/lib/undies/template.rb +17 -131
- data/lib/undies/version.rb +1 -1
- data/lib/undies.rb +3 -2
- data/test/element_closed_test.rb +69 -0
- data/test/element_node_test.rb +274 -0
- data/test/element_open_test.rb +101 -0
- data/test/element_test.rb +23 -196
- data/test/fixtures/write_thing.rb +4 -4
- data/test/helper.rb +84 -0
- data/test/io_test.rb +104 -0
- data/test/named_source_test.rb +1 -1
- data/test/raw_test.rb +25 -0
- data/test/root_node_test.rb +108 -0
- data/test/source_stack_test.rb +1 -1
- data/test/template_builder_render_test.rb +4 -9
- data/test/template_source_render_test.rb +16 -20
- data/test/template_test.rb +87 -80
- data/test/templates/content.html.rb +1 -1
- data/test/templates/test.html.rb +1 -1
- data/undies.gemspec +1 -0
- metadata +52 -23
- data/README.rdoc +0 -203
- data/lib/undies/named_source.rb +0 -54
- data/lib/undies/node.rb +0 -87
- data/lib/undies/node_stack.rb +0 -111
- data/lib/undies/output.rb +0 -31
- data/lib/undies/source_stack.rb +0 -22
- data/test/node_stack_test.rb +0 -109
- data/test/node_test.rb +0 -91
- data/test/output_test.rb +0 -69
data/lib/undies/template.rb
CHANGED
@@ -1,27 +1,19 @@
|
|
1
|
-
require 'undies/
|
2
|
-
require 'undies/
|
3
|
-
require 'undies/
|
4
|
-
|
5
|
-
require 'undies/node'
|
6
|
-
require 'undies/element'
|
1
|
+
require 'undies/io'
|
2
|
+
require 'undies/source'
|
3
|
+
require 'undies/root_node'
|
4
|
+
require 'undies/api'
|
7
5
|
|
8
6
|
module Undies
|
9
7
|
class Template
|
10
8
|
|
9
|
+
include API
|
10
|
+
|
11
11
|
# have as many methods on the class level as possible to keep from
|
12
12
|
# polluting the public instance methods, the instance scope, and to
|
13
13
|
# maximize the effectiveness of the Template#method_missing logic
|
14
14
|
|
15
|
-
def self.source_stack(template)
|
16
|
-
template.instance_variable_get("@_undies_source_stack")
|
17
|
-
end
|
18
|
-
|
19
|
-
def self.node_stack(template)
|
20
|
-
template.instance_variable_get("@_undies_node_stack")
|
21
|
-
end
|
22
|
-
|
23
15
|
def self.flush(template)
|
24
|
-
|
16
|
+
template.__flush
|
25
17
|
end
|
26
18
|
|
27
19
|
# Ripped from Rack v1.3.0 ======================================
|
@@ -43,136 +35,30 @@ module Undies
|
|
43
35
|
|
44
36
|
def initialize(*args)
|
45
37
|
# setup a node stack with the given output obj
|
46
|
-
|
38
|
+
@_undies_io = if args.last.kind_of?(Undies::IO)
|
47
39
|
args.pop
|
48
40
|
else
|
49
|
-
raise ArgumentError, "please provide an
|
41
|
+
raise ArgumentError, "please provide an IO object"
|
50
42
|
end
|
51
|
-
@_undies_node_stack = NodeStack.create(output)
|
52
43
|
|
53
|
-
# apply any given data to template scope
|
54
|
-
|
55
|
-
|
56
|
-
raise ArgumentError, "data conflicts with template public methods."
|
44
|
+
# apply any given data to template scope as instance variables
|
45
|
+
(args.last.kind_of?(::Hash) ? args.pop : {}).each do |k, v|
|
46
|
+
self.instance_variable_set("@#{k}", v)
|
57
47
|
end
|
58
|
-
metaclass = class << self; self; end
|
59
|
-
data.each {|key, value| metaclass.class_eval { define_method(key){value} }}
|
60
48
|
|
61
49
|
# setup a source stack with the given source
|
62
50
|
source = args.last.kind_of?(Source) ? args.pop : Source.new(Proc.new {})
|
63
51
|
@_undies_source_stack = SourceStack.new(source)
|
64
52
|
|
53
|
+
# push a root node onto the IO
|
54
|
+
@_undies_io.push!(RootNode.new(@_undies_io)) if @_undies_io.empty?
|
55
|
+
|
65
56
|
# yield to recursivley render the source stack
|
66
|
-
|
57
|
+
__yield
|
67
58
|
|
68
59
|
# flush any elements that need to be built
|
69
|
-
|
70
|
-
end
|
71
|
-
|
72
|
-
# call this to modify element attrs inside a build block. Once content
|
73
|
-
# or child elements have been added, any '__attr' directives will
|
74
|
-
# be ignored b/c the elements start_tag has already been flushed
|
75
|
-
# to the output
|
76
|
-
def __attrs(attrs_hash={})
|
77
|
-
self.class.node_stack(self).current.tap do |node|
|
78
|
-
if node
|
79
|
-
node.class.merge_attrs(node, attrs_hash)
|
80
|
-
node.class.set_start_tag(node)
|
81
|
-
end
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
# call this method to manually push the currently cached node onto the
|
86
|
-
# node stack
|
87
|
-
# - implicitly flushes the cache
|
88
|
-
# - changes the context of template method calls to operate on that node
|
89
|
-
def __push
|
90
|
-
ns = self.class.node_stack(self)
|
91
|
-
node, ns.cached_node = ns.cached_node, nil
|
92
|
-
if node
|
93
|
-
# add an empty build block to generate a non-closing start tag
|
94
|
-
# and a closing end tag
|
95
|
-
node.class.add_build(node, Proc.new {})
|
96
|
-
node.class.set_start_tag(node)
|
97
|
-
node.class.set_end_tag(node)
|
98
|
-
|
99
|
-
ns.push(node)
|
100
|
-
end
|
101
|
-
end
|
102
|
-
|
103
|
-
# call this method to manually pop the current scoped node from the node stack
|
104
|
-
# - flushes the cache
|
105
|
-
# - changes the context of template method calls to operate on the parent node
|
106
|
-
def __pop
|
107
|
-
ns = self.class.node_stack(self)
|
108
|
-
ns.clear_cached
|
109
|
-
ns.pop
|
110
|
-
end
|
111
|
-
|
112
|
-
# call this to manually flush a template
|
113
|
-
def __flush
|
114
|
-
self.class.flush(self)
|
115
|
-
end
|
116
|
-
|
117
|
-
# call this to render template source
|
118
|
-
# use this method in layouts to insert a layout's content source
|
119
|
-
def __yield
|
120
|
-
return if self.class.node_stack(self).nil? || (source = self.class.source_stack(self).pop).nil?
|
121
|
-
if source.file?
|
122
|
-
instance_eval(source.data, source.source, 1)
|
123
|
-
else
|
124
|
-
instance_eval(&source.data)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
# call this to render partial source embedded in a template
|
129
|
-
# partial source is rendered with its own scope/data but shares
|
130
|
-
# its parent template's output object
|
131
|
-
def __partial(source, data={})
|
132
|
-
if source.kind_of?(Source)
|
133
|
-
Undies::Template.new(source, data, self.class.node_stack(self))
|
134
|
-
else
|
135
|
-
self.__ source.to_s, :partial
|
136
|
-
end
|
137
|
-
end
|
138
|
-
|
139
|
-
# Add a text node (data escaped) to the nodes of the current node
|
140
|
-
def _(data="", mode=:inline)
|
141
|
-
self.__ self.class.escape_html(data.to_s), mode
|
142
|
-
end
|
143
|
-
|
144
|
-
# Add a text node with the data un-escaped
|
145
|
-
def __(data="", mode=:inline)
|
146
|
-
Node.new(data.to_s, mode).tap do |node|
|
147
|
-
self.class.node_stack(self).node(node)
|
148
|
-
end
|
149
|
-
end
|
150
|
-
|
151
|
-
# Add an element to the node stack
|
152
|
-
def element(*args, &build)
|
153
|
-
Element.new(*args, &build).tap do |element|
|
154
|
-
self.class.node_stack(self).node(element)
|
155
|
-
end
|
156
|
-
end
|
157
|
-
alias_method :tag, :element
|
158
|
-
|
159
|
-
# Element proxy methods ('_<element>'') ========================
|
160
|
-
ELEM_METH_REGEX = /^_(.+)$/
|
161
|
-
def method_missing(meth, *args, &block)
|
162
|
-
if meth.to_s =~ ELEM_METH_REGEX
|
163
|
-
element($1, *args, &block)
|
164
|
-
else
|
165
|
-
super
|
166
|
-
end
|
167
|
-
end
|
168
|
-
def respond_to?(*args)
|
169
|
-
if args.first.to_s =~ ELEM_METH_REGEX
|
170
|
-
true
|
171
|
-
else
|
172
|
-
super
|
173
|
-
end
|
60
|
+
__flush
|
174
61
|
end
|
175
|
-
# ==============================================================
|
176
62
|
|
177
63
|
end
|
178
64
|
end
|
data/lib/undies/version.rb
CHANGED
data/lib/undies.rb
CHANGED
@@ -0,0 +1,69 @@
|
|
1
|
+
require "assert"
|
2
|
+
require 'undies/io'
|
3
|
+
require "undies/element"
|
4
|
+
|
5
|
+
|
6
|
+
module Undies::Element
|
7
|
+
|
8
|
+
class ClosedBasicTests < Assert::Context
|
9
|
+
desc 'a closed element'
|
10
|
+
before do
|
11
|
+
@ec = Undies::Element::Closed.new(:br)
|
12
|
+
end
|
13
|
+
subject { @ec }
|
14
|
+
|
15
|
+
should have_instance_methods :__start_tag, :__content, :__build, :__end_tag
|
16
|
+
should have_instance_methods :to_s
|
17
|
+
|
18
|
+
should "know its name and store it as a string" do
|
19
|
+
assert_equal "br", subject.instance_variable_get("@name")
|
20
|
+
end
|
21
|
+
|
22
|
+
should "have no attrs by default" do
|
23
|
+
assert_empty subject.instance_variable_get("@attrs")
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
class ClosedCSSProxyTests < ClosedBasicTests
|
31
|
+
extend CSSProxyMacro
|
32
|
+
|
33
|
+
should proxy_css_methods
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
|
38
|
+
class ClosedSerializeTests < ClosedBasicTests
|
39
|
+
|
40
|
+
should "serialize with no attrs" do
|
41
|
+
elem = Undies::Element::Closed.new(:br)
|
42
|
+
assert_equal "<br />", elem.to_s
|
43
|
+
end
|
44
|
+
|
45
|
+
should "serialize with attrs" do
|
46
|
+
elem = Undies::Element::Closed.new(:br, :class => 'big')
|
47
|
+
assert_equal "<br class=\"big\" />", elem.to_s
|
48
|
+
end
|
49
|
+
|
50
|
+
should "serialize with attrs that have double-quotes" do
|
51
|
+
elem = Undies::Element::Closed.new(:br, :class => '"this" is double-quoted')
|
52
|
+
assert_equal "<br class=\""this" is double-quoted\" />", elem.to_s
|
53
|
+
end
|
54
|
+
|
55
|
+
should "serialize element proxy id call" do
|
56
|
+
elem = Undies::Element::Closed.new(:br).thing1!
|
57
|
+
assert_equal "<br id=\"thing1\" />", elem.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
should "serialize element proxy class call" do
|
61
|
+
# calling a private method as public to test private methods not
|
62
|
+
# polluting public method_missing scope
|
63
|
+
elem = Undies::Element::Closed.new(:br).proxy
|
64
|
+
assert_equal "<br class=\"proxy\" />", elem.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
end
|
68
|
+
|
69
|
+
end
|
@@ -0,0 +1,274 @@
|
|
1
|
+
require "assert"
|
2
|
+
require 'undies/io'
|
3
|
+
require 'undies/element_node'
|
4
|
+
require 'undies/element'
|
5
|
+
|
6
|
+
|
7
|
+
class Undies::ElementNode
|
8
|
+
|
9
|
+
class BasicTests < Assert::Context
|
10
|
+
desc 'an element node'
|
11
|
+
before do
|
12
|
+
# io test with :pp 1 so we can test newline insertion
|
13
|
+
# io test with level 1 so we can test element start tag writing
|
14
|
+
@io = Undies::IO.new(@out = "", :pp => 1, :level => 1)
|
15
|
+
@e = Undies::Element.open(:div, "hi")
|
16
|
+
@en = Undies::ElementNode.new(@io, @e)
|
17
|
+
end
|
18
|
+
subject { @en }
|
19
|
+
|
20
|
+
should have_readers :io, :element, :cached
|
21
|
+
should have_instance_methods :attrs, :text, :element_node
|
22
|
+
should have_instance_methods :partial, :flush, :push, :pop, :to_s
|
23
|
+
|
24
|
+
should "know its IO" do
|
25
|
+
assert_equal @io, subject.io
|
26
|
+
end
|
27
|
+
|
28
|
+
should "know its element" do
|
29
|
+
assert_equal @e, subject.element
|
30
|
+
end
|
31
|
+
|
32
|
+
should "have nothing cached by default" do
|
33
|
+
assert_nil subject.cached
|
34
|
+
end
|
35
|
+
|
36
|
+
should "complain if trying to add text in a build" do
|
37
|
+
assert_raises Undies::ElementAPIError do
|
38
|
+
subject.text 'blah'
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
43
|
+
|
44
|
+
|
45
|
+
|
46
|
+
class AddContentTests < BasicTests
|
47
|
+
desc "adding content"
|
48
|
+
before do
|
49
|
+
@text1 = "some raw markup"
|
50
|
+
@text2 = "more raw markup"
|
51
|
+
@elem1 = Undies::Element::Open.new(:strong, "blah")
|
52
|
+
@elem2 = Undies::Element::Closed.new(:br).meh
|
53
|
+
@en1 = Undies::ElementNode.new(@io, @elem1)
|
54
|
+
@en2 = Undies::ElementNode.new(@io, @elem2)
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
class AddContentStartTagWrittenTests < AddContentTests
|
60
|
+
desc "(the start tag has already been written)"
|
61
|
+
before do
|
62
|
+
subject.instance_variable_set("@start_tag_written", true)
|
63
|
+
end
|
64
|
+
|
65
|
+
end
|
66
|
+
|
67
|
+
class ElementStartTagWrittenTests < AddContentStartTagWrittenTests
|
68
|
+
desc "using the element_node meth"
|
69
|
+
|
70
|
+
should "cache any element node given" do
|
71
|
+
subject.element_node(@en1)
|
72
|
+
assert_equal @en1, subject.cached
|
73
|
+
end
|
74
|
+
|
75
|
+
should "return the element node" do
|
76
|
+
assert_equal @en1, subject.element_node(@en1)
|
77
|
+
end
|
78
|
+
|
79
|
+
should "write out any cached value when a new element is given" do
|
80
|
+
subject.element_node(@en1)
|
81
|
+
assert_empty @out
|
82
|
+
|
83
|
+
subject.element_node(@en2)
|
84
|
+
assert_equal "#{@io.line_indent}<strong>blah</strong>#{@io.newline}", @out
|
85
|
+
end
|
86
|
+
|
87
|
+
should "write out any cached value when flushed" do
|
88
|
+
subject.flush
|
89
|
+
assert_empty @out
|
90
|
+
|
91
|
+
subject.element_node(@en1)
|
92
|
+
subject.flush
|
93
|
+
assert_equal "#{@io.line_indent}<strong>blah</strong>#{@io.newline}", @out
|
94
|
+
end
|
95
|
+
|
96
|
+
end
|
97
|
+
|
98
|
+
class PartialStartTagWrittenTests < AddContentStartTagWrittenTests
|
99
|
+
desc "using the partial meth"
|
100
|
+
|
101
|
+
should "cache any partial markup given" do
|
102
|
+
subject.partial("partial markup")
|
103
|
+
assert_equal "partial markup", subject.cached
|
104
|
+
end
|
105
|
+
|
106
|
+
should "write out any cached partial values" do
|
107
|
+
subject.partial("partial markup")
|
108
|
+
assert_empty @out
|
109
|
+
|
110
|
+
subject.element_node(@en2)
|
111
|
+
assert_equal "partial markup", @out
|
112
|
+
end
|
113
|
+
|
114
|
+
should "write out any cached value when flushed" do
|
115
|
+
subject.flush
|
116
|
+
assert_empty @out
|
117
|
+
|
118
|
+
subject.partial("partial markup")
|
119
|
+
subject.flush
|
120
|
+
assert_equal "partial markup", @out
|
121
|
+
end
|
122
|
+
|
123
|
+
end
|
124
|
+
|
125
|
+
|
126
|
+
|
127
|
+
class AddContentStartTagNotWrittenTests < AddContentTests
|
128
|
+
desc "(the start tag has not been written)"
|
129
|
+
before do
|
130
|
+
subject.instance_variable_set("@start_tag_written", false)
|
131
|
+
end
|
132
|
+
|
133
|
+
end
|
134
|
+
|
135
|
+
class ElementStartTagNotWrittenTests < AddContentStartTagNotWrittenTests
|
136
|
+
desc "using the element_node meth"
|
137
|
+
|
138
|
+
should "cache any element_node given" do
|
139
|
+
subject.element_node(@en1)
|
140
|
+
assert_equal @en1, subject.cached
|
141
|
+
end
|
142
|
+
|
143
|
+
should "return the element node" do
|
144
|
+
assert_equal @en1, subject.element_node(@en1)
|
145
|
+
end
|
146
|
+
|
147
|
+
should "write out the start tag with IO#newline when an element is given" do
|
148
|
+
subject.element_node(@en1)
|
149
|
+
assert_equal "<div>#{@io.newline}", @out
|
150
|
+
end
|
151
|
+
|
152
|
+
should "write out any cached content and cache new markup when given" do
|
153
|
+
subject.element_node @en1
|
154
|
+
subject.element_node @en2
|
155
|
+
assert_equal "<div>#{@io.newline}#{@io.line_indent}<strong>blah</strong>#{@io.newline}", @out
|
156
|
+
assert_equal @en2, subject.cached
|
157
|
+
end
|
158
|
+
|
159
|
+
should "write out the end tag with IO#newline indented when popped" do
|
160
|
+
subject.element_node(@en1)
|
161
|
+
subject.pop
|
162
|
+
assert_equal "<div>#{@io.newline} <strong>blah</strong>#{@io.newline}</div>#{@io.newline}", @out
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
class PartialStartTagNotWrittenTests < AddContentStartTagNotWrittenTests
|
168
|
+
desc "using the partial meth"
|
169
|
+
|
170
|
+
should "cache any partial markup given" do
|
171
|
+
subject.partial("partial markup")
|
172
|
+
assert_equal "partial markup", subject.cached
|
173
|
+
end
|
174
|
+
|
175
|
+
should "write out the start tag with IO#newline when a partial is given" do
|
176
|
+
subject.partial("partial markup")
|
177
|
+
assert_equal "<div>#{@io.newline}", @out
|
178
|
+
end
|
179
|
+
|
180
|
+
should "write out the end tag with IO#newline indented when a partial is given" do
|
181
|
+
subject.partial(" partial markup\n")
|
182
|
+
subject.pop
|
183
|
+
assert_equal "<div>#{@io.newline} partial markup\n</div>#{@io.newline}", @out
|
184
|
+
end
|
185
|
+
|
186
|
+
end
|
187
|
+
|
188
|
+
class AttrsTests < AddContentStartTagNotWrittenTests
|
189
|
+
desc "using the attrs meth"
|
190
|
+
|
191
|
+
should "modify the parent element's tag attributes" do
|
192
|
+
subject.attrs(:test => 'value')
|
193
|
+
subject.element_node(@en1)
|
194
|
+
|
195
|
+
assert_equal "<div test=\"value\">#{@io.newline}", @out
|
196
|
+
end
|
197
|
+
|
198
|
+
should "not effect the start tag once child elements have been written" do
|
199
|
+
subject.attrs(:test => 'value')
|
200
|
+
subject.element_node(@en1)
|
201
|
+
subject.attrs(:another => 'val')
|
202
|
+
|
203
|
+
assert_equal "<div test=\"value\">#{@io.newline}", @out
|
204
|
+
end
|
205
|
+
|
206
|
+
end
|
207
|
+
|
208
|
+
|
209
|
+
|
210
|
+
class SerializeTests < BasicTests
|
211
|
+
|
212
|
+
should "serialize nested elements with pp and only honor the last build block" do
|
213
|
+
io = Undies::IO.new(@out = "", :pp => 1, :level => 0)
|
214
|
+
|
215
|
+
e1a = Undies::Element::Open.new :span, 'Content!'
|
216
|
+
en1a = Undies::ElementNode.new(io, e1a)
|
217
|
+
|
218
|
+
e1b = Undies::Element::Open.new :span, 'More content'
|
219
|
+
en1b = Undies::ElementNode.new(io, e1b)
|
220
|
+
|
221
|
+
e1c = Undies::Element::Open.new :div
|
222
|
+
en1c = Undies::ElementNode.new(io, e1c)
|
223
|
+
|
224
|
+
e2a = Undies::Element::Open.new :p, 'a'
|
225
|
+
en2a = Undies::ElementNode.new(io, e2a)
|
226
|
+
|
227
|
+
e2b = Undies::Element::Open.new :p, 'b'
|
228
|
+
en2b = Undies::ElementNode.new(io, e2b)
|
229
|
+
|
230
|
+
e_root = Undies::Element::Open.new :div
|
231
|
+
en_root = Undies::ElementNode.new(io, e_root)
|
232
|
+
e_root.test do
|
233
|
+
en_root.attrs :class => 'root'
|
234
|
+
en_root.element_node(en1a)
|
235
|
+
en_root.element_node(en1b)
|
236
|
+
en_root.element_node(en1c)
|
237
|
+
end
|
238
|
+
|
239
|
+
# any build trumps any content provided in the args
|
240
|
+
e1b.test {
|
241
|
+
en1b.element_node(en2a)
|
242
|
+
}
|
243
|
+
|
244
|
+
# the last build specified is the only one used
|
245
|
+
e1c.
|
246
|
+
proxy {
|
247
|
+
# this will be ignored
|
248
|
+
en1c.element_node(en1a)
|
249
|
+
}.
|
250
|
+
start_tag.
|
251
|
+
you! {
|
252
|
+
# this will be the build for e1c
|
253
|
+
# only builds on the last proxy call
|
254
|
+
en1c.element_node(en2b)
|
255
|
+
}
|
256
|
+
|
257
|
+
|
258
|
+
en_root.to_s
|
259
|
+
|
260
|
+
assert_equal "<div class=\"root\">
|
261
|
+
<span>Content!</span>
|
262
|
+
<span class=\"test\">
|
263
|
+
<p>a</p>
|
264
|
+
</span>
|
265
|
+
<div class=\"proxy start_tag\" id=\"you\">
|
266
|
+
<p>b</p>
|
267
|
+
</div>
|
268
|
+
</div>
|
269
|
+
", @out
|
270
|
+
end
|
271
|
+
|
272
|
+
end
|
273
|
+
|
274
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require "assert"
|
2
|
+
require "undies/element"
|
3
|
+
|
4
|
+
|
5
|
+
module Undies::Element
|
6
|
+
|
7
|
+
class OpenBasicTests < Assert::Context
|
8
|
+
desc 'an open element'
|
9
|
+
before do
|
10
|
+
@e = Undies::Element::Open.new(:div)
|
11
|
+
end
|
12
|
+
subject { @e }
|
13
|
+
|
14
|
+
should have_instance_methods :__start_tag, :__content, :__build, :__end_tag
|
15
|
+
should have_instance_methods :to_s
|
16
|
+
|
17
|
+
should "know its name and store it as a string" do
|
18
|
+
assert_equal "div", subject.instance_variable_get("@name")
|
19
|
+
end
|
20
|
+
|
21
|
+
should "have no attrs by default" do
|
22
|
+
assert_empty subject.instance_variable_get("@attrs")
|
23
|
+
end
|
24
|
+
|
25
|
+
should "have no content by default" do
|
26
|
+
assert_empty subject.instance_variable_get("@content")
|
27
|
+
end
|
28
|
+
|
29
|
+
should "have no build by default" do
|
30
|
+
assert_nil subject.instance_variable_get("@build")
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
|
37
|
+
class OpenCSSProxyTests < OpenBasicTests
|
38
|
+
extend CSSProxyMacro
|
39
|
+
|
40
|
+
should proxy_css_methods
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
class OpenSerializeTests < OpenBasicTests
|
46
|
+
|
47
|
+
should "serialize with no attrs, content, or build" do
|
48
|
+
elem = Undies::Element::Open.new(:div)
|
49
|
+
assert_equal "<div></div>", elem.to_s
|
50
|
+
end
|
51
|
+
|
52
|
+
should "serialize with attrs" do
|
53
|
+
elem = Undies::Element::Open.new(:div, :class => 'big')
|
54
|
+
assert_equal "<div class=\"big\"></div>", elem.to_s
|
55
|
+
end
|
56
|
+
|
57
|
+
should "serialize with escaped attrs content" do
|
58
|
+
elem = Undies::Element::Open.new(:div, :class => '"this" is double-quoted')
|
59
|
+
assert_equal "<div class=\""this" is double-quoted\"></div>", elem.to_s
|
60
|
+
end
|
61
|
+
|
62
|
+
should "serialize with a single piece of content" do
|
63
|
+
elem = Undies::Element::Open.new(:div, "hi")
|
64
|
+
assert_equal "<div>hi</div>", elem.to_s
|
65
|
+
end
|
66
|
+
|
67
|
+
should "serialize with multiple pieces of content joined" do
|
68
|
+
elem = Undies::Element::Open.new(:div, "hi", ' there', ' you')
|
69
|
+
assert_equal "<div>hi there you</div>", elem.to_s
|
70
|
+
end
|
71
|
+
|
72
|
+
should "serialize with escaped content" do
|
73
|
+
elem = Undies::Element::Open.new(:div, "stuff & <em>more stuff</em>")
|
74
|
+
assert_equal "<div>stuff & <em>more stuff</em></div>", elem.to_s
|
75
|
+
end
|
76
|
+
|
77
|
+
should "serialize with raw content" do
|
78
|
+
elem = Undies::Element::Open.new(:div, Undies::Raw.new("stuff & <em>more stuff</em>"))
|
79
|
+
assert_equal "<div>stuff & <em>more stuff</em></div>", elem.to_s
|
80
|
+
end
|
81
|
+
|
82
|
+
should "serialize element proxy id call" do
|
83
|
+
elem = Undies::Element::Open.new(:div, 'stuff').thing1!
|
84
|
+
assert_equal "<div id=\"thing1\">stuff</div>", elem.to_s
|
85
|
+
end
|
86
|
+
|
87
|
+
should "serialize element proxy id call with content" do
|
88
|
+
elem = Undies::Element::Open.new(:div).thing1! 'proxy stuff'
|
89
|
+
assert_equal "<div id=\"thing1\">proxy stuff</div>", elem.to_s
|
90
|
+
end
|
91
|
+
|
92
|
+
should "serialize element proxy class call" do
|
93
|
+
# calling a private method as public to test private methods not
|
94
|
+
# polluting public method_missing scope
|
95
|
+
elem = Undies::Element::Open.new(:div, 'stuff').proxy
|
96
|
+
assert_equal "<div class=\"proxy\">stuff</div>", elem.to_s
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|