inversion 0.1.1 → 0.2.0
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.tar.gz.sig +0 -0
- data/ChangeLog +157 -28
- data/History.rdoc +8 -0
- data/Manifest.txt +2 -3
- data/Rakefile +1 -3
- data/lib/inversion.rb +2 -2
- data/lib/inversion/exceptions.rb +1 -1
- data/lib/inversion/{template/parser.rb → parser.rb} +5 -5
- data/lib/inversion/renderstate.rb +55 -5
- data/lib/inversion/template.rb +5 -3
- data/lib/inversion/template/attrtag.rb +19 -12
- data/lib/inversion/template/begintag.rb +1 -2
- data/lib/inversion/template/configtag.rb +7 -1
- data/lib/inversion/template/containertag.rb +8 -3
- data/lib/inversion/template/elsetag.rb +16 -0
- data/lib/inversion/template/elsiftag.rb +16 -0
- data/lib/inversion/template/escapetag.rb +1 -1
- data/lib/inversion/template/fortag.rb +2 -5
- data/lib/inversion/template/iftag.rb +17 -35
- data/lib/inversion/template/importtag.rb +2 -1
- data/lib/inversion/template/includetag.rb +2 -0
- data/lib/inversion/template/node.rb +1 -1
- data/lib/inversion/template/tag.rb +5 -2
- data/lib/inversion/template/textnode.rb +1 -2
- data/lib/inversion/template/unlesstag.rb +16 -26
- data/lib/inversion/template/yieldtag.rb +3 -8
- data/spec/inversion/{template/parser_spec.rb → parser_spec.rb} +14 -14
- data/spec/inversion/renderstate_spec.rb +242 -165
- data/spec/inversion/template/attrtag_spec.rb +10 -18
- data/spec/inversion/template/begintag_spec.rb +13 -12
- data/spec/inversion/template/configtag_spec.rb +5 -7
- data/spec/inversion/template/elsetag_spec.rb +5 -5
- data/spec/inversion/template/elsiftag_spec.rb +5 -5
- data/spec/inversion/template/endtag_spec.rb +1 -1
- data/spec/inversion/template/fortag_spec.rb +22 -1
- data/spec/inversion/template/iftag_spec.rb +14 -0
- data/spec/inversion/template/rescuetag_spec.rb +4 -4
- data/spec/inversion/template/tag_spec.rb +6 -4
- data/spec/inversion/template/unlesstag_spec.rb +12 -6
- data/spec/inversion/template/yieldtag_spec.rb +2 -2
- metadata +31 -32
- metadata.gz.sig +0 -0
- data/lib/inversion/template/conditionaltag.rb +0 -49
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
BEGIN {
|
5
5
|
require 'pathname'
|
6
|
-
basedir = Pathname( __FILE__ ).dirname.parent.parent
|
6
|
+
basedir = Pathname( __FILE__ ).dirname.parent.parent
|
7
7
|
libdir = basedir + 'lib'
|
8
8
|
|
9
9
|
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
@@ -12,9 +12,9 @@ BEGIN {
|
|
12
12
|
|
13
13
|
require 'rspec'
|
14
14
|
require 'spec/lib/helpers'
|
15
|
-
require 'inversion/
|
15
|
+
require 'inversion/parser'
|
16
16
|
|
17
|
-
describe Inversion::
|
17
|
+
describe Inversion::Parser do
|
18
18
|
|
19
19
|
before( :all ) do
|
20
20
|
setup_logging( :fatal )
|
@@ -26,7 +26,7 @@ describe Inversion::Template::Parser do
|
|
26
26
|
end
|
27
27
|
|
28
28
|
it "parses a string with no PIs as a single text node" do
|
29
|
-
result = Inversion::
|
29
|
+
result = Inversion::Parser.new( @template ).parse( "render unto Caesar" )
|
30
30
|
|
31
31
|
result.should have( 1 ).member
|
32
32
|
result.first.should be_a( Inversion::Template::TextNode )
|
@@ -34,18 +34,18 @@ describe Inversion::Template::Parser do
|
|
34
34
|
end
|
35
35
|
|
36
36
|
it "parses an empty string as a empty tree" do
|
37
|
-
result = Inversion::
|
37
|
+
result = Inversion::Parser.new( @template ).parse( "" )
|
38
38
|
result.should be_empty
|
39
39
|
end
|
40
40
|
|
41
41
|
it "raises a ParseError on mismatched tag brackets" do
|
42
42
|
expect {
|
43
|
-
Inversion::
|
43
|
+
Inversion::Parser.new( @template ).parse( '[?foo bar ?>' )
|
44
44
|
}.to raise_error( Inversion::ParseError, /mismatched start and end brackets/i )
|
45
45
|
end
|
46
46
|
|
47
47
|
it "parses a string with a single 'attr' tag as a single AttrTag node" do
|
48
|
-
result = Inversion::
|
48
|
+
result = Inversion::Parser.new( @template ).parse( "<?attr foo ?>" )
|
49
49
|
|
50
50
|
result.should have( 1 ).member
|
51
51
|
result.first.should be_a( Inversion::Template::AttrTag )
|
@@ -53,7 +53,7 @@ describe Inversion::Template::Parser do
|
|
53
53
|
end
|
54
54
|
|
55
55
|
it "parses a single 'attr' tag surrounded by plain text" do
|
56
|
-
result = Inversion::
|
56
|
+
result = Inversion::Parser.new( @template ).parse( "beginning<?attr foo ?>end" )
|
57
57
|
|
58
58
|
result.should have( 3 ).members
|
59
59
|
result[0].should be_a( Inversion::Template::TextNode )
|
@@ -63,7 +63,7 @@ describe Inversion::Template::Parser do
|
|
63
63
|
end
|
64
64
|
|
65
65
|
it "ignores unknown tags by default" do
|
66
|
-
result = Inversion::
|
66
|
+
result = Inversion::Parser.new( @template ).parse( "Text <?hoooowhat ?>" )
|
67
67
|
|
68
68
|
result.should have( 2 ).members
|
69
69
|
result[0].should be_a( Inversion::Template::TextNode )
|
@@ -73,28 +73,28 @@ describe Inversion::Template::Parser do
|
|
73
73
|
|
74
74
|
it "can raise exceptions on unknown tags" do
|
75
75
|
expect {
|
76
|
-
Inversion::
|
76
|
+
Inversion::Parser.new( @template, :ignore_unknown_tags => false ).
|
77
77
|
parse( "Text <?hoooowhat ?>" )
|
78
78
|
}.to raise_exception( Inversion::ParseError, /unknown tag/i )
|
79
79
|
end
|
80
80
|
|
81
81
|
it "can raise exceptions on unclosed (nested) tags" do
|
82
82
|
expect {
|
83
|
-
Inversion::
|
83
|
+
Inversion::Parser.new( @template ).parse( "Text <?attr something <?attr something_else ?>" )
|
84
84
|
}.to raise_exception( Inversion::ParseError, /unclosed or nested tag/i )
|
85
85
|
end
|
86
86
|
|
87
87
|
it "can raise exceptions on unclosed (eof) tags" do
|
88
88
|
expect {
|
89
|
-
Inversion::
|
89
|
+
Inversion::Parser.new( @template ).parse( "Text <?hoooowhat" )
|
90
90
|
}.to raise_exception( Inversion::ParseError, /unclosed tag/i )
|
91
91
|
end
|
92
92
|
|
93
93
|
|
94
|
-
describe Inversion::
|
94
|
+
describe Inversion::Parser::State do
|
95
95
|
|
96
96
|
before( :each ) do
|
97
|
-
@state = Inversion::
|
97
|
+
@state = Inversion::Parser::State.new( @template )
|
98
98
|
end
|
99
99
|
|
100
100
|
it "returns the node tree if it's well-formed" do
|
@@ -23,245 +23,287 @@ describe Inversion::RenderState do
|
|
23
23
|
setup_logging( :fatal )
|
24
24
|
end
|
25
25
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
state = Inversion::RenderState.new( attributes )
|
30
|
-
|
31
|
-
state.attributes.should_not equal( attributes )
|
32
|
-
state.attributes[:foot].should == "in mouth"
|
33
|
-
state.attributes[:foot].should_not equal( attributes[:foot] )
|
34
|
-
state.attributes[:bear].should == "in woods"
|
35
|
-
state.attributes[:bear].should_not equal( attributes[:bear] )
|
26
|
+
after( :all ) do
|
27
|
+
reset_logging()
|
36
28
|
end
|
37
29
|
|
38
30
|
|
39
|
-
it "
|
40
|
-
|
41
|
-
|
31
|
+
it "provides access to the block it was constructed with if there was one" do
|
32
|
+
block = Proc.new {}
|
33
|
+
state = Inversion::RenderState.new( &block )
|
34
|
+
state.block.should equal( block )
|
35
|
+
end
|
42
36
|
|
37
|
+
it "can evaluate code in the context of itself" do
|
38
|
+
attributes = { :foot => "in mouth", :bear => "in woods" }
|
43
39
|
state = Inversion::RenderState.new( attributes )
|
44
|
-
|
45
|
-
state.attributes[:danger].should be_tainted()
|
40
|
+
state.eval( "foot" ).should == 'in mouth'
|
46
41
|
end
|
47
42
|
|
48
43
|
|
49
|
-
|
50
|
-
attributes = { :danger => "in pants" }
|
51
|
-
attributes[:danger].freeze
|
44
|
+
describe "overridable attributes" do
|
52
45
|
|
53
|
-
|
46
|
+
it "copies its initial attributes" do
|
47
|
+
attributes = { :foot => "in mouth", :bear => "in woods" }
|
54
48
|
|
55
|
-
|
56
|
-
end
|
49
|
+
state = Inversion::RenderState.new( attributes )
|
57
50
|
|
51
|
+
state.attributes.should_not equal( attributes )
|
52
|
+
state.attributes[:foot].should == "in mouth"
|
53
|
+
state.attributes[:foot].should_not equal( attributes[:foot] )
|
54
|
+
state.attributes[:bear].should == "in woods"
|
55
|
+
state.attributes[:bear].should_not equal( attributes[:bear] )
|
56
|
+
end
|
58
57
|
|
59
|
-
|
60
|
-
|
61
|
-
|
58
|
+
it "preserves tainted status when copying its attributes" do
|
59
|
+
attributes = { :danger => "in pants" }
|
60
|
+
attributes[:danger].taint
|
62
61
|
|
63
|
-
|
62
|
+
state = Inversion::RenderState.new( attributes )
|
64
63
|
|
65
|
-
|
66
|
-
|
64
|
+
state.attributes[:danger].should be_tainted()
|
65
|
+
end
|
67
66
|
|
67
|
+
it "preserves singleton methods on attribute objects when copying" do
|
68
|
+
obj = Object.new
|
69
|
+
def obj.foo; "foo!"; end
|
68
70
|
|
69
|
-
|
70
|
-
block = Proc.new {}
|
71
|
-
state = Inversion::RenderState.new( &block )
|
72
|
-
state.block.should equal( block )
|
73
|
-
end
|
71
|
+
state = Inversion::RenderState.new( :foo => obj )
|
74
72
|
|
73
|
+
state.attributes[:foo].singleton_methods.map( &:to_sym ).should include( :foo )
|
74
|
+
end
|
75
75
|
|
76
|
-
|
77
|
-
|
76
|
+
it "preserves frozen status when copying its attributes" do
|
77
|
+
attributes = { :danger => "in pants" }
|
78
|
+
attributes[:danger].freeze
|
78
79
|
|
79
|
-
|
80
|
+
state = Inversion::RenderState.new( attributes )
|
80
81
|
|
81
|
-
|
82
|
-
|
82
|
+
state.attributes[:danger].should be_frozen()
|
83
|
+
end
|
83
84
|
|
84
|
-
|
85
|
-
|
85
|
+
it "can override its attributes for the duration of a block" do
|
86
|
+
attributes = { :foot => "in mouth", :bear => "in woods" }
|
86
87
|
|
87
|
-
|
88
|
+
state = Inversion::RenderState.new( attributes )
|
88
89
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
90
|
+
state.with_attributes( :foot => 'ball' ) do
|
91
|
+
state.foot.should == 'ball'
|
92
|
+
state.bear.should == 'in woods'
|
93
|
+
end
|
93
94
|
|
94
|
-
|
95
|
-
|
95
|
+
state.attributes[:foot].should == 'in mouth'
|
96
|
+
end
|
96
97
|
|
97
98
|
|
98
|
-
|
99
|
-
|
99
|
+
it "restores the original attributes if the block raises an exception" do
|
100
|
+
attributes = { :foot => "in mouth", :bear => "in woods" }
|
100
101
|
|
101
|
-
|
102
|
+
state = Inversion::RenderState.new( attributes )
|
102
103
|
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
104
|
+
expect {
|
105
|
+
state.with_attributes( {} ) do
|
106
|
+
raise "Charlie dooo!"
|
107
|
+
end
|
108
|
+
}.to raise_error()
|
108
109
|
|
109
|
-
|
110
|
-
|
110
|
+
state.attributes[:foot].should == 'in mouth'
|
111
|
+
end
|
111
112
|
|
112
113
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
114
|
+
it "raises an error if #with_attributes is called without a block" do
|
115
|
+
expect {
|
116
|
+
Inversion::RenderState.new.with_attributes( {} )
|
117
|
+
}.to raise_error( LocalJumpError, /no block/i )
|
118
|
+
end
|
118
119
|
|
120
|
+
it "provides accessor methods for its attributes" do
|
121
|
+
state = Inversion::RenderState.new( :bar => :the_attribute_value )
|
122
|
+
state.bar.should == :the_attribute_value
|
123
|
+
end
|
119
124
|
|
120
|
-
|
121
|
-
|
125
|
+
it "doesn't error if an accessor for a non-existant attribute is called" do
|
126
|
+
state = Inversion::RenderState.new( :bar => :the_attribute_value )
|
127
|
+
state.foo.should be_nil()
|
128
|
+
end
|
122
129
|
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
130
|
+
it "can be merged with another RenderState" do
|
131
|
+
state = Inversion::RenderState.new(
|
132
|
+
{:bar => :the_bar_value},
|
133
|
+
{:debugging_comments => false} )
|
134
|
+
anotherstate = Inversion::RenderState.new(
|
135
|
+
{:foo => :the_foo_value},
|
136
|
+
{:debugging_comments => true, :on_render_error => :propagate} )
|
137
|
+
|
138
|
+
thirdstate = state.merge( anotherstate )
|
139
|
+
|
140
|
+
thirdstate.attributes.should == {
|
141
|
+
:bar => :the_bar_value,
|
142
|
+
:foo => :the_foo_value
|
143
|
+
}
|
144
|
+
thirdstate.options.should include(
|
145
|
+
:debugging_comments => true,
|
146
|
+
:on_render_error => :propagate
|
147
|
+
)
|
128
148
|
end
|
129
|
-
rval.should equal( newdest )
|
130
149
|
|
131
|
-
newdest.should have( 1 ).member
|
132
|
-
newdest.should include( 'New!' )
|
133
|
-
state.destination.should equal( original_dest )
|
134
150
|
end
|
135
151
|
|
136
|
-
it "restores the original destination if the block raises an exception" do
|
137
|
-
state = Inversion::RenderState.new
|
138
152
|
|
139
|
-
|
153
|
+
describe "context-aware tag state" do
|
140
154
|
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
end
|
145
|
-
}.to raise_error()
|
155
|
+
before( :each ) do
|
156
|
+
@renderstate = Inversion::RenderState.new
|
157
|
+
end
|
146
158
|
|
147
|
-
state
|
148
|
-
|
159
|
+
it "provides a mechanism for storing tag state for the current render" do
|
160
|
+
@renderstate.tag_data.should be_a( Hash )
|
161
|
+
end
|
149
162
|
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
}.to raise_error( LocalJumpError, /no block/i )
|
154
|
-
end
|
163
|
+
it "can override tag state for the duration of a block" do
|
164
|
+
@renderstate.tag_data[ :montana ] = 'excellent fishing'
|
165
|
+
@renderstate.tag_data[ :colorado ] = 'fine fishing'
|
155
166
|
|
156
|
-
|
157
|
-
|
158
|
-
|
167
|
+
@renderstate.with_tag_data( :alaska => 'good fishing' ) do
|
168
|
+
@renderstate.tag_data[:alaska].should == 'good fishing'
|
169
|
+
@renderstate.tag_data[:alaska] = 'blueberry bear poop'
|
170
|
+
@renderstate.tag_data[:colorado] = 'Boulder has hippies'
|
171
|
+
end
|
159
172
|
|
160
|
-
|
173
|
+
@renderstate.tag_data.should_not have_key( :alaska )
|
174
|
+
@renderstate.tag_data[:montana].should == 'excellent fishing'
|
175
|
+
@renderstate.tag_data[:colorado].should == 'fine fishing'
|
176
|
+
end
|
161
177
|
|
162
|
-
state.to_s.should == '<!-- Attr: { template.foo } -->'
|
163
178
|
end
|
164
179
|
|
165
|
-
|
166
|
-
node = Inversion::Template::AttrTag.new( 'foo' )
|
167
|
-
state = Inversion::RenderState.new( {}, :debugging_comments => false )
|
180
|
+
describe "render destinations" do
|
168
181
|
|
169
|
-
|
182
|
+
it "can override the render destination for the duration of a block" do
|
183
|
+
state = Inversion::RenderState.new
|
170
184
|
|
171
|
-
|
172
|
-
|
185
|
+
original_dest = state.destination
|
186
|
+
newdest = []
|
187
|
+
node = Inversion::Template::TextNode.new( "New!" )
|
188
|
+
rval = state.with_destination( newdest ) do
|
189
|
+
state << node
|
190
|
+
end
|
191
|
+
rval.should equal( newdest )
|
173
192
|
|
174
|
-
|
175
|
-
|
176
|
-
|
193
|
+
newdest.should have( 1 ).member
|
194
|
+
newdest.should include( 'New!' )
|
195
|
+
state.destination.should equal( original_dest )
|
196
|
+
end
|
177
197
|
|
178
|
-
|
198
|
+
it "restores the original destination if the block raises an exception" do
|
199
|
+
state = Inversion::RenderState.new
|
179
200
|
|
180
|
-
|
181
|
-
end
|
201
|
+
original_dest = state.destination
|
182
202
|
|
183
|
-
|
184
|
-
|
185
|
-
|
203
|
+
expect {
|
204
|
+
state.with_destination( [] ) do
|
205
|
+
raise "New!"
|
206
|
+
end
|
207
|
+
}.to raise_error()
|
186
208
|
|
187
|
-
|
209
|
+
state.destination.should equal( original_dest )
|
210
|
+
end
|
211
|
+
|
212
|
+
it "raises an error if #with_destination is called without a block" do
|
213
|
+
expect {
|
214
|
+
Inversion::RenderState.new.with_destination( [] )
|
215
|
+
}.to raise_error( LocalJumpError, /no block/i )
|
216
|
+
end
|
188
217
|
|
189
|
-
state.to_s.should == "<!-- NoMethodError: undefined method `klang' for nil:NilClass -->"
|
190
218
|
end
|
191
219
|
|
192
|
-
it "re-raises errors while rendering appended nodes in 'propagate' mode" do
|
193
|
-
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
194
|
-
state = Inversion::RenderState.new( {}, :on_render_error => :propagate )
|
195
220
|
|
196
|
-
|
221
|
+
describe "debugging comments" do
|
222
|
+
|
223
|
+
it "adds a debugging comment when appending a node if debugging comments are enabled" do
|
224
|
+
node = Inversion::Template::AttrTag.new( 'foo' )
|
225
|
+
state = Inversion::RenderState.new( {}, :debugging_comments => true )
|
226
|
+
|
197
227
|
state << node
|
198
|
-
}.to raise_error( NoMethodError, /undefined method/ )
|
199
|
-
end
|
200
228
|
|
201
|
-
|
202
|
-
"overridden" do
|
203
|
-
handler = Proc.new do |state, node, err|
|
204
|
-
"Yum, I eat %p from %p! Tasting good!" % [err.class, node.class]
|
229
|
+
state.to_s.should == '<!-- Attr: { template.foo } -->'
|
205
230
|
end
|
206
|
-
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
207
|
-
state = Inversion::RenderState.new( {}, :on_render_error => :propagate )
|
208
|
-
defhandler = state.errhandler
|
209
231
|
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
end
|
214
|
-
}.to_not raise_error()
|
232
|
+
it "doesn't add a debugging comment when appending a node if debugging comments are disabled" do
|
233
|
+
node = Inversion::Template::AttrTag.new( 'foo' )
|
234
|
+
state = Inversion::RenderState.new( {}, :debugging_comments => false )
|
215
235
|
|
216
|
-
|
217
|
-
|
218
|
-
|
236
|
+
state << node
|
237
|
+
|
238
|
+
state.to_s.should == ''
|
239
|
+
end
|
219
240
|
|
220
|
-
it "raises an exception if the error handler is set to something that doesn't respond to #call" do
|
221
|
-
state = Inversion::RenderState.new
|
222
|
-
expect {
|
223
|
-
state.with_error_handler( :foo )
|
224
|
-
}.to raise_error( ArgumentError, /doesn't respond_to #call/i )
|
225
241
|
end
|
226
242
|
|
227
|
-
it "re-raises errors while rendering appended nodes in 'propagate' mode" do
|
228
|
-
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
229
|
-
state = Inversion::RenderState.new( {}, :on_render_error => :propagate )
|
230
243
|
|
231
|
-
|
244
|
+
describe "error-handling" do
|
245
|
+
|
246
|
+
it "ignores errors while rendering appended nodes in 'ignore' mode" do
|
247
|
+
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
248
|
+
state = Inversion::RenderState.new( {}, :on_render_error => :ignore )
|
249
|
+
|
232
250
|
state << node
|
233
|
-
}.to raise_error( NoMethodError, /undefined method/ )
|
234
|
-
end
|
235
251
|
|
236
|
-
|
237
|
-
|
238
|
-
state.bar.should == :the_attribute_value
|
239
|
-
end
|
252
|
+
state.to_s.should == ''
|
253
|
+
end
|
240
254
|
|
241
|
-
|
242
|
-
|
243
|
-
|
244
|
-
|
255
|
+
it "adds a comment for errors while rendering appended nodes in 'comment' mode" do
|
256
|
+
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
257
|
+
state = Inversion::RenderState.new( {}, :on_render_error => :comment )
|
258
|
+
|
259
|
+
state << node
|
245
260
|
|
261
|
+
state.to_s.should == "<!-- NoMethodError: undefined method `klang' for nil:NilClass -->"
|
262
|
+
end
|
246
263
|
|
247
|
-
|
248
|
-
|
249
|
-
{:
|
250
|
-
{:debugging_comments => false} )
|
251
|
-
anotherstate = Inversion::RenderState.new(
|
252
|
-
{:foo => :the_foo_value},
|
253
|
-
{:debugging_comments => true, :on_render_error => :propagate} )
|
264
|
+
it "re-raises errors while rendering appended nodes in 'propagate' mode" do
|
265
|
+
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
266
|
+
state = Inversion::RenderState.new( {}, :on_render_error => :propagate )
|
254
267
|
|
255
|
-
|
268
|
+
expect {
|
269
|
+
state << node
|
270
|
+
}.to raise_error( NoMethodError, /undefined method/ )
|
271
|
+
end
|
256
272
|
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
:on_render_error => :propagate
|
264
|
-
|
273
|
+
it "calls the provided handler if an exception is raised while the error handler has been " +
|
274
|
+
"overridden" do
|
275
|
+
handler = Proc.new do |state, node, err|
|
276
|
+
"Yum, I eat %p from %p! Tasting good!" % [err.class, node.class]
|
277
|
+
end
|
278
|
+
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
279
|
+
state = Inversion::RenderState.new( {}, :on_render_error => :propagate )
|
280
|
+
defhandler = state.errhandler
|
281
|
+
|
282
|
+
expect {
|
283
|
+
state.with_error_handler( handler ) do
|
284
|
+
state << node
|
285
|
+
end
|
286
|
+
}.to_not raise_error()
|
287
|
+
|
288
|
+
state.to_s.should =~ /yum, i eat nomethoderror/i
|
289
|
+
state.errhandler.should equal( defhandler )
|
290
|
+
end
|
291
|
+
|
292
|
+
it "raises an exception if the error handler is set to something that doesn't respond to #call" do
|
293
|
+
state = Inversion::RenderState.new
|
294
|
+
expect {
|
295
|
+
state.with_error_handler( :foo )
|
296
|
+
}.to raise_error( ArgumentError, /doesn't respond_to #call/i )
|
297
|
+
end
|
298
|
+
|
299
|
+
it "re-raises errors while rendering appended nodes in 'propagate' mode" do
|
300
|
+
node = Inversion::Template::AttrTag.new( 'boom.klang' )
|
301
|
+
state = Inversion::RenderState.new( {}, :on_render_error => :propagate )
|
302
|
+
|
303
|
+
expect {
|
304
|
+
state << node
|
305
|
+
}.to raise_error( NoMethodError, /undefined method/ )
|
306
|
+
end
|
265
307
|
|
266
308
|
end
|
267
309
|
|
@@ -287,5 +329,40 @@ describe Inversion::RenderState do
|
|
287
329
|
|
288
330
|
end
|
289
331
|
|
332
|
+
|
333
|
+
describe "conditional rendering" do
|
334
|
+
|
335
|
+
before( :each ) do
|
336
|
+
@state = Inversion::RenderState.new
|
337
|
+
end
|
338
|
+
|
339
|
+
it "allows rendering to be explicitly enabled and disabled" do
|
340
|
+
@state.rendering_enabled?.should be_true()
|
341
|
+
@state.disable_rendering
|
342
|
+
@state.rendering_enabled?.should be_false()
|
343
|
+
@state.enable_rendering
|
344
|
+
@state.rendering_enabled?.should be_true()
|
345
|
+
end
|
346
|
+
|
347
|
+
it "allows rendering to be toggled" do
|
348
|
+
@state.rendering_enabled?.should be_true()
|
349
|
+
@state.toggle_rendering
|
350
|
+
@state.rendering_enabled?.should be_false()
|
351
|
+
@state.toggle_rendering
|
352
|
+
@state.rendering_enabled?.should be_true()
|
353
|
+
end
|
354
|
+
|
355
|
+
it "doesn't render nodes that are appended to it if rendering is disabled" do
|
356
|
+
@state << Inversion::Template::TextNode.new( "before" )
|
357
|
+
@state.disable_rendering
|
358
|
+
@state << Inversion::Template::TextNode.new( "during" )
|
359
|
+
@state.enable_rendering
|
360
|
+
@state << Inversion::Template::TextNode.new( "after" )
|
361
|
+
|
362
|
+
@state.to_s.should == 'beforeafter'
|
363
|
+
end
|
364
|
+
|
365
|
+
end
|
366
|
+
|
290
367
|
end
|
291
368
|
|