inversion 0.12.3 → 0.14.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.
- 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
|