inversion 0.12.3 → 0.14.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- checksums.yaml.gz.sig +2 -1
- data.tar.gz.sig +0 -0
- data/ChangeLog +305 -9
- data/Examples.rdoc +134 -0
- data/GettingStarted.rdoc +44 -0
- data/Guide.rdoc +47 -0
- data/History.rdoc +15 -0
- data/Manifest.txt +7 -2
- data/README.rdoc +9 -10
- data/Rakefile +23 -10
- data/Tags.rdoc +561 -0
- data/lib/inversion.rb +2 -2
- data/lib/inversion/renderstate.rb +46 -11
- data/lib/inversion/template.rb +85 -7
- data/lib/inversion/template/attrtag.rb +1 -1
- data/lib/inversion/template/begintag.rb +8 -8
- data/lib/inversion/template/fragmenttag.rb +60 -0
- data/lib/inversion/template/rescuetag.rb +1 -1
- data/spec/{lib/helpers.rb → helpers.rb} +7 -30
- data/spec/inversion/mixins_spec.rb +55 -65
- data/spec/inversion/monkeypatches_spec.rb +2 -12
- data/spec/inversion/parser_spec.rb +34 -44
- data/spec/inversion/renderstate_spec.rb +123 -69
- data/spec/inversion/sinatra_spec.rb +6 -19
- data/spec/inversion/template/attrtag_spec.rb +56 -76
- data/spec/inversion/template/begintag_spec.rb +24 -41
- data/spec/inversion/template/calltag_spec.rb +1 -18
- data/spec/inversion/template/codetag_spec.rb +6 -24
- data/spec/inversion/template/commenttag_spec.rb +9 -27
- data/spec/inversion/template/configtag_spec.rb +5 -16
- data/spec/inversion/template/containertag_spec.rb +4 -21
- data/spec/inversion/template/defaulttag_spec.rb +6 -23
- data/spec/inversion/template/elsetag_spec.rb +9 -26
- data/spec/inversion/template/elsiftag_spec.rb +7 -24
- data/spec/inversion/template/endtag_spec.rb +6 -23
- data/spec/inversion/template/escapetag_spec.rb +10 -25
- data/spec/inversion/template/fortag_spec.rb +20 -37
- data/spec/inversion/template/fragmenttag_spec.rb +40 -0
- data/spec/inversion/template/iftag_spec.rb +23 -40
- data/spec/inversion/template/importtag_spec.rb +8 -25
- data/spec/inversion/template/includetag_spec.rb +27 -42
- data/spec/inversion/template/node_spec.rb +6 -15
- data/spec/inversion/template/pptag_spec.rb +10 -23
- data/spec/inversion/template/publishtag_spec.rb +4 -21
- data/spec/inversion/template/rescuetag_spec.rb +12 -29
- data/spec/inversion/template/subscribetag_spec.rb +8 -25
- data/spec/inversion/template/tag_spec.rb +24 -37
- data/spec/inversion/template/textnode_spec.rb +8 -24
- data/spec/inversion/template/timedeltatag_spec.rb +31 -43
- data/spec/inversion/template/unlesstag_spec.rb +7 -24
- data/spec/inversion/template/uriencodetag_spec.rb +6 -23
- data/spec/inversion/template/yieldtag_spec.rb +3 -20
- data/spec/inversion/template_spec.rb +155 -108
- data/spec/inversion/tilt_spec.rb +7 -16
- data/spec/inversion_spec.rb +7 -22
- metadata +63 -40
- metadata.gz.sig +0 -0
- data/spec/lib/constants.rb +0 -9
@@ -1,17 +1,7 @@
|
|
1
1
|
#!/usr/bin/env rspec -cfd -b
|
2
2
|
# vim: set noet nosta sw=4 ts=4 :
|
3
3
|
|
4
|
-
|
5
|
-
require 'pathname'
|
6
|
-
basedir = Pathname( __FILE__ ).dirname.parent.parent
|
7
|
-
libdir = basedir + 'lib'
|
8
|
-
|
9
|
-
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
10
|
-
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
11
|
-
}
|
12
|
-
|
13
|
-
require 'rspec'
|
14
|
-
require 'spec/lib/helpers'
|
4
|
+
require_relative '../helpers'
|
15
5
|
|
16
6
|
require 'inversion/mixins'
|
17
7
|
|
@@ -30,15 +20,15 @@ describe Inversion, "mixins" do
|
|
30
20
|
|
31
21
|
result = Inversion::HashUtilities.stringify_keys( testhash )
|
32
22
|
|
33
|
-
result.
|
34
|
-
result.
|
35
|
-
result.
|
23
|
+
expect( result ).to be_an_instance_of( Hash )
|
24
|
+
expect( result ).to_not be_equal( testhash )
|
25
|
+
expect( result ).to eq({
|
36
26
|
'foo' => 1,
|
37
27
|
'bar' => {
|
38
28
|
'klang' => 'klong',
|
39
29
|
'barang' => { 'kerklang' => 'dumdumdum' },
|
40
30
|
}
|
41
|
-
}
|
31
|
+
})
|
42
32
|
end
|
43
33
|
|
44
34
|
|
@@ -53,15 +43,15 @@ describe Inversion, "mixins" do
|
|
53
43
|
|
54
44
|
result = Inversion::HashUtilities.symbolify_keys( testhash )
|
55
45
|
|
56
|
-
result.
|
57
|
-
result.
|
58
|
-
result.
|
46
|
+
expect( result ).to be_an_instance_of( Hash )
|
47
|
+
expect( result ).to_not be_equal( testhash )
|
48
|
+
expect( result ).to eq({
|
59
49
|
:foo => 1,
|
60
50
|
:bar => {
|
61
51
|
:klang => 'klong',
|
62
52
|
:barang => { :kerklang => 'dumdumdum' },
|
63
53
|
}
|
64
|
-
}
|
54
|
+
})
|
65
55
|
end
|
66
56
|
|
67
57
|
end
|
@@ -125,17 +115,17 @@ describe Inversion, "mixins" do
|
|
125
115
|
|
126
116
|
it "adds configurable escaping to including classes" do
|
127
117
|
render_state = Inversion::RenderState.new( {}, :escape_format => :html )
|
128
|
-
@obj.render( render_state ).
|
118
|
+
expect( @obj.render( render_state ) ).to eq( "<something>" )
|
129
119
|
end
|
130
120
|
|
131
121
|
it "doesn't escape anything if escaping is disabled" do
|
132
122
|
render_state = Inversion::RenderState.new( {}, :escape_format => nil )
|
133
|
-
@obj.render( render_state ).
|
123
|
+
expect( @obj.render( render_state ) ).to eq( "<something>" )
|
134
124
|
end
|
135
125
|
|
136
126
|
it "doesn't escape anything if escaping is set to ':none'" do
|
137
127
|
render_state = Inversion::RenderState.new( {}, :escape_format => :none )
|
138
|
-
@obj.render( render_state ).
|
128
|
+
expect( @obj.render( render_state ) ).to eq( "<something>" )
|
139
129
|
end
|
140
130
|
end
|
141
131
|
|
@@ -143,26 +133,26 @@ describe Inversion, "mixins" do
|
|
143
133
|
describe Inversion::DataUtilities do
|
144
134
|
|
145
135
|
it "doesn't try to dup immediate objects" do
|
146
|
-
Inversion::DataUtilities.deep_copy( nil ).
|
147
|
-
Inversion::DataUtilities.deep_copy( 112 ).
|
148
|
-
Inversion::DataUtilities.deep_copy( true ).
|
149
|
-
Inversion::DataUtilities.deep_copy( false ).
|
150
|
-
Inversion::DataUtilities.deep_copy( :a_symbol ).
|
136
|
+
expect( Inversion::DataUtilities.deep_copy( nil ) ).to be( nil )
|
137
|
+
expect( Inversion::DataUtilities.deep_copy( 112 ) ).to be( 112 )
|
138
|
+
expect( Inversion::DataUtilities.deep_copy( true ) ).to be( true )
|
139
|
+
expect( Inversion::DataUtilities.deep_copy( false ) ).to be( false )
|
140
|
+
expect( Inversion::DataUtilities.deep_copy( :a_symbol ) ).to be( :a_symbol )
|
151
141
|
end
|
152
142
|
|
153
143
|
it "doesn't try to dup modules/classes" do
|
154
144
|
klass = Class.new
|
155
|
-
Inversion::DataUtilities.deep_copy( klass ).
|
145
|
+
expect( Inversion::DataUtilities.deep_copy( klass ) ).to be( klass )
|
156
146
|
end
|
157
147
|
|
158
148
|
it "doesn't try to dup IOs" do
|
159
149
|
data = [ $stdin ]
|
160
|
-
Inversion::DataUtilities.deep_copy( data[0] ).
|
150
|
+
expect( Inversion::DataUtilities.deep_copy( data[0] ) ).to be( $stdin )
|
161
151
|
end
|
162
152
|
|
163
153
|
it "doesn't try to dup Tempfiles" do
|
164
154
|
data = Tempfile.new( 'inversion_deepcopy.XXXXX' )
|
165
|
-
Inversion::DataUtilities.deep_copy( data ).
|
155
|
+
expect( Inversion::DataUtilities.deep_copy( data ) ).to be( data )
|
166
156
|
end
|
167
157
|
|
168
158
|
it "makes distinct copies of arrays and their members" do
|
@@ -170,14 +160,14 @@ describe Inversion, "mixins" do
|
|
170
160
|
|
171
161
|
copy = Inversion::DataUtilities.deep_copy( original )
|
172
162
|
|
173
|
-
copy.
|
174
|
-
copy.
|
175
|
-
copy[0].
|
176
|
-
copy[0].
|
177
|
-
copy[1].
|
178
|
-
copy[1].
|
179
|
-
copy[2].
|
180
|
-
copy[2].
|
163
|
+
expect( copy ).to eq( original )
|
164
|
+
expect( copy ).to_not be( original )
|
165
|
+
expect( copy[0] ).to eq( original[0] )
|
166
|
+
expect( copy[0] ).to_not be( original[0] )
|
167
|
+
expect( copy[1] ).to eq( original[1] )
|
168
|
+
expect( copy[1] ).to_not be( original[1] )
|
169
|
+
expect( copy[2] ).to eq( original[2] )
|
170
|
+
expect( copy[2] ).to be( original[2] ) # Immediate
|
181
171
|
end
|
182
172
|
|
183
173
|
it "makes recursive copies of deeply-nested Arrays" do
|
@@ -185,12 +175,12 @@ describe Inversion, "mixins" do
|
|
185
175
|
|
186
176
|
copy = Inversion::DataUtilities.deep_copy( original )
|
187
177
|
|
188
|
-
copy.
|
189
|
-
copy.
|
190
|
-
copy[1].
|
191
|
-
copy[1][2].
|
192
|
-
copy[3].
|
193
|
-
copy[3][1].
|
178
|
+
expect( copy ).to eq( original )
|
179
|
+
expect( copy ).to_not be( original )
|
180
|
+
expect( copy[1] ).to_not be( original[1] )
|
181
|
+
expect( copy[1][2] ).to_not be( original[1][2] )
|
182
|
+
expect( copy[3] ).to_not be( original[3] )
|
183
|
+
expect( copy[3][1] ).to_not be( original[3][1] )
|
194
184
|
end
|
195
185
|
|
196
186
|
it "makes distinct copies of Hashes and their members" do
|
@@ -202,13 +192,13 @@ describe Inversion, "mixins" do
|
|
202
192
|
|
203
193
|
copy = Inversion::DataUtilities.deep_copy( original )
|
204
194
|
|
205
|
-
copy.
|
206
|
-
copy.
|
207
|
-
copy[:a].
|
208
|
-
copy.key( 2 ).
|
209
|
-
copy.key( 2 ).
|
210
|
-
copy[3].
|
211
|
-
copy[3].
|
195
|
+
expect( copy ).to eq( original )
|
196
|
+
expect( copy ).to_not be( original )
|
197
|
+
expect( copy[:a] ).to eq( 1 )
|
198
|
+
expect( copy.key( 2 ) ).to eq( 'b' )
|
199
|
+
expect( copy.key( 2 ) ).to_not be( original.key(2) )
|
200
|
+
expect( copy[3] ).to eq( 'c' )
|
201
|
+
expect( copy[3] ).to_not be( original[3] )
|
212
202
|
end
|
213
203
|
|
214
204
|
it "makes distinct copies of deeply-nested Hashes" do
|
@@ -225,15 +215,15 @@ describe Inversion, "mixins" do
|
|
225
215
|
|
226
216
|
copy = Inversion::DataUtilities.deep_copy( original )
|
227
217
|
|
228
|
-
copy.
|
229
|
-
copy[:a][:b][:c].
|
230
|
-
copy[:a][:b][:c].
|
231
|
-
copy[:a][:b][:e].
|
232
|
-
copy[:a][:b][:e].
|
233
|
-
copy[:a][:g].
|
234
|
-
copy[:a][:g].
|
235
|
-
copy[:i].
|
236
|
-
copy[:i].
|
218
|
+
expect( copy ).to eq( original )
|
219
|
+
expect( copy[:a][:b][:c] ).to eq( 'd' )
|
220
|
+
expect( copy[:a][:b][:c] ).to_not be( original[:a][:b][:c] )
|
221
|
+
expect( copy[:a][:b][:e] ).to eq( 'f' )
|
222
|
+
expect( copy[:a][:b][:e] ).to_not be( original[:a][:b][:e] )
|
223
|
+
expect( copy[:a][:g] ).to eq( 'h' )
|
224
|
+
expect( copy[:a][:g] ).to_not be( original[:a][:g] )
|
225
|
+
expect( copy[:i] ).to eq( 'j' )
|
226
|
+
expect( copy[:i] ).to_not be( original[:i] )
|
237
227
|
end
|
238
228
|
|
239
229
|
it "copies the default proc of copied Hashes" do
|
@@ -241,7 +231,7 @@ describe Inversion, "mixins" do
|
|
241
231
|
|
242
232
|
copy = Inversion::DataUtilities.deep_copy( original )
|
243
233
|
|
244
|
-
copy.default_proc.
|
234
|
+
expect( copy.default_proc ).to eq( original.default_proc )
|
245
235
|
end
|
246
236
|
|
247
237
|
it "preserves taintedness of copied objects" do
|
@@ -250,8 +240,8 @@ describe Inversion, "mixins" do
|
|
250
240
|
|
251
241
|
copy = Inversion::DataUtilities.deep_copy( original )
|
252
242
|
|
253
|
-
copy.
|
254
|
-
copy.
|
243
|
+
expect( copy ).to_not be( original )
|
244
|
+
expect( copy ).to be_tainted()
|
255
245
|
end
|
256
246
|
|
257
247
|
it "preserves frozen-ness of copied objects" do
|
@@ -260,8 +250,8 @@ describe Inversion, "mixins" do
|
|
260
250
|
|
261
251
|
copy = Inversion::DataUtilities.deep_copy( original )
|
262
252
|
|
263
|
-
copy.
|
264
|
-
copy.
|
253
|
+
expect( copy ).to_not be( original )
|
254
|
+
expect( copy ).to be_frozen()
|
265
255
|
end
|
266
256
|
end
|
267
257
|
end
|
@@ -1,20 +1,10 @@
|
|
1
1
|
#!/usr/bin/env rspec -cfd -b
|
2
2
|
# vim: set noet nosta sw=4 ts=4 :
|
3
3
|
|
4
|
-
BEGIN {
|
5
|
-
require 'pathname'
|
6
|
-
basedir = Pathname( __FILE__ ).dirname.parent.parent
|
7
|
-
libdir = basedir + 'lib'
|
8
4
|
|
9
|
-
|
10
|
-
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
11
|
-
}
|
5
|
+
require_relative '../helpers'
|
12
6
|
|
13
7
|
require 'ripper'
|
14
|
-
|
15
|
-
require 'rspec'
|
16
|
-
require 'spec/lib/helpers'
|
17
|
-
|
18
8
|
require 'inversion/monkeypatches'
|
19
9
|
|
20
10
|
|
@@ -25,7 +15,7 @@ describe Inversion, "monkeypatches" do
|
|
25
15
|
it "exposes the Ripper::TokenPattern::MatchData's #tokens array" do
|
26
16
|
tagpattern = Ripper::TokenPattern.compile( '$(ident) $(sp) $(ident)' )
|
27
17
|
matchdata = tagpattern.match( "foo bar" )
|
28
|
-
matchdata.tokens.map {|tok| tok[1]
|
18
|
+
expect( matchdata.tokens.map {|tok| tok[1]} ).to eq([ :on_ident, :on_sp, :on_ident ])
|
29
19
|
end
|
30
20
|
|
31
21
|
end
|
@@ -1,23 +1,13 @@
|
|
1
1
|
#!/usr/bin/env rspec -cfd -b
|
2
2
|
# vim: set noet nosta sw=4 ts=4 :
|
3
3
|
|
4
|
-
|
5
|
-
require 'pathname'
|
6
|
-
basedir = Pathname( __FILE__ ).dirname.parent.parent
|
7
|
-
libdir = basedir + 'lib'
|
4
|
+
require_relative '../helpers'
|
8
5
|
|
9
|
-
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
10
|
-
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
11
|
-
}
|
12
|
-
|
13
|
-
require 'rspec'
|
14
|
-
require 'spec/lib/helpers'
|
15
6
|
require 'inversion/parser'
|
16
7
|
|
17
8
|
describe Inversion::Parser do
|
18
9
|
|
19
10
|
before( :all ) do
|
20
|
-
setup_logging( :fatal )
|
21
11
|
Inversion::Template::Tag.load_all
|
22
12
|
end
|
23
13
|
|
@@ -28,14 +18,14 @@ describe Inversion::Parser do
|
|
28
18
|
it "parses a string with no PIs as a single text node" do
|
29
19
|
result = Inversion::Parser.new( @template ).parse( "render unto Caesar" )
|
30
20
|
|
31
|
-
result.
|
32
|
-
result.first.
|
33
|
-
result.first.body.
|
21
|
+
expect( result.size ).to eq( 1 )
|
22
|
+
expect( result.first ).to be_a( Inversion::Template::TextNode )
|
23
|
+
expect( result.first.body ).to eq( 'render unto Caesar' )
|
34
24
|
end
|
35
25
|
|
36
26
|
it "parses an empty string as a empty tree" do
|
37
27
|
result = Inversion::Parser.new( @template ).parse( "" )
|
38
|
-
result.
|
28
|
+
expect( result ).to be_empty
|
39
29
|
end
|
40
30
|
|
41
31
|
it "raises a ParseError on mismatched tag brackets" do
|
@@ -47,47 +37,47 @@ describe Inversion::Parser do
|
|
47
37
|
it "parses a string with a single 'attr' tag as a single AttrTag node" do
|
48
38
|
result = Inversion::Parser.new( @template ).parse( "<?attr foo ?>" )
|
49
39
|
|
50
|
-
result.
|
51
|
-
result.first.
|
52
|
-
result.first.body.
|
40
|
+
expect( result.size ).to eq( 1 )
|
41
|
+
expect( result.first ).to be_a( Inversion::Template::AttrTag )
|
42
|
+
expect( result.first.body ).to eq( 'foo' )
|
53
43
|
end
|
54
44
|
|
55
45
|
it "parses a single 'attr' tag surrounded by plain text" do
|
56
46
|
result = Inversion::Parser.new( @template ).parse( "beginning<?attr foo ?>end" )
|
57
47
|
|
58
|
-
result.
|
59
|
-
result[0].
|
60
|
-
result[1].
|
61
|
-
result[1].body.
|
62
|
-
result[2].
|
48
|
+
expect( result.size ).to eq( 3 )
|
49
|
+
expect( result[0] ).to be_a( Inversion::Template::TextNode )
|
50
|
+
expect( result[1] ).to be_a( Inversion::Template::AttrTag )
|
51
|
+
expect( result[1].body ).to eq( 'foo' )
|
52
|
+
expect( result[2] ).to be_a( Inversion::Template::TextNode )
|
63
53
|
end
|
64
54
|
|
65
55
|
it "ignores unknown tags by default" do
|
66
56
|
result = Inversion::Parser.new( @template ).parse( "Text <?hoooowhat ?>" )
|
67
57
|
|
68
|
-
result.
|
69
|
-
result[0].
|
70
|
-
result[1].
|
71
|
-
result[1].body.
|
58
|
+
expect( result.size ).to eq( 2 )
|
59
|
+
expect( result[0] ).to be_a( Inversion::Template::TextNode )
|
60
|
+
expect( result[1] ).to be_a( Inversion::Template::TextNode )
|
61
|
+
expect( result[1].body ).to eq( '<?hoooowhat ?>' )
|
72
62
|
end
|
73
63
|
|
74
64
|
it "can raise exceptions on unknown tags" do
|
75
65
|
expect {
|
76
66
|
Inversion::Parser.new( @template, :ignore_unknown_tags => false ).
|
77
67
|
parse( "Text <?hoooowhat ?>" )
|
78
|
-
}.to
|
68
|
+
}.to raise_error( Inversion::ParseError, /unknown tag/i )
|
79
69
|
end
|
80
70
|
|
81
71
|
it "can raise exceptions on unclosed (nested) tags" do
|
82
72
|
expect {
|
83
73
|
Inversion::Parser.new( @template ).parse( "Text <?attr something <?attr something_else ?>" )
|
84
|
-
}.to
|
74
|
+
}.to raise_error( Inversion::ParseError, /unclosed or nested tag/i )
|
85
75
|
end
|
86
76
|
|
87
77
|
it "can raise exceptions on unclosed (eof) tags" do
|
88
78
|
expect {
|
89
79
|
Inversion::Parser.new( @template ).parse( "Text <?hoooowhat" )
|
90
|
-
}.to
|
80
|
+
}.to raise_error( Inversion::ParseError, /unclosed tag/i )
|
91
81
|
end
|
92
82
|
|
93
83
|
|
@@ -103,41 +93,41 @@ describe Inversion::Parser do
|
|
103
93
|
|
104
94
|
@state << open_tag << end_tag
|
105
95
|
|
106
|
-
@state.tree.
|
96
|
+
expect( @state.tree ).to eq( [ open_tag, end_tag ] )
|
107
97
|
end
|
108
98
|
|
109
99
|
it "knows it is well-formed if there are no open tags" do
|
110
100
|
@state << Inversion::Template::ForTag.new( 'foo in bar' )
|
111
|
-
@state.
|
101
|
+
expect( @state ).to_not be_well_formed
|
112
102
|
|
113
103
|
@state << Inversion::Template::ForTag.new( 'foo in bar' )
|
114
|
-
@state.
|
104
|
+
expect( @state ).to_not be_well_formed
|
115
105
|
|
116
106
|
@state << Inversion::Template::EndTag.new( 'for' )
|
117
|
-
@state.
|
107
|
+
expect( @state ).to_not be_well_formed
|
118
108
|
|
119
109
|
@state << Inversion::Template::EndTag.new( 'for' )
|
120
|
-
@state.
|
110
|
+
expect( @state ).to be_well_formed
|
121
111
|
end
|
122
112
|
|
123
113
|
it "can pop a container tag off of the current context" do
|
124
114
|
container = Inversion::Template::ForTag.new( 'foo in bar' )
|
125
115
|
@state << container
|
126
|
-
@state.pop.
|
116
|
+
expect( @state.pop ).to eq( container )
|
127
117
|
end
|
128
118
|
|
129
119
|
it "calls the #after_appending hook of container nodes when they're popped" do
|
130
|
-
container =
|
120
|
+
container = double( "container tag", :before_appending => false, :is_container? => true )
|
131
121
|
@state << container
|
132
122
|
|
133
|
-
container.
|
123
|
+
expect( container ).to receive( :after_appending ).with( @state )
|
134
124
|
@state.pop
|
135
125
|
end
|
136
126
|
|
137
127
|
it "raises an error when popping if there is no container tag" do
|
138
128
|
expect {
|
139
129
|
@state.pop
|
140
|
-
}.to
|
130
|
+
}.to raise_error( Inversion::ParseError, /unbalanced end: no open tag/i )
|
141
131
|
end
|
142
132
|
|
143
133
|
it "raises an error when the tree is fetched if it isn't well-formed" do
|
@@ -146,19 +136,19 @@ describe Inversion::Parser do
|
|
146
136
|
|
147
137
|
expect {
|
148
138
|
@state.tree
|
149
|
-
}.to
|
139
|
+
}.to raise_error( Inversion::ParseError, /unclosed/i )
|
150
140
|
end
|
151
141
|
|
152
142
|
it "calls the #before_appending callback on nodes that are appended to it" do
|
153
|
-
node =
|
154
|
-
node.
|
143
|
+
node = double( "node", :is_container? => false, :after_appending => nil )
|
144
|
+
expect( node ).to receive( :before_appending ).with( @state )
|
155
145
|
|
156
146
|
@state << node
|
157
147
|
end
|
158
148
|
|
159
149
|
it "calls the #after_appending callback on nodes that are appended to it" do
|
160
|
-
node =
|
161
|
-
node.
|
150
|
+
node = double( "node", :is_container? => false, :before_appending => nil )
|
151
|
+
expect( node ).to receive( :after_appending ).with( @state )
|
162
152
|
|
163
153
|
@state << node
|
164
154
|
end
|
@@ -2,43 +2,28 @@
|
|
2
2
|
# encoding: utf-8
|
3
3
|
# vim: set noet nosta sw=4 ts=4 :
|
4
4
|
|
5
|
-
|
6
|
-
require 'pathname'
|
7
|
-
basedir = Pathname( __FILE__ ).dirname.parent.parent
|
8
|
-
libdir = basedir + 'lib'
|
5
|
+
require_relative '../helpers'
|
9
6
|
|
10
|
-
$LOAD_PATH.unshift( basedir.to_s ) unless $LOAD_PATH.include?( basedir.to_s )
|
11
|
-
$LOAD_PATH.unshift( libdir.to_s ) unless $LOAD_PATH.include?( libdir.to_s )
|
12
|
-
}
|
13
|
-
|
14
|
-
require 'rspec'
|
15
|
-
|
16
|
-
require 'spec/lib/helpers'
|
17
7
|
require 'inversion/renderstate'
|
18
8
|
require 'inversion/template/attrtag'
|
19
9
|
require 'inversion/template/textnode'
|
10
|
+
require 'inversion/template/fragmenttag'
|
11
|
+
require 'inversion/template/subscribetag'
|
12
|
+
require 'inversion/template/publishtag'
|
20
13
|
|
21
14
|
describe Inversion::RenderState do
|
22
15
|
|
23
|
-
before( :all ) do
|
24
|
-
setup_logging( :fatal )
|
25
|
-
end
|
26
|
-
|
27
|
-
after( :all ) do
|
28
|
-
reset_logging()
|
29
|
-
end
|
30
|
-
|
31
16
|
|
32
17
|
it "provides access to the block it was constructed with if there was one" do
|
33
18
|
block = Proc.new {}
|
34
19
|
state = Inversion::RenderState.new( &block )
|
35
|
-
state.block.
|
20
|
+
expect( state.block ).to equal( block )
|
36
21
|
end
|
37
22
|
|
38
23
|
it "can evaluate code in the context of itself" do
|
39
24
|
attributes = { :foot => "in mouth", :bear => "in woods" }
|
40
25
|
state = Inversion::RenderState.new( attributes )
|
41
|
-
state.eval( "foot" ).
|
26
|
+
expect( state.eval( "foot" ) ).to eq( 'in mouth' )
|
42
27
|
end
|
43
28
|
|
44
29
|
|
@@ -49,11 +34,11 @@ describe Inversion::RenderState do
|
|
49
34
|
|
50
35
|
state = Inversion::RenderState.new( attributes )
|
51
36
|
|
52
|
-
state.scope.__locals__.
|
53
|
-
state.scope[:foot].
|
54
|
-
state.scope[:foot].
|
55
|
-
state.scope[:bear].
|
56
|
-
state.scope[:bear].
|
37
|
+
expect( state.scope.__locals__ ).to_not equal( attributes )
|
38
|
+
expect( state.scope[:foot] ).to eq( "in mouth" )
|
39
|
+
expect( state.scope[:foot] ).to_not equal( attributes[:foot] )
|
40
|
+
expect( state.scope[:bear] ).to eq( "in woods" )
|
41
|
+
expect( state.scope[:bear] ).to_not equal( attributes[:bear] )
|
57
42
|
end
|
58
43
|
|
59
44
|
it "preserves tainted status when copying its attributes" do
|
@@ -62,7 +47,7 @@ describe Inversion::RenderState do
|
|
62
47
|
|
63
48
|
state = Inversion::RenderState.new( attributes )
|
64
49
|
|
65
|
-
state.scope[:danger].
|
50
|
+
expect( state.scope[:danger] ).to be_tainted()
|
66
51
|
end
|
67
52
|
|
68
53
|
it "preserves singleton methods on attribute objects when copying" do
|
@@ -71,7 +56,7 @@ describe Inversion::RenderState do
|
|
71
56
|
|
72
57
|
state = Inversion::RenderState.new( :foo => obj )
|
73
58
|
|
74
|
-
state.scope[:foo].singleton_methods.map( &:to_sym ).
|
59
|
+
expect( state.scope[:foo].singleton_methods.map( &:to_sym ) ).to include( :foo )
|
75
60
|
end
|
76
61
|
|
77
62
|
it "preserves frozen status when copying its attributes" do
|
@@ -80,7 +65,7 @@ describe Inversion::RenderState do
|
|
80
65
|
|
81
66
|
state = Inversion::RenderState.new( attributes )
|
82
67
|
|
83
|
-
state.scope[:danger].
|
68
|
+
expect( state.scope[:danger] ).to be_frozen()
|
84
69
|
end
|
85
70
|
|
86
71
|
it "can override its attributes for the duration of a block" do
|
@@ -89,11 +74,11 @@ describe Inversion::RenderState do
|
|
89
74
|
state = Inversion::RenderState.new( attributes )
|
90
75
|
|
91
76
|
state.with_attributes( :foot => 'ball' ) do
|
92
|
-
state.foot.
|
93
|
-
state.bear.
|
77
|
+
expect( state.foot ).to eq( 'ball' )
|
78
|
+
expect( state.bear ).to eq( 'in woods' )
|
94
79
|
end
|
95
80
|
|
96
|
-
state.scope[:foot].
|
81
|
+
expect( state.scope[:foot] ).to eq( 'in mouth' )
|
97
82
|
end
|
98
83
|
|
99
84
|
|
@@ -108,7 +93,7 @@ describe Inversion::RenderState do
|
|
108
93
|
end
|
109
94
|
}.to raise_error()
|
110
95
|
|
111
|
-
state.scope[:foot].
|
96
|
+
expect( state.scope[:foot] ).to eq( 'in mouth' )
|
112
97
|
end
|
113
98
|
|
114
99
|
|
@@ -122,12 +107,12 @@ describe Inversion::RenderState do
|
|
122
107
|
|
123
108
|
it "provides accessor methods for its attributes" do
|
124
109
|
state = Inversion::RenderState.new( :bar => :the_attribute_value )
|
125
|
-
state.scope.bar.
|
110
|
+
expect( state.scope.bar ).to eq( :the_attribute_value )
|
126
111
|
end
|
127
112
|
|
128
113
|
it "doesn't error if an accessor for a non-existant attribute is called" do
|
129
114
|
state = Inversion::RenderState.new( :bar => :the_attribute_value )
|
130
|
-
state.scope.foo.
|
115
|
+
expect( state.scope.foo ).to be_nil()
|
131
116
|
end
|
132
117
|
|
133
118
|
end
|
@@ -142,11 +127,11 @@ describe Inversion::RenderState do
|
|
142
127
|
|
143
128
|
thirdstate = state.merge( anotherstate )
|
144
129
|
|
145
|
-
thirdstate.attributes.
|
130
|
+
expect( thirdstate.attributes ).to eq({
|
146
131
|
:bar => :the_bar_value,
|
147
132
|
:foo => :the_foo_value
|
148
|
-
}
|
149
|
-
thirdstate.options.
|
133
|
+
})
|
134
|
+
expect( thirdstate.options ).to include(
|
150
135
|
:debugging_comments => true,
|
151
136
|
:on_render_error => :propagate
|
152
137
|
)
|
@@ -162,7 +147,7 @@ describe Inversion::RenderState do
|
|
162
147
|
end
|
163
148
|
|
164
149
|
it "provides a mechanism for storing tag state for the current render" do
|
165
|
-
@renderstate.tag_data.
|
150
|
+
expect( @renderstate.tag_data ).to be_a( Hash )
|
166
151
|
end
|
167
152
|
|
168
153
|
it "can override tag state for the duration of a block" do
|
@@ -170,14 +155,14 @@ describe Inversion::RenderState do
|
|
170
155
|
@renderstate.tag_data[ :colorado ] = 'fine fishing'
|
171
156
|
|
172
157
|
@renderstate.with_tag_data( :alaska => 'good fishing' ) do
|
173
|
-
@renderstate.tag_data[:alaska].
|
158
|
+
expect( @renderstate.tag_data[:alaska] ).to eq( 'good fishing' )
|
174
159
|
@renderstate.tag_data[:alaska] = 'blueberry bear poop'
|
175
160
|
@renderstate.tag_data[:colorado] = 'Boulder has hippies'
|
176
161
|
end
|
177
162
|
|
178
|
-
@renderstate.tag_data.
|
179
|
-
@renderstate.tag_data[:montana].
|
180
|
-
@renderstate.tag_data[:colorado].
|
163
|
+
expect( @renderstate.tag_data ).to_not have_key( :alaska )
|
164
|
+
expect( @renderstate.tag_data[:montana] ).to eq( 'excellent fishing' )
|
165
|
+
expect( @renderstate.tag_data[:colorado] ).to eq( 'fine fishing' )
|
181
166
|
end
|
182
167
|
|
183
168
|
end
|
@@ -194,11 +179,11 @@ describe Inversion::RenderState do
|
|
194
179
|
rval = state.with_destination( newdest ) do
|
195
180
|
state << node
|
196
181
|
end
|
197
|
-
rval.
|
182
|
+
expect( rval ).to equal( newdest )
|
198
183
|
|
199
|
-
newdest.
|
200
|
-
newdest.
|
201
|
-
state.destination.
|
184
|
+
expect( newdest.size ).to eq( 1 )
|
185
|
+
expect( newdest ).to include( 'New!' )
|
186
|
+
expect( state.destination ).to equal( original_dest )
|
202
187
|
end
|
203
188
|
|
204
189
|
it "restores the original destination if the block raises an exception" do
|
@@ -212,7 +197,7 @@ describe Inversion::RenderState do
|
|
212
197
|
end
|
213
198
|
}.to raise_error()
|
214
199
|
|
215
|
-
state.destination.
|
200
|
+
expect( state.destination ).to equal( original_dest )
|
216
201
|
end
|
217
202
|
|
218
203
|
it "raises an error if #with_destination is called without a block" do
|
@@ -232,7 +217,7 @@ describe Inversion::RenderState do
|
|
232
217
|
|
233
218
|
state << node
|
234
219
|
|
235
|
-
state.to_s.
|
220
|
+
expect( state.to_s ).to eq( '<!-- Attr: { template.foo } -->' )
|
236
221
|
end
|
237
222
|
|
238
223
|
it "doesn't add a debugging comment when appending a node if debugging comments are disabled" do
|
@@ -241,7 +226,7 @@ describe Inversion::RenderState do
|
|
241
226
|
|
242
227
|
state << node
|
243
228
|
|
244
|
-
state.to_s.
|
229
|
+
expect( state.to_s ).to eq( '' )
|
245
230
|
end
|
246
231
|
|
247
232
|
end
|
@@ -255,7 +240,7 @@ describe Inversion::RenderState do
|
|
255
240
|
|
256
241
|
state << node
|
257
242
|
|
258
|
-
state.to_s.
|
243
|
+
expect( state.to_s ).to eq( '' )
|
259
244
|
end
|
260
245
|
|
261
246
|
it "adds a comment for errors while rendering appended nodes in 'comment' mode" do
|
@@ -264,7 +249,7 @@ describe Inversion::RenderState do
|
|
264
249
|
|
265
250
|
state << node
|
266
251
|
|
267
|
-
state.to_s.
|
252
|
+
expect( state.to_s ).to eq( "<!-- NoMethodError: undefined method `klang' for nil:NilClass -->" )
|
268
253
|
end
|
269
254
|
|
270
255
|
it "includes a backtrace when rendering errors in 'comment' mode with 'debugging_comments' enabled" do
|
@@ -274,8 +259,8 @@ describe Inversion::RenderState do
|
|
274
259
|
state << node
|
275
260
|
output = state.to_s
|
276
261
|
|
277
|
-
output.
|
278
|
-
output.
|
262
|
+
expect( output ).to include( "<!-- NoMethodError: undefined method `klang' for nil:NilClass" )
|
263
|
+
expect( output ).to include( "#{__FILE__}:#{__LINE__ - 4}" )
|
279
264
|
end
|
280
265
|
|
281
266
|
it "re-raises errors while rendering appended nodes in 'propagate' mode" do
|
@@ -302,8 +287,8 @@ describe Inversion::RenderState do
|
|
302
287
|
end
|
303
288
|
}.to_not raise_error()
|
304
289
|
|
305
|
-
state.to_s.
|
306
|
-
state.errhandler.
|
290
|
+
expect( state.to_s ).to match( /yum, i eat nomethoderror/i )
|
291
|
+
expect( state.errhandler ).to equal( defhandler )
|
307
292
|
end
|
308
293
|
|
309
294
|
it "raises an exception if the error handler is set to something that doesn't respond to #call" do
|
@@ -332,7 +317,7 @@ describe Inversion::RenderState do
|
|
332
317
|
end
|
333
318
|
|
334
319
|
it "doesn't have any subscriptions by default" do
|
335
|
-
@state.subscriptions.
|
320
|
+
expect( @state.subscriptions ).to eq( {} )
|
336
321
|
end
|
337
322
|
|
338
323
|
it "allows an object to subscribe to node publications" do
|
@@ -340,8 +325,8 @@ describe Inversion::RenderState do
|
|
340
325
|
|
341
326
|
@state.subscribe( :the_key, subscriber )
|
342
327
|
|
343
|
-
@state.subscriptions.
|
344
|
-
@state.subscriptions[
|
328
|
+
expect( @state.subscriptions.size ).to eq( 1 )
|
329
|
+
expect( @state.subscriptions[:the_key] ).to eq( [subscriber] )
|
345
330
|
end
|
346
331
|
|
347
332
|
end
|
@@ -354,19 +339,19 @@ describe Inversion::RenderState do
|
|
354
339
|
end
|
355
340
|
|
356
341
|
it "allows rendering to be explicitly enabled and disabled" do
|
357
|
-
@state.rendering_enabled
|
342
|
+
expect( @state.rendering_enabled? ).to be_truthy()
|
358
343
|
@state.disable_rendering
|
359
|
-
@state.rendering_enabled
|
344
|
+
expect( @state.rendering_enabled? ).to be_falsey()
|
360
345
|
@state.enable_rendering
|
361
|
-
@state.rendering_enabled
|
346
|
+
expect( @state.rendering_enabled? ).to be_truthy()
|
362
347
|
end
|
363
348
|
|
364
349
|
it "allows rendering to be toggled" do
|
365
|
-
@state.rendering_enabled
|
350
|
+
expect( @state.rendering_enabled? ).to be_truthy()
|
366
351
|
@state.toggle_rendering
|
367
|
-
@state.rendering_enabled
|
352
|
+
expect( @state.rendering_enabled? ).to be_falsey()
|
368
353
|
@state.toggle_rendering
|
369
|
-
@state.rendering_enabled
|
354
|
+
expect( @state.rendering_enabled? ).to be_truthy()
|
370
355
|
end
|
371
356
|
|
372
357
|
it "doesn't render nodes that are appended to it if rendering is disabled" do
|
@@ -376,7 +361,7 @@ describe Inversion::RenderState do
|
|
376
361
|
@state.enable_rendering
|
377
362
|
@state << Inversion::Template::TextNode.new( "after" )
|
378
363
|
|
379
|
-
@state.to_s.
|
364
|
+
expect( @state.to_s ).to eq( 'beforeafter' )
|
380
365
|
end
|
381
366
|
|
382
367
|
end
|
@@ -390,7 +375,7 @@ describe Inversion::RenderState do
|
|
390
375
|
|
391
376
|
|
392
377
|
it "knows how many floating-point seconds have passed since it was created" do
|
393
|
-
@state.time_elapsed.
|
378
|
+
expect( @state.time_elapsed ).to be_a( Float )
|
394
379
|
end
|
395
380
|
|
396
381
|
end
|
@@ -409,7 +394,7 @@ describe Inversion::RenderState do
|
|
409
394
|
state << Inversion::Template::AttrTag.new( 'good_doggie' )
|
410
395
|
state << Inversion::Template::AttrTag.new( 'little' )
|
411
396
|
|
412
|
-
state.to_s.encoding.
|
397
|
+
expect( state.to_s.encoding ).to be( Encoding::UTF_8 )
|
413
398
|
end
|
414
399
|
|
415
400
|
it "replaces characters with undefined conversions instead of raising an encoding error" do
|
@@ -426,7 +411,76 @@ describe Inversion::RenderState do
|
|
426
411
|
state << Inversion::Template::AttrTag.new( 'okay' )
|
427
412
|
state << Inversion::Template::AttrTag.new( 'bogus' )
|
428
413
|
|
429
|
-
state.to_s.encoding.
|
414
|
+
expect( state.to_s.encoding ).to be( Encoding::UTF_8 )
|
415
|
+
end
|
416
|
+
|
417
|
+
end
|
418
|
+
|
419
|
+
|
420
|
+
describe "fragments" do
|
421
|
+
|
422
|
+
before( :each ) do
|
423
|
+
@state = Inversion::RenderState.new
|
424
|
+
end
|
425
|
+
|
426
|
+
|
427
|
+
it "can be set to an Array of rendered nodes" do
|
428
|
+
subscribe_node = Inversion::Template::SubscribeTag.new( 'brand' )
|
429
|
+
@state << subscribe_node
|
430
|
+
|
431
|
+
publish_node = Inversion::Template::PublishTag.new( 'brand' )
|
432
|
+
publish_node << Inversion::Template::TextNode.new( 'Acme' )
|
433
|
+
@state << publish_node
|
434
|
+
|
435
|
+
@state.add_fragment( :title, "Welcome to the ", subscribe_node, " website!" )
|
436
|
+
|
437
|
+
expect( @state.fragments ).to be_a( Hash )
|
438
|
+
expect( @state.fragments[:title] ).to eq([ "Welcome to the ", subscribe_node, " website!" ])
|
439
|
+
end
|
440
|
+
|
441
|
+
|
442
|
+
it "can be returned as a rendered Hash" do
|
443
|
+
subscribe_node = Inversion::Template::SubscribeTag.new( 'brand' )
|
444
|
+
@state << subscribe_node
|
445
|
+
|
446
|
+
publish_node = Inversion::Template::PublishTag.new( 'brand' )
|
447
|
+
publish_node << Inversion::Template::TextNode.new( 'Acme' )
|
448
|
+
@state << publish_node
|
449
|
+
|
450
|
+
@state.add_fragment( :title, "Welcome to the ", subscribe_node, " website!" )
|
451
|
+
|
452
|
+
expect( @state.rendered_fragments ).to be_a( Hash )
|
453
|
+
expect( @state.rendered_fragments[:title] ).to eq( "Welcome to the Acme website!" )
|
454
|
+
end
|
455
|
+
|
456
|
+
|
457
|
+
it "acts like a default if an attribute isn't set" do
|
458
|
+
node = Inversion::Template::FragmentTag.new( 'pork' )
|
459
|
+
node << Inversion::Template::AttrTag.new( 'bool' )
|
460
|
+
node << Inversion::Template::TextNode.new( ' please!' )
|
461
|
+
|
462
|
+
@state.scope[ :bool ] = 'yes'
|
463
|
+
@state << node
|
464
|
+
@state << Inversion::Template::TextNode.new( '--> ' )
|
465
|
+
@state << Inversion::Template::AttrTag.new( 'pork' )
|
466
|
+
@state << Inversion::Template::TextNode.new( ' <--' )
|
467
|
+
|
468
|
+
expect( @state.to_s ).to eq( '--> yes please! <--' )
|
469
|
+
end
|
470
|
+
|
471
|
+
|
472
|
+
it "don't override explicitly-set attributes" do
|
473
|
+
node = Inversion::Template::FragmentTag.new( 'pork' )
|
474
|
+
node << Inversion::Template::AttrTag.new( 'bool' )
|
475
|
+
node << Inversion::Template::TextNode.new( ' please!' )
|
476
|
+
|
477
|
+
@state.scope[ :pork ] = 'pie'
|
478
|
+
@state << node
|
479
|
+
@state << Inversion::Template::TextNode.new( '--> ' )
|
480
|
+
@state << Inversion::Template::AttrTag.new( 'pork' )
|
481
|
+
@state << Inversion::Template::TextNode.new( ' <--' )
|
482
|
+
|
483
|
+
expect( @state.to_s ).to eq( '--> pie <--' )
|
430
484
|
end
|
431
485
|
|
432
486
|
end
|