inversion 0.0.1
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 +2 -0
- data/.gemtest +0 -0
- data/ChangeLog +836 -0
- data/History.md +4 -0
- data/Manifest.txt +74 -0
- data/README.rdoc +171 -0
- data/Rakefile +55 -0
- data/bin/inversion +276 -0
- data/lib/inversion.rb +98 -0
- data/lib/inversion/exceptions.rb +21 -0
- data/lib/inversion/mixins.rb +236 -0
- data/lib/inversion/monkeypatches.rb +20 -0
- data/lib/inversion/renderstate.rb +337 -0
- data/lib/inversion/sinatra.rb +35 -0
- data/lib/inversion/template.rb +250 -0
- data/lib/inversion/template/attrtag.rb +120 -0
- data/lib/inversion/template/calltag.rb +16 -0
- data/lib/inversion/template/codetag.rb +164 -0
- data/lib/inversion/template/commenttag.rb +54 -0
- data/lib/inversion/template/conditionaltag.rb +49 -0
- data/lib/inversion/template/configtag.rb +60 -0
- data/lib/inversion/template/containertag.rb +45 -0
- data/lib/inversion/template/elsetag.rb +62 -0
- data/lib/inversion/template/elsiftag.rb +49 -0
- data/lib/inversion/template/endtag.rb +55 -0
- data/lib/inversion/template/escapetag.rb +26 -0
- data/lib/inversion/template/fortag.rb +120 -0
- data/lib/inversion/template/iftag.rb +69 -0
- data/lib/inversion/template/importtag.rb +70 -0
- data/lib/inversion/template/includetag.rb +51 -0
- data/lib/inversion/template/node.rb +102 -0
- data/lib/inversion/template/parser.rb +297 -0
- data/lib/inversion/template/pptag.rb +28 -0
- data/lib/inversion/template/publishtag.rb +72 -0
- data/lib/inversion/template/subscribetag.rb +88 -0
- data/lib/inversion/template/tag.rb +150 -0
- data/lib/inversion/template/textnode.rb +43 -0
- data/lib/inversion/template/unlesstag.rb +60 -0
- data/lib/inversion/template/uriencodetag.rb +30 -0
- data/lib/inversion/template/yieldtag.rb +51 -0
- data/lib/inversion/tilt.rb +82 -0
- data/lib/inversion/utils.rb +235 -0
- data/spec/data/sinatra/hello.inversion +1 -0
- data/spec/inversion/mixins_spec.rb +177 -0
- data/spec/inversion/monkeypatches_spec.rb +35 -0
- data/spec/inversion/renderstate_spec.rb +291 -0
- data/spec/inversion/sinatra_spec.rb +59 -0
- data/spec/inversion/template/attrtag_spec.rb +216 -0
- data/spec/inversion/template/calltag_spec.rb +30 -0
- data/spec/inversion/template/codetag_spec.rb +51 -0
- data/spec/inversion/template/commenttag_spec.rb +84 -0
- data/spec/inversion/template/configtag_spec.rb +105 -0
- data/spec/inversion/template/containertag_spec.rb +54 -0
- data/spec/inversion/template/elsetag_spec.rb +105 -0
- data/spec/inversion/template/elsiftag_spec.rb +87 -0
- data/spec/inversion/template/endtag_spec.rb +78 -0
- data/spec/inversion/template/escapetag_spec.rb +59 -0
- data/spec/inversion/template/fortag_spec.rb +98 -0
- data/spec/inversion/template/iftag_spec.rb +241 -0
- data/spec/inversion/template/importtag_spec.rb +106 -0
- data/spec/inversion/template/includetag_spec.rb +108 -0
- data/spec/inversion/template/node_spec.rb +81 -0
- data/spec/inversion/template/parser_spec.rb +170 -0
- data/spec/inversion/template/pptag_spec.rb +51 -0
- data/spec/inversion/template/publishtag_spec.rb +69 -0
- data/spec/inversion/template/subscribetag_spec.rb +60 -0
- data/spec/inversion/template/tag_spec.rb +97 -0
- data/spec/inversion/template/textnode_spec.rb +86 -0
- data/spec/inversion/template/unlesstag_spec.rb +84 -0
- data/spec/inversion/template/uriencodetag_spec.rb +49 -0
- data/spec/inversion/template/yieldtag_spec.rb +54 -0
- data/spec/inversion/template_spec.rb +269 -0
- data/spec/inversion/tilt_spec.rb +47 -0
- data/spec/inversion_spec.rb +95 -0
- data/spec/lib/constants.rb +9 -0
- data/spec/lib/helpers.rb +160 -0
- metadata +316 -0
- metadata.gz.sig +0 -0
@@ -0,0 +1,106 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd -b
|
2
|
+
# vim: set noet nosta sw=4 ts=4 :
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname( __FILE__ ).dirname.parent.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'
|
15
|
+
require 'inversion/template/importtag'
|
16
|
+
|
17
|
+
describe Inversion::Template::ImportTag do
|
18
|
+
|
19
|
+
before( :all ) do
|
20
|
+
setup_logging( :fatal )
|
21
|
+
end
|
22
|
+
|
23
|
+
after( :all ) do
|
24
|
+
reset_logging()
|
25
|
+
end
|
26
|
+
|
27
|
+
it "can import a single attribute" do
|
28
|
+
tag = Inversion::Template::ImportTag.new( 'txn ' )
|
29
|
+
tag.attributes.should == [ :txn ]
|
30
|
+
end
|
31
|
+
|
32
|
+
it "can import multiple attributes" do
|
33
|
+
tag = Inversion::Template::ImportTag.new( 'txn, applet' )
|
34
|
+
tag.attributes.should == [ :txn, :applet ]
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
context "with a single attribute name" do
|
39
|
+
|
40
|
+
before( :each ) do
|
41
|
+
@subtemplate = Inversion::Template.new( '<?import foo ?><?attr foo ?>' )
|
42
|
+
end
|
43
|
+
|
44
|
+
it "copies the named value from the enclosing template" do
|
45
|
+
outside = Inversion::Template.new( '<?attr foo ?><?attr subtemplate ?>' )
|
46
|
+
outside.subtemplate = @subtemplate
|
47
|
+
outside.foo = 'Froo'
|
48
|
+
|
49
|
+
outside.render.should == 'FrooFroo'
|
50
|
+
end
|
51
|
+
|
52
|
+
it "doesn't override values set explicitly on the subtemplate" do
|
53
|
+
outside = Inversion::Template.new( '<?attr foo ?><?attr subtemplate ?>' )
|
54
|
+
outside.subtemplate = @subtemplate
|
55
|
+
outside.foo = 'Froo'
|
56
|
+
|
57
|
+
@subtemplate.foo = 'Frar'
|
58
|
+
|
59
|
+
outside.render.should == 'FrooFrar'
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
context "with multiple attribute names" do
|
66
|
+
|
67
|
+
before( :each ) do
|
68
|
+
source = '<?import foo, bar ?><?attr foo.capitalize ?>: ' +
|
69
|
+
'<?attr bar.capitalize ?><?attr baz ?>'
|
70
|
+
@subtemplate = Inversion::Template.new( source )
|
71
|
+
end
|
72
|
+
|
73
|
+
it "copies the named value from the enclosing template" do
|
74
|
+
outside = Inversion::Template.new( '<?attr subtemplate ?>' )
|
75
|
+
outside.subtemplate = @subtemplate
|
76
|
+
outside.foo = 'mission'
|
77
|
+
outside.bar = 'accomplished'
|
78
|
+
|
79
|
+
outside.render.should == 'Mission: Accomplished'
|
80
|
+
end
|
81
|
+
|
82
|
+
it "doesn't override values set explicitly on the subtemplate" do
|
83
|
+
outside = Inversion::Template.new( '<?attr subtemplate ?>' )
|
84
|
+
outside.subtemplate = @subtemplate
|
85
|
+
outside.foo = 'mission'
|
86
|
+
outside.bar = 'accomplished'
|
87
|
+
|
88
|
+
@subtemplate.bar = 'abandoned'
|
89
|
+
|
90
|
+
outside.render.should == 'Mission: Abandoned'
|
91
|
+
end
|
92
|
+
|
93
|
+
it "only imports listed attributes" do
|
94
|
+
outside = Inversion::Template.new( '<?attr subtemplate ?>' )
|
95
|
+
outside.subtemplate = @subtemplate
|
96
|
+
outside.foo = 'Attributes'
|
97
|
+
outside.bar = 'Just This One'
|
98
|
+
outside.baz = 'And Not This One'
|
99
|
+
|
100
|
+
outside.render.should == 'Attributes: Just this one'
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
|
@@ -0,0 +1,108 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd -b
|
2
|
+
# vim: set noet nosta sw=4 ts=4 :
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname( __FILE__ ).dirname.parent.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 'timeout'
|
14
|
+
require 'rspec'
|
15
|
+
require 'spec/lib/helpers'
|
16
|
+
require 'inversion/template'
|
17
|
+
require 'inversion/template/includetag'
|
18
|
+
|
19
|
+
describe Inversion::Template::IncludeTag do
|
20
|
+
|
21
|
+
before( :all ) do
|
22
|
+
setup_logging( :fatal )
|
23
|
+
end
|
24
|
+
|
25
|
+
after( :all ) do
|
26
|
+
reset_logging()
|
27
|
+
end
|
28
|
+
|
29
|
+
|
30
|
+
it "renders the IncludeTag as an empty string" do
|
31
|
+
included_path = Pathname.pwd + 'included.tmpl'
|
32
|
+
FileTest.stub( :exist? ).with( included_path.to_s ).and_return true
|
33
|
+
IO.stub( :read ).with( included_path.to_s ).and_return( 'there,' )
|
34
|
+
|
35
|
+
tmpl = Inversion::Template.new( "hi <?include included.tmpl ?> handsome!" )
|
36
|
+
tmpl.render.should == "hi there, handsome!"
|
37
|
+
end
|
38
|
+
|
39
|
+
|
40
|
+
it "renders debugging comments with the included template path" do
|
41
|
+
included_path = Pathname.pwd + 'included.tmpl'
|
42
|
+
FileTest.stub( :exist? ).with( included_path.to_s ).and_return true
|
43
|
+
IO.stub( :read ).with( included_path.to_s ).and_return( 'there,' )
|
44
|
+
|
45
|
+
tmpl = Inversion::Template.
|
46
|
+
new( "hi <?include included.tmpl ?> handsome!", :debugging_comments => true )
|
47
|
+
tmpl.render.should =~ /Include "included\.tmpl"/
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
it "appends the nodes from a separate template onto the including template" do
|
52
|
+
included_path = Pathname.pwd + 'included.tmpl'
|
53
|
+
FileTest.stub( :exist? ).with( included_path.to_s ).and_return true
|
54
|
+
IO.stub( :read ).with( included_path.to_s ).and_return( 'there,' )
|
55
|
+
|
56
|
+
tmpl = Inversion::Template.new( "hi <?include included.tmpl ?> handsome!" )
|
57
|
+
tmpl.node_tree.should have(4).members
|
58
|
+
tmpl.node_tree[0].should be_a( Inversion::Template::TextNode )
|
59
|
+
tmpl.node_tree[1].should be_a( Inversion::Template::IncludeTag )
|
60
|
+
tmpl.node_tree[2].should be_a( Inversion::Template::TextNode )
|
61
|
+
tmpl.node_tree[3].should be_a( Inversion::Template::TextNode )
|
62
|
+
end
|
63
|
+
|
64
|
+
|
65
|
+
it "allows the same template to be included multiple times" do
|
66
|
+
included_path = Pathname.pwd + 'included.tmpl'
|
67
|
+
FileTest.stub( :exist? ).with( included_path.to_s ).and_return true
|
68
|
+
IO.stub( :read ).with( included_path.to_s ).and_return( ' hi' )
|
69
|
+
|
70
|
+
tmpl = Inversion::Template.
|
71
|
+
new( "hi<?include included.tmpl ?><?include included.tmpl ?> handsome!" )
|
72
|
+
tmpl.render.should == "hi hi hi handsome!"
|
73
|
+
end
|
74
|
+
|
75
|
+
|
76
|
+
it "raises exception on include loops" do
|
77
|
+
included_path = Pathname.pwd + 'included.tmpl'
|
78
|
+
FileTest.stub( :exist? ).with( included_path.to_s ).and_return true
|
79
|
+
IO.stub( :read ).with( included_path.to_s ).and_return( "<?include included.tmpl ?>" )
|
80
|
+
|
81
|
+
expect {
|
82
|
+
Inversion::Template.new( "hi <?include included.tmpl ?> handsome!" )
|
83
|
+
}.to raise_error( Inversion::StackError, /Recursive load .+"included.tmpl"/ )
|
84
|
+
end
|
85
|
+
|
86
|
+
|
87
|
+
it "raises exception on complex include loops" do
|
88
|
+
top_path = Pathname.pwd + 'top.tmpl'
|
89
|
+
middle_path = Pathname.pwd + 'middle.tmpl'
|
90
|
+
bottom_path = Pathname.pwd + 'bottom.tmpl'
|
91
|
+
|
92
|
+
FileTest.stub( :exist? ).with( top_path.to_s ).and_return true
|
93
|
+
IO.stub( :read ).with( top_path.to_s ).and_return( "<?include middle.tmpl ?>" )
|
94
|
+
|
95
|
+
FileTest.stub( :exist? ).with( middle_path.to_s ).and_return true
|
96
|
+
IO.stub( :read ).with( middle_path.to_s ).and_return( "<?include bottom.tmpl ?>" )
|
97
|
+
|
98
|
+
FileTest.stub( :exist? ).with( bottom_path.to_s ).and_return true
|
99
|
+
IO.stub( :read ).with( bottom_path.to_s ).and_return( "<?include top.tmpl ?>" )
|
100
|
+
|
101
|
+
expect {
|
102
|
+
Inversion::Template.new( "hi <?include top.tmpl ?> handsome!" )
|
103
|
+
}.to raise_error( Inversion::StackError, /Recursive load .+"top.tmpl"/ )
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
|
108
|
+
|
@@ -0,0 +1,81 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd -b
|
2
|
+
# vim: set noet nosta sw=4 ts=4 :
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname( __FILE__ ).dirname.parent.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'
|
15
|
+
require 'inversion/template/node'
|
16
|
+
|
17
|
+
describe Inversion::Template::Node do
|
18
|
+
|
19
|
+
let( :concrete_subclass ) { Class.new(Inversion::Template::Node) }
|
20
|
+
|
21
|
+
it "is an abstract class" do
|
22
|
+
expect {
|
23
|
+
Inversion::Template::Node.new( '' )
|
24
|
+
}.to raise_exception( NoMethodError, /private method `new'/i )
|
25
|
+
end
|
26
|
+
|
27
|
+
it "defaults to using inspect to render itself as a comment" do
|
28
|
+
node = concrete_subclass.new( '' )
|
29
|
+
node.as_comment_body.should == node.inspect
|
30
|
+
end
|
31
|
+
|
32
|
+
it "isn't a container" do
|
33
|
+
node = concrete_subclass.new( '' )
|
34
|
+
node.should_not be_a_container()
|
35
|
+
end
|
36
|
+
|
37
|
+
it "knows where it was parsed from if constructed with a position" do
|
38
|
+
node = concrete_subclass.new( '', 4, 12 )
|
39
|
+
node.location.should =~ /line 4, column 12/
|
40
|
+
end
|
41
|
+
|
42
|
+
it "knows that it was created from an unknown location if created without a position" do
|
43
|
+
node = concrete_subclass.new( '' )
|
44
|
+
node.location.should == 'line ??, column ??'
|
45
|
+
end
|
46
|
+
|
47
|
+
it "doesn't raise an exception when the before_appending event callback is called" do
|
48
|
+
state = double( "parser state" )
|
49
|
+
node = concrete_subclass.new( '' )
|
50
|
+
expect {
|
51
|
+
node.before_appending( state )
|
52
|
+
}.to_not raise_error()
|
53
|
+
end
|
54
|
+
|
55
|
+
it "doesn't raise an exception when the after_appending event callback is called" do
|
56
|
+
state = double( "parser state" )
|
57
|
+
node = concrete_subclass.new( '' )
|
58
|
+
expect {
|
59
|
+
node.after_appending( state )
|
60
|
+
}.to_not raise_error()
|
61
|
+
end
|
62
|
+
|
63
|
+
it "doesn't raise an exception when the before_rendering event callback is called" do
|
64
|
+
state = double( "render state" )
|
65
|
+
node = concrete_subclass.new( '' )
|
66
|
+
expect {
|
67
|
+
node.before_rendering( state )
|
68
|
+
}.to_not raise_error()
|
69
|
+
end
|
70
|
+
|
71
|
+
it "doesn't raise an exception when the after_rendering event callback is called" do
|
72
|
+
state = double( "render state" )
|
73
|
+
node = concrete_subclass.new( '' )
|
74
|
+
expect {
|
75
|
+
node.after_rendering( state )
|
76
|
+
}.to_not raise_error()
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
|
@@ -0,0 +1,170 @@
|
|
1
|
+
#!/usr/bin/env rspec -cfd -b
|
2
|
+
# vim: set noet nosta sw=4 ts=4 :
|
3
|
+
|
4
|
+
BEGIN {
|
5
|
+
require 'pathname'
|
6
|
+
basedir = Pathname( __FILE__ ).dirname.parent.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'
|
15
|
+
require 'inversion/template/parser'
|
16
|
+
|
17
|
+
describe Inversion::Template::Parser do
|
18
|
+
|
19
|
+
before( :all ) do
|
20
|
+
setup_logging( :fatal )
|
21
|
+
Inversion::Template::Tag.load_all
|
22
|
+
end
|
23
|
+
|
24
|
+
before( :each ) do
|
25
|
+
@template = double( "An Inversion::Template" )
|
26
|
+
end
|
27
|
+
|
28
|
+
it "parses a string with no PIs as a single text node" do
|
29
|
+
result = Inversion::Template::Parser.new( @template ).parse( "render unto Caesar" )
|
30
|
+
|
31
|
+
result.should have( 1 ).member
|
32
|
+
result.first.should be_a( Inversion::Template::TextNode )
|
33
|
+
result.first.body.should == 'render unto Caesar'
|
34
|
+
end
|
35
|
+
|
36
|
+
it "parses an empty string as a empty tree" do
|
37
|
+
result = Inversion::Template::Parser.new( @template ).parse( "" )
|
38
|
+
result.should be_empty
|
39
|
+
end
|
40
|
+
|
41
|
+
it "raises a ParseError on mismatched tag brackets" do
|
42
|
+
expect {
|
43
|
+
Inversion::Template::Parser.new( @template ).parse( '[?foo bar ?>' )
|
44
|
+
}.to raise_error( Inversion::ParseError, /mismatched start and end brackets/i )
|
45
|
+
end
|
46
|
+
|
47
|
+
it "parses a string with a single 'attr' tag as a single AttrTag node" do
|
48
|
+
result = Inversion::Template::Parser.new( @template ).parse( "<?attr foo ?>" )
|
49
|
+
|
50
|
+
result.should have( 1 ).member
|
51
|
+
result.first.should be_a( Inversion::Template::AttrTag )
|
52
|
+
result.first.body.should == 'foo'
|
53
|
+
end
|
54
|
+
|
55
|
+
it "parses a single 'attr' tag surrounded by plain text" do
|
56
|
+
result = Inversion::Template::Parser.new( @template ).parse( "beginning<?attr foo ?>end" )
|
57
|
+
|
58
|
+
result.should have( 3 ).members
|
59
|
+
result[0].should be_a( Inversion::Template::TextNode )
|
60
|
+
result[1].should be_a( Inversion::Template::AttrTag )
|
61
|
+
result[1].body.should == 'foo'
|
62
|
+
result[2].should be_a( Inversion::Template::TextNode )
|
63
|
+
end
|
64
|
+
|
65
|
+
it "ignores unknown tags by default" do
|
66
|
+
result = Inversion::Template::Parser.new( @template ).parse( "Text <?hoooowhat ?>" )
|
67
|
+
|
68
|
+
result.should have( 2 ).members
|
69
|
+
result[0].should be_a( Inversion::Template::TextNode )
|
70
|
+
result[1].should be_a( Inversion::Template::TextNode )
|
71
|
+
result[1].body.should == '<?hoooowhat ?>'
|
72
|
+
end
|
73
|
+
|
74
|
+
it "can raise exceptions on unknown tags" do
|
75
|
+
expect {
|
76
|
+
Inversion::Template::Parser.new( @template, :ignore_unknown_tags => false ).
|
77
|
+
parse( "Text <?hoooowhat ?>" )
|
78
|
+
}.to raise_exception( Inversion::ParseError, /unknown tag/i )
|
79
|
+
end
|
80
|
+
|
81
|
+
it "can raise exceptions on unclosed (nested) tags" do
|
82
|
+
expect {
|
83
|
+
Inversion::Template::Parser.new( @template ).parse( "Text <?attr something <?attr something_else ?>" )
|
84
|
+
}.to raise_exception( Inversion::ParseError, /unclosed or nested tag/i )
|
85
|
+
end
|
86
|
+
|
87
|
+
it "can raise exceptions on unclosed (eof) tags" do
|
88
|
+
expect {
|
89
|
+
Inversion::Template::Parser.new( @template ).parse( "Text <?hoooowhat" )
|
90
|
+
}.to raise_exception( Inversion::ParseError, /unclosed tag/i )
|
91
|
+
end
|
92
|
+
|
93
|
+
|
94
|
+
describe Inversion::Template::Parser::State do
|
95
|
+
|
96
|
+
before( :each ) do
|
97
|
+
@state = Inversion::Template::Parser::State.new( @template )
|
98
|
+
end
|
99
|
+
|
100
|
+
it "returns the node tree if it's well-formed" do
|
101
|
+
open_tag = Inversion::Template::ForTag.new( 'foo in bar' )
|
102
|
+
end_tag = Inversion::Template::EndTag.new( 'for' )
|
103
|
+
|
104
|
+
@state << open_tag << end_tag
|
105
|
+
|
106
|
+
@state.tree.should == [ open_tag, end_tag ]
|
107
|
+
end
|
108
|
+
|
109
|
+
it "knows it is well-formed if there are no open tags" do
|
110
|
+
@state << Inversion::Template::ForTag.new( 'foo in bar' )
|
111
|
+
@state.should_not be_well_formed
|
112
|
+
|
113
|
+
@state << Inversion::Template::ForTag.new( 'foo in bar' )
|
114
|
+
@state.should_not be_well_formed
|
115
|
+
|
116
|
+
@state << Inversion::Template::EndTag.new( 'for' )
|
117
|
+
@state.should_not be_well_formed
|
118
|
+
|
119
|
+
@state << Inversion::Template::EndTag.new( 'for' )
|
120
|
+
@state.should be_well_formed
|
121
|
+
end
|
122
|
+
|
123
|
+
it "can pop a container tag off of the current context" do
|
124
|
+
container = Inversion::Template::ForTag.new( 'foo in bar' )
|
125
|
+
@state << container
|
126
|
+
@state.pop.should == container
|
127
|
+
end
|
128
|
+
|
129
|
+
it "calls the #after_appending hook of container nodes when they're popped" do
|
130
|
+
container = mock( "container tag", :before_appending => false, :is_container? => true )
|
131
|
+
@state << container
|
132
|
+
|
133
|
+
container.should_receive( :after_appending ).with( @state )
|
134
|
+
@state.pop
|
135
|
+
end
|
136
|
+
|
137
|
+
it "raises an error when popping if there is no container tag" do
|
138
|
+
expect {
|
139
|
+
@state.pop
|
140
|
+
}.to raise_exception( Inversion::ParseError, /unbalanced end: no open tag/i )
|
141
|
+
end
|
142
|
+
|
143
|
+
it "raises an error when the tree is fetched if it isn't well-formed" do
|
144
|
+
open_tag = Inversion::Template::ForTag.new( 'foo in bar' )
|
145
|
+
@state << open_tag
|
146
|
+
|
147
|
+
expect {
|
148
|
+
@state.tree
|
149
|
+
}.to raise_exception( Inversion::ParseError, /unclosed/i )
|
150
|
+
end
|
151
|
+
|
152
|
+
it "calls the #before_appending callback on nodes that are appended to it" do
|
153
|
+
node = mock( "node", :is_container? => false, :after_appending => nil )
|
154
|
+
node.should_receive( :before_appending ).with( @state )
|
155
|
+
|
156
|
+
@state << node
|
157
|
+
end
|
158
|
+
|
159
|
+
it "calls the #after_appending callback on nodes that are appended to it" do
|
160
|
+
node = mock( "node", :is_container? => false, :before_appending => nil )
|
161
|
+
node.should_receive( :after_appending ).with( @state )
|
162
|
+
|
163
|
+
@state << node
|
164
|
+
end
|
165
|
+
|
166
|
+
|
167
|
+
end
|
168
|
+
|
169
|
+
end
|
170
|
+
|