garterbelt 0.0.2

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 (57) hide show
  1. data/.document +5 -0
  2. data/.rspec +1 -0
  3. data/Gemfile +16 -0
  4. data/Gemfile.lock +38 -0
  5. data/LICENSE.txt +20 -0
  6. data/README.rdoc +21 -0
  7. data/Rakefile +46 -0
  8. data/TODO +3 -0
  9. data/VERSION +1 -0
  10. data/garterbelt.gemspec +165 -0
  11. data/lib/garterbelt.rb +23 -0
  12. data/lib/page.rb +46 -0
  13. data/lib/renderers/cache.rb +35 -0
  14. data/lib/renderers/closed_tag.rb +60 -0
  15. data/lib/renderers/comment.rb +14 -0
  16. data/lib/renderers/content_rendering.rb +41 -0
  17. data/lib/renderers/content_tag.rb +36 -0
  18. data/lib/renderers/doctype.rb +24 -0
  19. data/lib/renderers/renderer.rb +33 -0
  20. data/lib/renderers/text.rb +28 -0
  21. data/lib/renderers/xml.rb +9 -0
  22. data/lib/stocking.rb +11 -0
  23. data/lib/support/string.rb +165 -0
  24. data/lib/view.rb +341 -0
  25. data/spec/benchmark/templates/erector.rb +37 -0
  26. data/spec/benchmark/templates/garterbelt.rb +37 -0
  27. data/spec/benchmark/vs_erector.rb +53 -0
  28. data/spec/garterbelt_spec.rb +49 -0
  29. data/spec/integration/expectations/general_view.html +17 -0
  30. data/spec/integration/expectations/variables/view_with_user_and_params.html +23 -0
  31. data/spec/integration/expectations/variables/view_with_user_email.html +23 -0
  32. data/spec/integration/expectations/view_partial_nest.html +24 -0
  33. data/spec/integration/expectations/view_with_tags.html +19 -0
  34. data/spec/integration/templates/view_partial_nest.rb +22 -0
  35. data/spec/integration/templates/view_with_cache.rb +30 -0
  36. data/spec/integration/templates/view_with_partial.rb +36 -0
  37. data/spec/integration/templates/view_with_partial_2.rb +36 -0
  38. data/spec/integration/templates/view_with_tags.rb +26 -0
  39. data/spec/integration/templates/view_with_vars.rb +32 -0
  40. data/spec/integration/view_spec.rb +57 -0
  41. data/spec/page_spec.rb +99 -0
  42. data/spec/renderers/cache_spec.rb +85 -0
  43. data/spec/renderers/closed_tag_spec.rb +172 -0
  44. data/spec/renderers/comment_spec.rb +68 -0
  45. data/spec/renderers/content_tag_spec.rb +150 -0
  46. data/spec/renderers/doctype_spec.rb +46 -0
  47. data/spec/renderers/text_spec.rb +68 -0
  48. data/spec/spec_helper.rb +17 -0
  49. data/spec/support/mock_view.rb +14 -0
  50. data/spec/support/puters.rb +10 -0
  51. data/spec/view/view_basics_spec.rb +106 -0
  52. data/spec/view/view_caching_spec.rb +132 -0
  53. data/spec/view/view_partial_spec.rb +63 -0
  54. data/spec/view/view_rails_type_helpers.rb +148 -0
  55. data/spec/view/view_render_spec.rb +408 -0
  56. data/spec/view/view_variables_spec.rb +159 -0
  57. metadata +367 -0
@@ -0,0 +1,172 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Garterbelt::ClosedTag do
4
+ ClosedTag = Garterbelt::ClosedTag unless defined?(ClosedTag)
5
+
6
+ before do
7
+ @output = ''
8
+ @view = mock(:output => @output, :level => 2)
9
+ end
10
+
11
+ describe 'initialize' do
12
+ it 'requires a type' do
13
+ lambda{ ClosedTag.new({:view => @view}) }.should raise_error(ArgumentError, ":type required in initialization options")
14
+ end
15
+
16
+ it 'requires a view' do
17
+ lambda{ ClosedTag.new({:type => :input}) }.should raise_error(ArgumentError, ":view required in initialization options")
18
+ end
19
+
20
+ it 'store the type as an attribute' do
21
+ ClosedTag.new({:type => :input, :view => @view}).type.should == :input
22
+ end
23
+
24
+ it 'attributes should be empty by default' do
25
+ ClosedTag.new(:type => :input, :view => @view).attributes.should == {}
26
+ end
27
+
28
+ it 'sets the attributes' do
29
+ ClosedTag.new(:type => :input, :attributes => {:foo => :bar}, :view => @view).attributes.should == {:foo => :bar}
30
+ end
31
+
32
+ it 'extracts css_class into its own variable' do
33
+ ClosedTag.new(:type => :input, :attributes => {:class => :foo}, :view => @view).css_class.should == [:foo]
34
+ end
35
+ end
36
+
37
+ describe 'pooling' do
38
+ it 'include RuPol::Swimsuit' do
39
+ ClosedTag.ancestors.should include(RuPol::Swimsuit)
40
+ end
41
+
42
+ it 'has a really large max_pool_size' do
43
+ ClosedTag._pool.max_size.should == 10000
44
+ end
45
+ end
46
+
47
+ describe 'method chaining' do
48
+ before do
49
+ @tag = ClosedTag.new(:type => :input, :view => @view)
50
+ end
51
+
52
+ describe '#id' do
53
+ it 'adds an id attribute' do
54
+ @tag.id(:foo).attributes[:id].should == :foo
55
+ end
56
+
57
+ it 'raises an argument error if passed an array or something non-stringy' do
58
+ lambda{ @tag.id([:foo, :bar]) }.should raise_error(ArgumentError, "Id must be a String or Symbol")
59
+ end
60
+
61
+ it 'returns self' do
62
+ @tag.id(:foo).should === @tag
63
+ end
64
+ end
65
+
66
+ describe '#c' do
67
+ it 'adds the value to the css_class' do
68
+ @tag.c(:foo).css_class.should == [:foo]
69
+ end
70
+
71
+ it 'will not overwrite existing css classes' do
72
+ @tag.c(:foo).css_class.should == [:foo]
73
+ @tag.c(:bar).css_class.should == [:foo, :bar]
74
+ end
75
+
76
+ it 'takes any number of arguments' do
77
+ @tag.c(:foo, :bar).css_class.should == [:foo, :bar]
78
+ end
79
+
80
+ it 'returns self' do
81
+ @tag.c(:foo, :bar).should === @tag
82
+ end
83
+ end
84
+ end
85
+
86
+ describe 'view usage' do
87
+ before do
88
+ @tag = ClosedTag.new(:type => :input, :view => @view)
89
+ end
90
+
91
+ it 'uses its output' do
92
+ @tag.output.should == @output
93
+ end
94
+
95
+ it 'uses its level' do
96
+ @tag.level.should == 2
97
+ end
98
+ end
99
+
100
+
101
+ describe 'rendering' do
102
+ before do
103
+ @tag = ClosedTag.new(
104
+ :type => :input,
105
+ :attributes => {:class => :foo_bar, :thing => :thong},
106
+ :view => @view
107
+ )
108
+ end
109
+
110
+ it 'indent corresponding to the view level' do
111
+ @tag.indent.should == " "
112
+ @tag.stub(:level).and_return(1)
113
+ @tag.indent.should == " "
114
+ @tag.stub(:level).and_return(0)
115
+ @tag.indent.should == ""
116
+ end
117
+
118
+ describe '#rendered_attributes' do
119
+ it 'includes the css_class' do
120
+ @tag.rendered_attributes.should include "class=\"foo_bar\""
121
+ end
122
+
123
+ it 'multiple classes are separated by a space' do
124
+ @tag.c(:more_classy)
125
+ @tag.rendered_attributes.should include "class=\"foo_bar more_classy\""
126
+ end
127
+
128
+ it 'include other key/value pairs' do
129
+ @tag.rendered_attributes.should include "thing=\"thong\""
130
+ end
131
+
132
+ it 'does not include attributes with nil or false values' do
133
+ @tag.attributes[:checked] = false
134
+ @tag.attributes[:nily] = nil
135
+ rendered = @tag.rendered_attributes
136
+ rendered.should_not include "checked=\"\""
137
+ rendered.should_not include "nily=\"\""
138
+ end
139
+
140
+ it 'should subs out double quotes from attributes' do
141
+ @tag.attributes[:foo_title] = 'I am not "sure" if this will work'
142
+ @tag.rendered_attributes.should include "I am not 'sure' if this will work"
143
+ end
144
+ end
145
+
146
+ describe 'integration' do
147
+ before do
148
+ @str = @tag.render
149
+ end
150
+
151
+ it 'starts with the indent' do
152
+ @str.should match /^\W{4}</
153
+ end
154
+
155
+ it 'includes the full tag' do
156
+ @str.should match /<input[^>]*>/
157
+ end
158
+
159
+ it 'includes the attributes' do
160
+ @str.should match /<input#{@tag.rendered_attributes}>/
161
+ end
162
+
163
+ it 'ends with the closing tag and a line break' do
164
+ @str.should match /\n$/
165
+ end
166
+
167
+ it 'adds the string to the output' do
168
+ @output.should include @str
169
+ end
170
+ end
171
+ end
172
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Garterbelt::Comment do
4
+ before :all do
5
+ @view = MockView.new
6
+ end
7
+
8
+ describe 'basics' do
9
+ it 'is decends from Renderer' do
10
+ Garterbelt::Comment.ancestors.should include Garterbelt::Renderer
11
+ end
12
+
13
+ it 'has conent' do
14
+ comment = Garterbelt::Comment.new(:view => @view, :content => "Initializing ...")
15
+ comment.content.should == "Initializing ..."
16
+ comment.content = "foo"
17
+ comment.content.should == "foo"
18
+ end
19
+
20
+ it 'raises an error when initializing without content' do
21
+ lambda{ Garterbelt::Comment.new(:view => @view) }.should raise_error(
22
+ ArgumentError, ":content option required for Garterbelt::Comment initialization"
23
+ )
24
+ end
25
+
26
+ it 'has a smaller pool size' do
27
+ Garterbelt::Comment._pool.max_size.should == 1000
28
+ end
29
+ end
30
+
31
+ describe 'render' do
32
+ before do
33
+ @view = MockView.new
34
+ @comment = Garterbelt::Comment.new(:view => @view, :content => 'Render me')
35
+ end
36
+
37
+ it 'raises an error with block content' do
38
+ @comment.content = lambda { puts "foo" }
39
+ lambda{ @comment.render }.should raise_error(ArgumentError, "Garterbelt::Comment does not take block content")
40
+ end
41
+
42
+ it 'it adds the content to the output' do
43
+ @comment.render
44
+ @view.output.should include "Render me"
45
+ end
46
+
47
+ it 'builds the right header tag' do
48
+ @comment.render
49
+ @view.output.should match /<!-- Render me/
50
+ end
51
+
52
+ it 'builds the right footer tag' do
53
+ @comment.render
54
+ @view.output.should match /Render me -->/
55
+ end
56
+
57
+ it 'indents to the view level' do
58
+ @comment.render
59
+ @view.output.should match /^\W{4}<!-- Render me/
60
+ end
61
+
62
+ it 'does not escape the content' do
63
+ @comment.content = "<div>foo</div>"
64
+ @comment.render
65
+ @view.output.should include "<div>foo</div>"
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,150 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Garterbelt::ContentTag do
4
+ ContentTag = Garterbelt::ContentTag unless defined?(ContentTag)
5
+
6
+ before do
7
+ @view = MockView.new
8
+ @output = @view.output
9
+ @params = {:type => :p, :attributes => {:class => 'classy'}, :view => @view}
10
+ @tag = ContentTag.new(@params)
11
+ end
12
+
13
+ describe "basics" do
14
+ it 'takes a content option' do
15
+ ContentTag.new(@params.merge(:content => 'My great content')).content.should == "My great content"
16
+ end
17
+
18
+ it 'takes a block as content' do
19
+ ContentTag.new(@params) do
20
+ @output << "This is block content"
21
+ end.content.class.should == Proc
22
+ end
23
+
24
+ it 'will override option content in favor of block content' do
25
+ ContentTag.new(@params.merge(:content => 'not the block')) do
26
+ @output << "This is block content"
27
+ end.content.class.should == Proc
28
+ end
29
+
30
+ it 'inherits a really large max_pool_size' do
31
+ ContentTag._pool.max_size.should == 10000
32
+ end
33
+ end
34
+
35
+ describe 'chaining' do
36
+ describe 'id' do
37
+ it 'takes a block and sets it to content' do
38
+ @tag.id(:foo) do
39
+ @output << "This is block content"
40
+ end
41
+ @tag.content.class.should == Proc
42
+ end
43
+
44
+ it 'returns self' do
45
+ @tag.id(:foo).should === @tag
46
+ end
47
+ end
48
+
49
+ describe 'c' do
50
+ it 'takes a block and sets it to content' do
51
+ @tag.c(:foo) do
52
+ @output << "This is block content"
53
+ end
54
+ @tag.content.class.should == Proc
55
+ end
56
+
57
+ it 'returns self' do
58
+ @tag.c(:foo).should === @tag
59
+ end
60
+ end
61
+ end
62
+
63
+ describe 'rendering' do
64
+ describe 'tags' do
65
+ before do
66
+ @tag.content = 'My string content'
67
+ @tag.render
68
+ end
69
+
70
+ it 'indents the beginning tag correctly' do
71
+ @output.should match /^ <p/
72
+ end
73
+
74
+ it 'renders the beginning tag correctly' do
75
+ @output.should include "<p class=\"classy\">"
76
+ end
77
+
78
+ it 'indents the ending tag correctly' do
79
+ @output.should match /^ <\/p/
80
+ end
81
+
82
+ it 'renders the ending tag correctly' do
83
+ @output.should include "</p>"
84
+ end
85
+ end
86
+
87
+ describe 'content' do
88
+ describe 'none' do
89
+ it 'works' do
90
+ @tag.content.should be_nil
91
+ @tag.render
92
+ @output.should match " <p class=\"classy\">\n </p>"
93
+ end
94
+ end
95
+
96
+ describe 'string' do
97
+ before do
98
+ @tag.content = "My string content"
99
+ end
100
+
101
+ it 'makes a Text object' do
102
+ Garterbelt::Text.should_receive(:new).and_return('text')
103
+ @tag.render
104
+ end
105
+ end
106
+
107
+ describe 'block' do
108
+ describe 'writing directly to output' do
109
+ before do
110
+ @tag.id(:foo) do
111
+ @output << "Going directly to the source"
112
+ end
113
+ @tag.render
114
+ end
115
+
116
+ it 'adds the content' do
117
+ @output.should include "Going directly to the source"
118
+ end
119
+
120
+ it 'does not indent' do
121
+ @output.should match /^Going/
122
+ end
123
+
124
+ it 'should put the content between the tags' do
125
+ @output.should match /<p.*\nGoing.*<\/p/
126
+ end
127
+ end
128
+
129
+ describe 'adding to the tag buffer' do
130
+ before do
131
+ @b = Garterbelt::ClosedTag.new(:view => @view, :type => :hr, :attributes => {:class => :linear})
132
+ @tag.id(:foo) do
133
+ @view.buffer << @b
134
+ end
135
+ end
136
+
137
+ it 'should add the tag to the buffer' do
138
+ @tag.render
139
+ @view.buffer.should include @b
140
+ end
141
+
142
+ it 'calls render buffer on the view' do
143
+ @view.should_receive(:render_buffer)
144
+ @tag.render
145
+ end
146
+ end
147
+ end
148
+ end
149
+ end
150
+ end
@@ -0,0 +1,46 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Garterbelt::Doctype do
4
+ before :all do
5
+ @view = MockView.new
6
+ end
7
+
8
+ describe 'basics' do
9
+ it 'is decends from ClosedTag' do
10
+ Garterbelt::Doctype.ancestors.should include Garterbelt::ClosedTag
11
+ end
12
+
13
+ it 'has a smaller pool size' do
14
+ Garterbelt::Doctype._pool.max_size.should == 1000
15
+ end
16
+ end
17
+
18
+ describe 'render' do
19
+ before do
20
+ @view = MockView.new
21
+ @doctype = Garterbelt::Doctype.new(:view => @view, :type => :transitional)
22
+ end
23
+
24
+ it 'builds the right tag for type = :transitional' do
25
+ tag = "<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Transitional//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd\">"
26
+ @doctype.render.should include tag
27
+ end
28
+
29
+ it 'builds the right tag for type = :strict' do
30
+ tag = '<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">'
31
+ @doctype.type = :strict
32
+ @doctype.render.should include tag
33
+ end
34
+
35
+ it 'builds the right tag for type = :html5' do
36
+ tag = '<!DOCTYPE html>'
37
+ @doctype.type = :html5
38
+ @doctype.render.should include tag
39
+ end
40
+
41
+ it 'indents to the view level' do
42
+ @doctype.render
43
+ @view.output.should match /^\W{4}<!DOCTYPE/
44
+ end
45
+ end
46
+ end
@@ -0,0 +1,68 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Garterbelt::Text do
4
+ before :all do
5
+ @view = MockView.new
6
+ end
7
+
8
+ describe 'basics' do
9
+ it 'is decends from Renderer' do
10
+ Garterbelt::Text.ancestors.should include Garterbelt::Renderer
11
+ end
12
+
13
+ it 'has conent' do
14
+ text = Garterbelt::Text.new(:view => @view, :content => "Initializing ...")
15
+ text.content.should == "Initializing ..."
16
+ text.content = "foo"
17
+ text.content.should == "foo"
18
+ end
19
+
20
+ it 'raises an error when initializing without content' do
21
+ lambda{ Garterbelt::Text.new(:view => @view) }.should raise_error(
22
+ ArgumentError, ":content option required for Garterbelt::Text initialization"
23
+ )
24
+ end
25
+
26
+ it 'inherits its pool size' do
27
+ Garterbelt::Text._pool.max_size.should == 10000
28
+ end
29
+ end
30
+
31
+ describe 'render' do
32
+ before do
33
+ @view = MockView.new
34
+ @text = Garterbelt::Text.new(:view => @view, :content => 'Render me')
35
+ end
36
+
37
+ it 'raises an error with block content' do
38
+ @text.content = lambda { puts "foo" }
39
+ lambda{ @text.render }.should raise_error(ArgumentError, "Garterbelt::Text does not take block content")
40
+ end
41
+
42
+ it 'it adds the content to the output' do
43
+ @text.render
44
+ @view.output.should include "Render me"
45
+ end
46
+
47
+ it 'indents to the view level' do
48
+ @text.render
49
+ @view.output.should match /^\W{4}Render me\n$/
50
+ end
51
+
52
+ describe 'escaping' do
53
+ it 'escapes if view is set to escape' do
54
+ str = "<a href='/foo.com'>Foo it!</a>"
55
+ text = Garterbelt::Text.new(:view => @view, :content => str)
56
+ text.render.should_not include str
57
+ text.render.should include ERB::Util.html_escape(str)
58
+ end
59
+
60
+ it 'does not escape if the view is set to not escape' do
61
+ str = "<a href='/foo.com'>Foo it!</a>"
62
+ @view.escape = false
63
+ text = Garterbelt::Text.new(:view => @view, :content => str)
64
+ text.render.should include str
65
+ end
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,17 @@
1
+ require 'rubygems'
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
4
+ $LOAD_PATH.unshift(File.dirname(__FILE__))
5
+
6
+ require 'rspec'
7
+ require 'hashie'
8
+ require 'garterbelt'
9
+
10
+ # Requires supporting files with custom matchers and macros, etc,
11
+ # in ./support/ and its subdirectories.
12
+ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each {|f| require f}
13
+ Dir["#{File.dirname(__FILE__)}/integration/templates/**/*.rb"].each {|f| require f}
14
+
15
+ RSpec.configure do |config|
16
+ include PutSpec
17
+ end
@@ -0,0 +1,14 @@
1
+ class MockView
2
+ attr_accessor :output, :buffer, :level, :escape, :cache_store
3
+
4
+ def initialize
5
+ self.buffer = []
6
+ self.output = ""
7
+ self.level ||= 2
8
+ self.escape = true
9
+ self.cache_store = Moneta::Memory.new
10
+ end
11
+
12
+ def render_buffer
13
+ end
14
+ end
@@ -0,0 +1,10 @@
1
+ require 'cgi'
2
+ module PutSpec
3
+ def putspec message
4
+ puts CGI.escapeHTML("#{message.inspect}") if message
5
+ end
6
+
7
+ def hr
8
+ puts "<hr>"
9
+ end
10
+ end
@@ -0,0 +1,106 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
+
3
+ describe Garterbelt::View do
4
+ class BasicView < Garterbelt::View
5
+ def content
6
+ end
7
+
8
+ def alt_content
9
+ end
10
+ end
11
+
12
+ before do
13
+ @view = BasicView.new
14
+ end
15
+
16
+ describe 'pooling' do
17
+ it 'includes the swimsuit' do
18
+ BasicView.ancestors.should include( RuPol::Swimsuit )
19
+ end
20
+ end
21
+
22
+ describe 'attributes' do
23
+ it 'has a tag buffer' do
24
+ @view.buffer.should == []
25
+ @tag = Garterbelt::ContentTag.new(:view => @view, :type => :hr)
26
+ @view.buffer << @tag
27
+ @view.buffer.should == [@tag]
28
+ end
29
+
30
+ describe 'output' do
31
+ it 'has an output' do
32
+ @view.output.should == ""
33
+ end
34
+
35
+ it 'its output is that of the curator if the curator is not self' do
36
+ BasicView.new(:curator => @view).output.should === @view.output
37
+ end
38
+ end
39
+
40
+ describe 'escape' do
41
+ it 'has escape set to true by default' do
42
+ @view.escape.should == true
43
+ end
44
+
45
+ it 'can be set' do
46
+ @view.escape = false
47
+ @view.escape.should == false
48
+ BasicView.new(:escape => false).escape.should == false
49
+ end
50
+ end
51
+
52
+ describe 'level' do
53
+ it 'is 0 by default' do
54
+ @view.level.should == 0
55
+ end
56
+
57
+ it 'can be set via initialization' do
58
+ BasicView.new(:level => 42).level.should == 42
59
+ end
60
+ end
61
+
62
+ describe 'setting the curator: view responsible for displaying the rendered content' do
63
+ before do
64
+ @view.level = 42
65
+ @view.output = "foo"
66
+ @view.buffer = ["bar"]
67
+ @view.escape = false
68
+ @child = BasicView.new(:curator => @view)
69
+ end
70
+
71
+ it 'is self by default' do
72
+ @view.curator.should == @view
73
+ end
74
+
75
+ it 'can be set' do
76
+ @view.curator = BasicView.new
77
+ @view.curator.should_not == @view
78
+ end
79
+
80
+ it 'can be intialized in' do
81
+ BasicView.new(:curator => @view).curator.should == @view
82
+ end
83
+
84
+ describe 'resets other attributes' do
85
+ it 'sets the output to the curator\'s' do
86
+ @child.output.should === @view.output
87
+ end
88
+
89
+ it 'sets the level to the curator\'s' do
90
+ @child.level.should == @view.level
91
+ @child.level.should == 42
92
+ end
93
+
94
+ it 'sets the buffer to the curator\'s' do
95
+ @child.buffer.should === @view.buffer
96
+ end
97
+
98
+ it 'sets the escape to the curator\'s' do
99
+ @child.escape.should == @view.escape
100
+ end
101
+ end
102
+ end
103
+
104
+ end
105
+ end
106
+