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