undies 1.2.0 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +2 -0
- data/Gemfile +2 -1
- data/Gemfile.lock +10 -5
- data/Rakefile +2 -4
- data/bench/large.html.rb +32 -0
- data/bench/procs.rb +106 -0
- data/bench/profiler.rb +25 -0
- data/bench/small.html.rb +32 -0
- data/bench/verylarge.html.rb +32 -0
- data/lib/undies/element.rb +61 -61
- data/lib/undies/named_source.rb +54 -0
- data/lib/undies/node.rb +16 -24
- data/lib/undies/node_buffer.rb +35 -0
- data/lib/undies/output.rb +64 -0
- data/lib/undies/source.rb +58 -12
- data/lib/undies/source_stack.rb +22 -0
- data/lib/undies/template.rb +47 -134
- data/lib/undies/version.rb +1 -1
- data/lib/undies.rb +1 -11
- data/test/element_test.rb +106 -99
- data/test/helper.rb +4 -2
- data/test/irb.rb +3 -4
- data/test/named_source_test.rb +91 -0
- data/test/node_buffer_test.rb +54 -0
- data/test/node_test.rb +19 -10
- data/test/output_test.rb +116 -0
- data/test/source_stack_test.rb +48 -0
- data/test/source_test.rb +131 -27
- data/test/template_test.rb +120 -145
- data/test/templates/layout.html.rb +1 -1
- data/undies.gemspec +1 -1
- metadata +27 -23
- data/lib/undies/element_stack.rb +0 -35
- data/lib/undies/node_list.rb +0 -35
- data/lib/undies/partial.rb +0 -23
- data/lib/undies/partial_data.rb +0 -32
- data/test/element_stack_test.rb +0 -77
- data/test/fixtures/partial_template.rb +0 -6
- data/test/node_list_test.rb +0 -69
- data/test/partial_data_test.rb +0 -100
- data/test/partial_test.rb +0 -63
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,21 +1,26 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
undies (
|
4
|
+
undies (2.0.0)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: http://rubygems.org/
|
8
8
|
specs:
|
9
|
-
|
9
|
+
ansi (1.4.1)
|
10
|
+
assert (0.7.3)
|
11
|
+
assert-view (~> 0.5)
|
12
|
+
assert-view (0.5.0)
|
13
|
+
ansi (~> 1.3)
|
14
|
+
undies (~> 2.0)
|
10
15
|
rake (0.9.2)
|
11
|
-
|
12
|
-
leftright (~> 0.9.0)
|
16
|
+
ruby-prof (0.10.8)
|
13
17
|
|
14
18
|
PLATFORMS
|
15
19
|
ruby
|
16
20
|
|
17
21
|
DEPENDENCIES
|
22
|
+
assert (~> 0.7.3)
|
18
23
|
bundler (~> 1.0)
|
19
24
|
rake (~> 0.9.2)
|
20
|
-
|
25
|
+
ruby-prof
|
21
26
|
undies!
|
data/Rakefile
CHANGED
data/bench/large.html.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
_html {
|
2
|
+
_head {}
|
3
|
+
_body {
|
4
|
+
|
5
|
+
10.times do
|
6
|
+
_ "Yo"
|
7
|
+
_ "Yo"
|
8
|
+
_ "Yo"
|
9
|
+
_ "Yo"
|
10
|
+
_ "Yo"
|
11
|
+
|
12
|
+
__ "YoYo"
|
13
|
+
__ "YoYo"
|
14
|
+
__ "YoYo"
|
15
|
+
__ "YoYo"
|
16
|
+
__ "YoYo"
|
17
|
+
|
18
|
+
_br
|
19
|
+
_br
|
20
|
+
_br
|
21
|
+
_br
|
22
|
+
_br
|
23
|
+
|
24
|
+
_div { _ "Hi" }
|
25
|
+
_div { _ "Hi" }
|
26
|
+
_div { _ "Hi" }
|
27
|
+
_div { _ "Hi" }
|
28
|
+
_div { _ "Hi" }
|
29
|
+
end
|
30
|
+
|
31
|
+
}
|
32
|
+
}
|
data/bench/procs.rb
ADDED
@@ -0,0 +1,106 @@
|
|
1
|
+
@small_proc = Proc.new do
|
2
|
+
_html {
|
3
|
+
_head {}
|
4
|
+
_body {
|
5
|
+
|
6
|
+
1.times do
|
7
|
+
_ "Yo"
|
8
|
+
_ "Yo"
|
9
|
+
_ "Yo"
|
10
|
+
_ "Yo"
|
11
|
+
_ "Yo"
|
12
|
+
|
13
|
+
__ "YoYo"
|
14
|
+
__ "YoYo"
|
15
|
+
__ "YoYo"
|
16
|
+
__ "YoYo"
|
17
|
+
__ "YoYo"
|
18
|
+
|
19
|
+
_br
|
20
|
+
_br
|
21
|
+
_br
|
22
|
+
_br
|
23
|
+
_br
|
24
|
+
|
25
|
+
_div { _ "Hi" }
|
26
|
+
_div { _ "Hi" }
|
27
|
+
_div { _ "Hi" }
|
28
|
+
_div { _ "Hi" }
|
29
|
+
_div { _ "Hi" }
|
30
|
+
end
|
31
|
+
|
32
|
+
}
|
33
|
+
}
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
@large_proc = Proc.new do
|
38
|
+
_html {
|
39
|
+
_head {}
|
40
|
+
_body {
|
41
|
+
|
42
|
+
10.times do
|
43
|
+
_ "Yo"
|
44
|
+
_ "Yo"
|
45
|
+
_ "Yo"
|
46
|
+
_ "Yo"
|
47
|
+
_ "Yo"
|
48
|
+
|
49
|
+
__ "YoYo"
|
50
|
+
__ "YoYo"
|
51
|
+
__ "YoYo"
|
52
|
+
__ "YoYo"
|
53
|
+
__ "YoYo"
|
54
|
+
|
55
|
+
_br
|
56
|
+
_br
|
57
|
+
_br
|
58
|
+
_br
|
59
|
+
_br
|
60
|
+
|
61
|
+
_div { _ "Hi" }
|
62
|
+
_div { _ "Hi" }
|
63
|
+
_div { _ "Hi" }
|
64
|
+
_div { _ "Hi" }
|
65
|
+
_div { _ "Hi" }
|
66
|
+
end
|
67
|
+
|
68
|
+
}
|
69
|
+
}
|
70
|
+
end
|
71
|
+
|
72
|
+
|
73
|
+
@verylarge_proc = Proc.new do
|
74
|
+
_html {
|
75
|
+
_head {}
|
76
|
+
_body {
|
77
|
+
|
78
|
+
1000.times do
|
79
|
+
_ "Yo"
|
80
|
+
_ "Yo"
|
81
|
+
_ "Yo"
|
82
|
+
_ "Yo"
|
83
|
+
_ "Yo"
|
84
|
+
|
85
|
+
__ "YoYo"
|
86
|
+
__ "YoYo"
|
87
|
+
__ "YoYo"
|
88
|
+
__ "YoYo"
|
89
|
+
__ "YoYo"
|
90
|
+
|
91
|
+
_br
|
92
|
+
_br
|
93
|
+
_br
|
94
|
+
_br
|
95
|
+
_br
|
96
|
+
|
97
|
+
_div { _ "Hi" }
|
98
|
+
_div { _ "Hi" }
|
99
|
+
_div { _ "Hi" }
|
100
|
+
_div { _ "Hi" }
|
101
|
+
_div { _ "Hi" }
|
102
|
+
end
|
103
|
+
|
104
|
+
}
|
105
|
+
}
|
106
|
+
end
|
data/bench/profiler.rb
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'ruby-prof'
|
2
|
+
require 'undies'
|
3
|
+
require 'bench/procs'
|
4
|
+
|
5
|
+
file = "bench/#{ARGV[0] || 'large'}.html.rb"
|
6
|
+
proc = eval("@#{ARGV[0] || 'large'}_proc")
|
7
|
+
result = nil
|
8
|
+
|
9
|
+
File.open('bench/output.txt', 'a+') do |outstream|
|
10
|
+
|
11
|
+
output = Undies::Output.new(outstream, :pp => 2)
|
12
|
+
|
13
|
+
result = RubyProf.profile do
|
14
|
+
50.times do
|
15
|
+
Undies::Template.new(Undies::Source.new(File.expand_path(file)), {}, output)
|
16
|
+
end
|
17
|
+
50.times do
|
18
|
+
Undies::Template.new(Undies::Source.new(proc), {}, output)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
printer = RubyProf::FlatPrinter.new(result).print(STDOUT, :min_percent => 1)
|
25
|
+
# printer = RubyProf::GraphPrinter.new(result).print(STDOUT)
|
data/bench/small.html.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
_html {
|
2
|
+
_head {}
|
3
|
+
_body {
|
4
|
+
|
5
|
+
1.times do
|
6
|
+
_ "Yo"
|
7
|
+
_ "Yo"
|
8
|
+
_ "Yo"
|
9
|
+
_ "Yo"
|
10
|
+
_ "Yo"
|
11
|
+
|
12
|
+
__ "YoYo"
|
13
|
+
__ "YoYo"
|
14
|
+
__ "YoYo"
|
15
|
+
__ "YoYo"
|
16
|
+
__ "YoYo"
|
17
|
+
|
18
|
+
_br
|
19
|
+
_br
|
20
|
+
_br
|
21
|
+
_br
|
22
|
+
_br
|
23
|
+
|
24
|
+
_div { _ "Hi" }
|
25
|
+
_div { _ "Hi" }
|
26
|
+
_div { _ "Hi" }
|
27
|
+
_div { _ "Hi" }
|
28
|
+
_div { _ "Hi" }
|
29
|
+
end
|
30
|
+
|
31
|
+
}
|
32
|
+
}
|
@@ -0,0 +1,32 @@
|
|
1
|
+
_html {
|
2
|
+
_head {}
|
3
|
+
_body {
|
4
|
+
|
5
|
+
1000.times do
|
6
|
+
_ "Yo"
|
7
|
+
_ "Yo"
|
8
|
+
_ "Yo"
|
9
|
+
_ "Yo"
|
10
|
+
_ "Yo"
|
11
|
+
|
12
|
+
__ "YoYo"
|
13
|
+
__ "YoYo"
|
14
|
+
__ "YoYo"
|
15
|
+
__ "YoYo"
|
16
|
+
__ "YoYo"
|
17
|
+
|
18
|
+
_br
|
19
|
+
_br
|
20
|
+
_br
|
21
|
+
_br
|
22
|
+
_br
|
23
|
+
|
24
|
+
_div { _ "Hi" }
|
25
|
+
_div { _ "Hi" }
|
26
|
+
_div { _ "Hi" }
|
27
|
+
_div { _ "Hi" }
|
28
|
+
_div { _ "Hi" }
|
29
|
+
end
|
30
|
+
|
31
|
+
}
|
32
|
+
}
|
data/lib/undies/element.rb
CHANGED
@@ -1,34 +1,53 @@
|
|
1
1
|
require 'undies/node'
|
2
|
-
require 'undies/node_list'
|
3
|
-
require 'undies/element_stack'
|
4
2
|
|
5
3
|
module Undies
|
6
4
|
class Element < Node
|
7
5
|
|
8
|
-
|
9
|
-
|
6
|
+
# have as many methods to the class level as possilbe to keep from
|
7
|
+
# polluting the public instance methods and to maximize the effectiveness
|
8
|
+
# of the Element#method_missing logic
|
9
|
+
|
10
|
+
def self.html_attrs(attrs="", ns=nil)
|
11
|
+
if attrs.kind_of? ::Hash
|
12
|
+
attrs.empty? ? '' : (attrs.keys.map(&:to_s).sort.map(&:to_sym).inject('') do |html, key|
|
13
|
+
ak = ns ? "#{ns}_#{key}" : key.to_s
|
14
|
+
av = attrs[key]
|
15
|
+
html + (av.kind_of?(::Hash) ? html_attrs(av, ak) : " #{ak}=\"#{av}\"")
|
16
|
+
end)
|
17
|
+
else
|
18
|
+
attrs.to_s
|
19
|
+
end
|
20
|
+
end
|
10
21
|
|
11
|
-
def
|
12
|
-
|
13
|
-
|
22
|
+
def self.content(element)
|
23
|
+
nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.flush(output, element)
|
27
|
+
output.pp_use_indent = true
|
28
|
+
output << element.instance_variable_get("@start_tag")
|
29
|
+
if (cbs = element.instance_variable_get("@content_blocks")).size > 0
|
30
|
+
output.pp_level += 1
|
31
|
+
output.pp_use_indent = false
|
32
|
+
cbs.each{ |content| content.call }
|
33
|
+
output.flush
|
34
|
+
output.pp_level -= 1
|
14
35
|
end
|
36
|
+
output << element.instance_variable_get("@end_tag") if element.instance_variable_get("@end_tag")
|
37
|
+
output.pp_use_indent = true
|
38
|
+
end
|
39
|
+
|
40
|
+
def initialize(name, attrs={}, &block)
|
15
41
|
if !attrs.kind_of?(::Hash)
|
16
42
|
raise ArgumentError, "#{name.inspect} attrs must be provided as a Hash."
|
17
43
|
end
|
18
|
-
super(@___nodes = NodeList.new)
|
19
|
-
@stack = stack
|
20
|
-
@content_writes = 0
|
21
|
-
@___name = name.to_s
|
22
|
-
@___attrs = attrs
|
23
|
-
self.___content = block
|
24
|
-
end
|
25
|
-
|
26
|
-
def start_tag
|
27
|
-
"<#{@___name}#{html_attrs(@___attrs)}" + (@content_writes > 0 ? ">" : " />")
|
28
|
-
end
|
29
44
|
|
30
|
-
|
31
|
-
@
|
45
|
+
@name = name.to_s
|
46
|
+
@attrs = attrs
|
47
|
+
@content_blocks = []
|
48
|
+
@content_blocks << block if block
|
49
|
+
@start_tag = start_tag
|
50
|
+
@end_tag = end_tag
|
32
51
|
end
|
33
52
|
|
34
53
|
# CSS proxy methods ============================================
|
@@ -37,9 +56,13 @@ module Undies
|
|
37
56
|
|
38
57
|
def method_missing(meth, *args, &block)
|
39
58
|
if meth.to_s =~ ID_METH_REGEX
|
40
|
-
|
59
|
+
proxy($1, args.first || {}, block) do |value|
|
60
|
+
@attrs.merge!(:id => value)
|
61
|
+
end
|
41
62
|
elsif meth.to_s =~ CLASS_METH_REGEX
|
42
|
-
|
63
|
+
proxy($1, args.first || {}, block) do |value|
|
64
|
+
@attrs[:class] = [@attrs[:class], value].compact.join(' ')
|
65
|
+
end
|
43
66
|
else
|
44
67
|
super
|
45
68
|
end
|
@@ -55,59 +78,36 @@ module Undies
|
|
55
78
|
# ==============================================================
|
56
79
|
|
57
80
|
def ==(other)
|
58
|
-
other.
|
59
|
-
other.
|
60
|
-
other.
|
81
|
+
other.instance_variable_get("@name") == @name &&
|
82
|
+
other.instance_variable_get("@attrs") == @attrs &&
|
83
|
+
other.instance_variable_get("@nodes") == @nodes
|
61
84
|
end
|
62
85
|
|
86
|
+
# overriding this because the base Node class defines a 'to_s' method that
|
87
|
+
# needs to be honored
|
63
88
|
def to_str(*args)
|
64
89
|
"Undies::Element:#{self.object_id} " +
|
65
|
-
"@name=#{
|
90
|
+
"@name=#{@name.inspect}, @attrs=#{@attrs.inspect}, @nodes=#{@nodes.inspect}"
|
66
91
|
end
|
67
92
|
alias_method :inspect, :to_str
|
68
93
|
|
69
|
-
def to_ary(*args)
|
70
|
-
self.___nodes
|
71
|
-
end
|
72
|
-
|
73
|
-
protected
|
74
|
-
|
75
|
-
def html_attrs(attrs={})
|
76
|
-
raise ArgumentError unless attrs.kind_of? ::Hash
|
77
|
-
if attrs.empty?
|
78
|
-
''
|
79
|
-
else
|
80
|
-
' '+attrs.
|
81
|
-
sort {|a,b| a[0].to_s <=> b[0].to_s}.
|
82
|
-
collect {|k_v| "#{k_v[0]}=\"#{k_v[1]}\""}.
|
83
|
-
join(' ').
|
84
|
-
strip
|
85
|
-
end
|
86
|
-
end
|
87
|
-
|
88
94
|
private
|
89
95
|
|
90
|
-
def
|
91
|
-
|
92
|
-
|
93
|
-
|
96
|
+
def proxy(value, attrs, content_block)
|
97
|
+
yield value if block_given?
|
98
|
+
@attrs.merge!(attrs)
|
99
|
+
@content_blocks << content_block if content_block
|
100
|
+
@start_tag = start_tag
|
101
|
+
@end_tag = end_tag
|
94
102
|
self
|
95
103
|
end
|
96
104
|
|
97
|
-
def
|
98
|
-
self.
|
99
|
-
self.___attrs.merge!(attrs)
|
100
|
-
self.___content = block
|
101
|
-
self
|
105
|
+
def start_tag
|
106
|
+
"<#{@name}#{self.class.html_attrs(@attrs)}" + (@content_blocks.size > 0 ? ">" : " />")
|
102
107
|
end
|
103
108
|
|
104
|
-
def
|
105
|
-
|
106
|
-
@content_writes += 1
|
107
|
-
@stack.push(self)
|
108
|
-
block.call
|
109
|
-
@stack.pop
|
110
|
-
end
|
109
|
+
def end_tag
|
110
|
+
@content_blocks.size > 0 ? "</#{@name}>" : nil
|
111
111
|
end
|
112
112
|
|
113
113
|
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Undies
|
2
|
+
|
3
|
+
class Source; end
|
4
|
+
|
5
|
+
class NamedSource
|
6
|
+
|
7
|
+
attr_accessor :file, :opts, :proc
|
8
|
+
|
9
|
+
def initialize(*args, &block)
|
10
|
+
args << block if block
|
11
|
+
self.args = args
|
12
|
+
end
|
13
|
+
|
14
|
+
def ==(other_named_source)
|
15
|
+
self.file == other_named_source.file &&
|
16
|
+
self.opts == other_named_source.opts &&
|
17
|
+
self.proc == other_named_source.proc
|
18
|
+
end
|
19
|
+
|
20
|
+
def args=(values)
|
21
|
+
self.proc, self.opts, self.file = [
|
22
|
+
values.last.kind_of?(::Proc) ? values.pop : nil,
|
23
|
+
values.last.kind_of?(::Hash) ? values.pop : {},
|
24
|
+
values.last.kind_of?(::String) ? values.pop : nil
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
def args
|
29
|
+
[self.file, self.opts, self.proc]
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
# singleton accessors for named sources
|
35
|
+
|
36
|
+
def self.named_sources
|
37
|
+
@@sources ||= {}
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.named_source(name, *args, &block)
|
41
|
+
if args.empty? && block.nil?
|
42
|
+
self.named_sources[name]
|
43
|
+
else
|
44
|
+
self.named_sources[name] = Undies::NamedSource.new(*args, &block)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.source(name)
|
49
|
+
if ns = self.named_source(name)
|
50
|
+
Undies::Source.new(ns)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/undies/node.rb
CHANGED
@@ -1,37 +1,29 @@
|
|
1
1
|
module Undies
|
2
|
-
class Node
|
3
2
|
|
4
|
-
|
3
|
+
class Node
|
5
4
|
|
6
|
-
|
7
|
-
|
8
|
-
|
5
|
+
# have as many methods to the class level as possilbe to keep from
|
6
|
+
# polluting the public instance methods and to maximize the effectiveness
|
7
|
+
# of the Element#method_missing logic
|
9
8
|
|
10
|
-
def
|
11
|
-
|
9
|
+
def self.content(node)
|
10
|
+
node.instance_variable_get("@content")
|
12
11
|
end
|
13
12
|
|
14
|
-
def
|
15
|
-
|
13
|
+
def self.flush(output, node)
|
14
|
+
output << self.content(node)
|
16
15
|
end
|
17
16
|
|
18
|
-
def
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
].compact.collect do |item|
|
23
|
-
pretty_print(item, pp_level, pp_indent)
|
24
|
-
end.join
|
17
|
+
def initialize(content)
|
18
|
+
@start_tag = nil
|
19
|
+
@end_tag = nil
|
20
|
+
@content = content
|
25
21
|
end
|
26
22
|
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
data.to_s(level+1, indent)
|
32
|
-
else
|
33
|
-
indent ? "#{' '*level*indent}#{data}\n" : data
|
34
|
-
end
|
23
|
+
def ==(other_node)
|
24
|
+
self.class.content(self) == other_node.class.content(other_node) &&
|
25
|
+
self.instance_variable_get("@start_tag") == other_node.instance_variable_get("@start_tag") &&
|
26
|
+
self.instance_variable_get("@end_tag") == other_node.instance_variable_get("@end_tag")
|
35
27
|
end
|
36
28
|
|
37
29
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Undies
|
2
|
+
|
3
|
+
class NodeBuffer < ::Array
|
4
|
+
|
5
|
+
# a node buffer is a FIFO used to, well, buffer node data for output.
|
6
|
+
# nodes are pushed on the stack for processing and flushed to output
|
7
|
+
# when pulled. empty the buffer by flushing it to output.
|
8
|
+
|
9
|
+
# the buffer allows for dynamic node handling while limiting memory
|
10
|
+
# bloat. the Output handler ensures that only 1 node is buffered
|
11
|
+
# in memory at any given time by pulling the previous node to output
|
12
|
+
# before pushing the next node for processing.
|
13
|
+
|
14
|
+
def initialize(*args)
|
15
|
+
# always initialize empty
|
16
|
+
super()
|
17
|
+
end
|
18
|
+
|
19
|
+
def push(node)
|
20
|
+
super
|
21
|
+
node
|
22
|
+
end
|
23
|
+
|
24
|
+
def pull(output)
|
25
|
+
if (node = self.shift)
|
26
|
+
node.class.flush(output, node)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def flush(output)
|
31
|
+
self.pull(output) while self.size > 0
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,64 @@
|
|
1
|
+
require 'undies/node'
|
2
|
+
require 'undies/element'
|
3
|
+
require 'undies/node_buffer'
|
4
|
+
|
5
|
+
module Undies
|
6
|
+
class Output
|
7
|
+
|
8
|
+
attr_reader :io, :options, :pp, :node_buffer
|
9
|
+
|
10
|
+
# the output class wraps an IO stream, gathers pretty printing options,
|
11
|
+
# and handles buffering nodes and pretty printing to the stream
|
12
|
+
|
13
|
+
def initialize(io, opts={})
|
14
|
+
@io = io
|
15
|
+
self.options = opts
|
16
|
+
@node_buffer = NodeBuffer.new
|
17
|
+
end
|
18
|
+
|
19
|
+
def options=(opts)
|
20
|
+
if !opts.kind_of?(::Hash)
|
21
|
+
raise ArgumentError, "please provide a hash to set options with"
|
22
|
+
end
|
23
|
+
|
24
|
+
# setup any pretty printing
|
25
|
+
@pp = opts[:pp]
|
26
|
+
self.pp_level = 0
|
27
|
+
self.pp_use_indent = true
|
28
|
+
|
29
|
+
@options = opts
|
30
|
+
end
|
31
|
+
|
32
|
+
def pp_level
|
33
|
+
@pp_level
|
34
|
+
end
|
35
|
+
|
36
|
+
def pp_level=(value)
|
37
|
+
@pp_indent = @pp ? "\n#{' '*value*@pp}" : ""
|
38
|
+
@pp_level = value
|
39
|
+
end
|
40
|
+
|
41
|
+
def pp_use_indent=(value)
|
42
|
+
@pp_use_indent = value
|
43
|
+
end
|
44
|
+
|
45
|
+
def <<(data)
|
46
|
+
@io << (@pp_use_indent ? "#{@pp_indent}#{data}" : data.to_s)
|
47
|
+
end
|
48
|
+
|
49
|
+
def node(data="")
|
50
|
+
self.node_buffer.pull(self)
|
51
|
+
self.node_buffer.push(Node.new(data))
|
52
|
+
end
|
53
|
+
|
54
|
+
def element(name, attrs={}, &block)
|
55
|
+
self.node_buffer.pull(self)
|
56
|
+
self.node_buffer.push(Element.new(name, attrs, &block))
|
57
|
+
end
|
58
|
+
|
59
|
+
def flush
|
60
|
+
self.node_buffer.flush(self)
|
61
|
+
end
|
62
|
+
|
63
|
+
end
|
64
|
+
end
|