inversion 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (50) hide show
  1. data.tar.gz.sig +0 -0
  2. data/Manifest.txt +45 -0
  3. data/lib/inversion.rb +2 -2
  4. data/lib/inversion/template/begintag.rb +122 -0
  5. data/lib/inversion/template/defaulttag.rb +135 -0
  6. data/lib/inversion/template/rescuetag.rb +92 -0
  7. data/lib/inversion/template/timedeltatag.rb +93 -0
  8. data/manual/layouts/default.erb +87 -0
  9. data/manual/lib/api-filter.rb +96 -0
  10. data/manual/lib/editorial-filter.rb +59 -0
  11. data/manual/lib/examples-filter.rb +238 -0
  12. data/manual/lib/links-filter.rb +111 -0
  13. data/manual/resources/css/manual.css +764 -0
  14. data/manual/resources/fonts/GraublauWeb.otf +0 -0
  15. data/manual/resources/fonts/GraublauWebBold.otf +0 -0
  16. data/manual/resources/fonts/Inconsolata.otf +0 -0
  17. data/manual/resources/images/arrow_225_small.png +0 -0
  18. data/manual/resources/images/arrow_315_small.png +0 -0
  19. data/manual/resources/images/arrow_skip.png +0 -0
  20. data/manual/resources/images/cc-by.png +0 -0
  21. data/manual/resources/images/dialog-error.png +0 -0
  22. data/manual/resources/images/dialog-information.png +0 -0
  23. data/manual/resources/images/dialog-warning.png +0 -0
  24. data/manual/resources/images/emblem-important.png +0 -0
  25. data/manual/resources/images/help.png +0 -0
  26. data/manual/resources/images/information.png +0 -0
  27. data/manual/resources/images/magnifier.png +0 -0
  28. data/manual/resources/images/magnifier_left.png +0 -0
  29. data/manual/resources/images/page_white_code.png +0 -0
  30. data/manual/resources/images/page_white_copy.png +0 -0
  31. data/manual/resources/images/printer.png +0 -0
  32. data/manual/resources/images/question.png +0 -0
  33. data/manual/resources/images/scripts_code.png +0 -0
  34. data/manual/resources/images/wrap.png +0 -0
  35. data/manual/resources/images/wrapping.png +0 -0
  36. data/manual/resources/js/jquery-1.4.4.min.js +167 -0
  37. data/manual/resources/js/manual.js +30 -0
  38. data/manual/resources/js/sh.js +580 -0
  39. data/manual/resources/swf/clipboard.swf +0 -0
  40. data/manual/src/examples.page +154 -0
  41. data/manual/src/gettingstarted.page +64 -0
  42. data/manual/src/index.page +97 -0
  43. data/manual/src/tags.page +501 -0
  44. data/manual/src/templates.page +74 -0
  45. data/spec/inversion/template/begintag_spec.rb +217 -0
  46. data/spec/inversion/template/defaulttag_spec.rb +60 -0
  47. data/spec/inversion/template/rescuetag_spec.rb +109 -0
  48. data/spec/inversion/template/timedeltatag_spec.rb +215 -0
  49. metadata +72 -27
  50. metadata.gz.sig +0 -0
@@ -0,0 +1,74 @@
1
+ ---
2
+ # vim: set et nosta sw=4 ts=4 ft=textile :
3
+ title: Templates
4
+ layout: default
5
+ index: 1
6
+ filters:
7
+ - erb
8
+ - links
9
+ - api
10
+ - examples
11
+ - textile
12
+ ---
13
+
14
+ h2. <%= page.config['title'] %>
15
+
16
+ <div id="auto-toc"></div>
17
+
18
+ Inversion <?api "templates":Inversion::Template ?> are the primary objects you'll be interacting with. Templates can be created from a string via <?api "Template#new":Inversion::Template.new ?>, or from a file with <?api "Template#load":Inversion::Template.load ?>.
19
+
20
+ h3(#options). Template Options
21
+
22
+ You can set Inversion's configuration options in a number of ways.
23
+
24
+ To set global options, Inversion supports the "Configurability":https://bitbucket.org/ged/configurability API, and registers itself with the @templates@ key. This means you can either add a 'templates' section to your Configurability config, or call <?api Inversion::Template.configure ?> yourself with an object that can be passed to @Hash#merge@.
25
+
26
+ To set options on a per-template basis, you can pass an options hash to either @.load@ or @.new@, or set them from within the template itself using the <?link "configure tag":Tags#configure-tag ?>.
27
+
28
+ The available options are:
29
+
30
+ <notextile>
31
+ <dl>
32
+ <dt>:ignore_unknown_tags</dt>
33
+ <dd>Setting to false causes unknown tags used in templates to raise an <code>Inversion::ParseError</code>.</dd>
34
+ <dd class="default">Default: true</dd>
35
+
36
+ <dt>:on_render_error</dt>
37
+ <dd>
38
+ Dictates the behavior of exceptions during rendering.
39
+ <dl>
40
+ <dt>:ignore</dt>
41
+ <dd>Exceptions are silently ignored.</dd>
42
+ <dt>:comment</dt>
43
+ <dd>Exceptions are rendered inline as comments.</dd>
44
+ <dt>:propagate</dt>
45
+ <dd>Exceptions bubble up to the caller of #render.</dd>
46
+ </dl>
47
+ </dd>
48
+ <dd class="default">Default: <code>:comment</code></dd>
49
+
50
+ <dt>:debugging_comments</dt>
51
+ <dd>Insert various Inversion parse and render statements while rendering.</dd>
52
+ <dd class="default">Default: <code>false</code></dd>
53
+
54
+ <dt>:comment_start</dt>
55
+ <dd>When rendering debugging comments, the comment is started with these characters.</dd>
56
+ <dd class="default">Default: <code>"&lt;!--"</code></dd>
57
+
58
+ <dt>:comment_end</dt>
59
+ <dd>When rendering debugging comments, the comment is finished with these characters.</dd>
60
+ <dd class="default">Default: <code>"--&gt;"</code></dd>
61
+
62
+ <dt>:template_paths</dt>
63
+ <dd>An array of filesystem paths to search for templates within, when loaded or included with a relative path. The current working directory is always the last checked member of this.</dd>
64
+ <dd class="default">Default: <code>[]</code></dd>
65
+
66
+ <dt>:escape_format</dt>
67
+ <dd>The escaping <?api "strategy":Inversion::Escaping ?> used by tags such as <code>escape</code> and <code>pp</code>.</dd>
68
+ <dd class="default">Default: <code>:html</code></dd>
69
+
70
+ <dt>:strip_tag_lines</dt>
71
+ <dd>If a tag's presence introduces a blank line into the output, this option removes it.</dd>
72
+ <dd class="default">Default: <code>true</code></dd>
73
+ </dl>
74
+ </notextile>
@@ -0,0 +1,217 @@
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 'ostruct'
15
+ require 'spec/lib/helpers'
16
+ require 'inversion/template/begintag'
17
+ require 'inversion/template/textnode'
18
+ require 'inversion/template/attrtag'
19
+ require 'inversion/template/rescuetag'
20
+ require 'inversion/template/endtag'
21
+ require 'inversion/renderstate'
22
+
23
+ describe Inversion::Template::BeginTag do
24
+
25
+ before( :all ) do
26
+ setup_logging( :fatal )
27
+ end
28
+
29
+ after( :all ) do
30
+ reset_logging()
31
+ end
32
+
33
+
34
+ context "without any rescue clauses" do
35
+
36
+ before( :each ) do
37
+ @tag = Inversion::Template::BeginTag.new( ' ' )
38
+ @tag << Inversion::Template::AttrTag.new( 'foo.baz' )
39
+ @tag << Inversion::Template::TextNode.new( ':the stuff after the attr' )
40
+ end
41
+
42
+ it "should render its subnodes as-is if none of them raise an exception" do
43
+ renderstate = Inversion::RenderState.new( :foo => OpenStruct.new(:baz => 'the body') )
44
+ renderstate << @tag
45
+ renderstate.to_s.should == 'the body:the stuff after the attr'
46
+ end
47
+
48
+ it "should use the configured error behavior of the template if a subnode raises any exception" do
49
+ renderstate = Inversion::RenderState.new
50
+ renderstate << @tag
51
+ renderstate.to_s.should =~ /NoMethodError/
52
+ renderstate.to_s.should_not =~ /the stuff after the attr/i
53
+ end
54
+
55
+ end
56
+
57
+ context "with a single rescue clause with no exception type" do
58
+
59
+ before( :each ) do
60
+ @tag = Inversion::Template::BeginTag.new( ' ' )
61
+
62
+ @attrtag = Inversion::Template::AttrTag.new( 'foo.baz' )
63
+ @normal_textnode = Inversion::Template::TextNode.new( ':the stuff after the attr' )
64
+ @rescue_textnode = Inversion::Template::TextNode.new( 'rescue stuff' )
65
+
66
+ @tag << @attrtag << @normal_textnode
67
+ @tag << Inversion::Template::RescueTag.new( '' )
68
+ @tag << @rescue_textnode
69
+
70
+ @renderstate = Inversion::RenderState.new
71
+ end
72
+
73
+ it "contains one rescue clause for RuntimeErrors" do
74
+ @tag.rescue_clauses.should == [ [[::RuntimeError], [@rescue_textnode]] ]
75
+ end
76
+
77
+ it "should render its subnodes as-is if none of them raise an exception" do
78
+ renderstate = Inversion::RenderState.new( :foo => OpenStruct.new(:baz => 'the body') )
79
+ renderstate << @tag
80
+ renderstate.to_s.should == 'the body:the stuff after the attr'
81
+ end
82
+
83
+ it "should render the rescue section if a subnode raises a RuntimeError" do
84
+ fooobj = Object.new
85
+ def fooobj.baz; raise "An exception"; end
86
+
87
+ renderstate = Inversion::RenderState.new( :foo => fooobj )
88
+ renderstate << @tag
89
+ renderstate.to_s.should == 'rescue stuff'
90
+ end
91
+
92
+ it "should use the configured error behavior of the template if a subnode raises an " +
93
+ "exception other than RuntimeError" do
94
+ fooobj = Object.new
95
+ def fooobj.baz; raise Errno::ENOENT, "No such file or directory"; end
96
+
97
+ renderstate = Inversion::RenderState.new( :foo => fooobj )
98
+ renderstate << @tag
99
+ renderstate.to_s.should =~ /ENOENT/i
100
+ renderstate.to_s.should_not =~ /rescue stuff/i
101
+ renderstate.to_s.should_not =~ /the stuff after the attr/i
102
+ end
103
+ end
104
+
105
+
106
+ context "with a single rescue clause with an exception type" do
107
+ before( :each ) do
108
+ @tag = Inversion::Template::BeginTag.new( ' ' )
109
+
110
+ @attrtag = Inversion::Template::AttrTag.new( 'foo.baz' )
111
+ @normal_textnode = Inversion::Template::TextNode.new( ':the stuff after the attr' )
112
+ @rescue_textnode = Inversion::Template::TextNode.new( 'rescue stuff' )
113
+
114
+ @tag << @attrtag << @normal_textnode
115
+ @tag << Inversion::Template::RescueTag.new( 'SystemCallError' )
116
+ @tag << @rescue_textnode
117
+
118
+ @renderstate = Inversion::RenderState.new
119
+ end
120
+
121
+ it "contains one rescue clause for the specified exception type" do
122
+ @tag.rescue_clauses.should == [ [[::SystemCallError], [@rescue_textnode]] ]
123
+ end
124
+
125
+ it "should render its subnodes as-is if none of them raise an exception" do
126
+ renderstate = Inversion::RenderState.new( :foo => OpenStruct.new(:baz => 'the body') )
127
+ renderstate << @tag
128
+ renderstate.to_s.should == 'the body:the stuff after the attr'
129
+ end
130
+
131
+ it "should render the rescue section if a subnode raises the specified exception type" do
132
+ fooobj = Object.new
133
+ def fooobj.baz; raise Errno::ENOENT, "no such file or directory"; end
134
+
135
+ renderstate = Inversion::RenderState.new( :foo => fooobj )
136
+ renderstate << @tag
137
+ renderstate.to_s.should == 'rescue stuff'
138
+ end
139
+
140
+ it "should use the configured error behavior of the template if a subnode raises an " +
141
+ "exception other than the specified type" do
142
+ fooobj = Object.new
143
+ def fooobj.baz; raise "SPlat!"; end
144
+
145
+ renderstate = Inversion::RenderState.new( :foo => fooobj )
146
+ renderstate << @tag
147
+ renderstate.to_s.should =~ /RuntimeError/i
148
+ renderstate.to_s.should_not =~ /rescue stuff/i
149
+ renderstate.to_s.should_not =~ /the stuff after the attr/i
150
+ end
151
+ end
152
+
153
+ context "with multiple rescue clauses" do
154
+ before( :each ) do
155
+ @tag = Inversion::Template::BeginTag.new( ' ' )
156
+
157
+ @attrtag = Inversion::Template::AttrTag.new( 'foo.baz' )
158
+ @normal_textnode = Inversion::Template::TextNode.new( ':the stuff after the attr' )
159
+ @rescue_textnode = Inversion::Template::TextNode.new( 'rescue stuff' )
160
+ @rescue_textnode2 = Inversion::Template::TextNode.new( 'alternative rescue stuff' )
161
+
162
+ @tag << @attrtag << @normal_textnode
163
+ @tag << Inversion::Template::RescueTag.new( '' )
164
+ @tag << @rescue_textnode
165
+ @tag << Inversion::Template::RescueTag.new( 'Errno::ENOENT, Errno::EWOULDBLOCK' )
166
+ @tag << @rescue_textnode2
167
+
168
+ @renderstate = Inversion::RenderState.new
169
+ end
170
+
171
+ it "contains a rescue tuple for each rescue tag" do
172
+ @tag.rescue_clauses.should == [
173
+ [[::RuntimeError], [@rescue_textnode]],
174
+ [[Errno::ENOENT, Errno::EWOULDBLOCK], [@rescue_textnode2]],
175
+ ]
176
+ end
177
+
178
+ it "should render its subnodes as-is if none of them raise an exception" do
179
+ renderstate = Inversion::RenderState.new( :foo => OpenStruct.new(:baz => 'the body') )
180
+ renderstate << @tag
181
+ renderstate.to_s.should == 'the body:the stuff after the attr'
182
+ end
183
+
184
+ it "should render the first rescue section if a subnode raises the exception it " +
185
+ "specifies" do
186
+ fooobj = Object.new
187
+ def fooobj.baz; raise "An exception"; end
188
+
189
+ renderstate = Inversion::RenderState.new( :foo => fooobj )
190
+ renderstate << @tag
191
+ renderstate.to_s.should == 'rescue stuff'
192
+ end
193
+
194
+ it "should render the second rescue section if a subnode raises the exception it " +
195
+ "specifies" do
196
+ fooobj = Object.new
197
+ def fooobj.baz; raise Errno::ENOENT, "no such file or directory"; end
198
+
199
+ renderstate = Inversion::RenderState.new( :foo => fooobj )
200
+ renderstate << @tag
201
+ renderstate.to_s.should == 'alternative rescue stuff'
202
+ end
203
+
204
+ it "should use the configured error behavior of the template if a subnode raises an " +
205
+ "exception other than those specified by the rescue clauses" do
206
+ fooobj = Object.new
207
+ def fooobj.baz; raise Errno::ENOMEM, "All out!"; end
208
+
209
+ renderstate = Inversion::RenderState.new( :foo => fooobj )
210
+ renderstate << @tag
211
+ renderstate.to_s.should =~ /ENOMEM/i
212
+ renderstate.to_s.should_not =~ /rescue stuff/i
213
+ renderstate.to_s.should_not =~ /the stuff after the attr/i
214
+ end
215
+ end
216
+
217
+ end
@@ -0,0 +1,60 @@
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/defaulttag'
16
+
17
+ describe Inversion::Template::DefaultTag do
18
+
19
+ before( :all ) do
20
+ setup_logging( :fatal )
21
+ end
22
+
23
+ after( :all ) do
24
+ reset_logging()
25
+ end
26
+
27
+
28
+ it "sets a template attribute to a default value" do
29
+ tmpl = Inversion::Template.new( '<?default foo to 11883 ?><?attr foo ?>' )
30
+ tmpl.render.should == '11883'
31
+ end
32
+
33
+ it "doesn't override a value set on the template as an attribute" do
34
+ tmpl = Inversion::Template.new( '<?default foo to 11883 ?><?attr foo ?>' )
35
+ tmpl.foo = 'bar'
36
+ tmpl.render.should == 'bar'
37
+ end
38
+
39
+ it "can set a template attribute to the result of calling a methodchain" do
40
+ tmpl = Inversion::Template.
41
+ new( '<?default width to foo.length ?><?attr foo ?>:<?attr width ?>' )
42
+ tmpl.foo = 'bar'
43
+ tmpl.render.should == 'bar:3'
44
+ end
45
+
46
+ it "can format the default value" do
47
+ tmpl = Inversion::Template.
48
+ new( '<?default width to "[%02d]" % [ foo.length ] ?><?attr foo ?>:<?attr width ?>' )
49
+ tmpl.foo = 'bar'
50
+ tmpl.render.should == 'bar:[03]'
51
+ end
52
+
53
+ it "can render itself as a comment for template debugging" do
54
+ tag = Inversion::Template::DefaultTag.new( 'width to foo.length' )
55
+ tag.as_comment_body.should == "Default 'width': { template.foo.length }"
56
+ end
57
+
58
+ end
59
+
60
+
@@ -0,0 +1,109 @@
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/begintag'
16
+ require 'inversion/template/rescuetag'
17
+ require 'inversion/template/commenttag'
18
+ require 'inversion/template/fortag'
19
+ require 'inversion/renderstate'
20
+
21
+ describe Inversion::Template::RescueTag do
22
+
23
+ before( :all ) do
24
+ setup_logging( :fatal )
25
+ end
26
+
27
+ after( :all ) do
28
+ reset_logging()
29
+ end
30
+
31
+ it "handles a non-existant body" do
32
+ tag = Inversion::Template::RescueTag.new( nil )
33
+ tag.exception_types.should == [ ::RuntimeError ]
34
+ end
35
+
36
+ it "parses its body into classes" do
37
+ tag = Inversion::Template::RescueTag.new( 'ScriptError' )
38
+ tag.exception_types.should == [ ::ScriptError ]
39
+ end
40
+
41
+ it "handles fully-qualified class names" do
42
+ tag = Inversion::Template::RescueTag.new( '::ScriptError' )
43
+ tag.exception_types.should == [ ::ScriptError ]
44
+ end
45
+
46
+ it "can parse multiple exception class names" do
47
+ tag = Inversion::Template::RescueTag.new( '::ScriptError, Inversion::ParseError' )
48
+ tag.exception_types.should == [ ::ScriptError, Inversion::ParseError ]
49
+ end
50
+
51
+ it "can be appended to a 'begin' tag" do
52
+ template = double( "template object" )
53
+ parserstate = Inversion::Template::Parser::State.new( template )
54
+ begintag = Inversion::Template::BeginTag.new
55
+ rescuetag = Inversion::Template::RescueTag.new
56
+ textnode = Inversion::Template::TextNode.new( 'Yeah!' )
57
+ endtag = Inversion::Template::EndTag.new
58
+
59
+ parserstate << begintag << rescuetag << textnode << endtag
60
+
61
+ parserstate.tree.should == [ begintag, endtag ]
62
+ begintag.rescue_clauses.should == [ [[::RuntimeError], [textnode]] ]
63
+ end
64
+
65
+ it "can be appended to a 'comment' tag" do
66
+ template = double( "template object" )
67
+ parserstate = Inversion::Template::Parser::State.new( template )
68
+ commenttag = Inversion::Template::CommentTag.new( 'rescue section for later' )
69
+ rescuetag = Inversion::Template::RescueTag.new
70
+ endtag = Inversion::Template::EndTag.new
71
+
72
+ parserstate << commenttag << rescuetag << endtag
73
+
74
+ parserstate.tree.should == [ commenttag, endtag ]
75
+ commenttag.subnodes.should include( rescuetag )
76
+ end
77
+
78
+ it "raises an error if it's about to be appended to anything other than a 'begin' or " +
79
+ "'comment' tag" do
80
+ template = double( "template object" )
81
+ parserstate = Inversion::Template::Parser::State.new( template )
82
+ parserstate << Inversion::Template::ForTag.new( 'foo in bar' )
83
+
84
+ expect {
85
+ parserstate << Inversion::Template::RescueTag.new
86
+ }.to raise_exception( Inversion::ParseError, /'for' tags can't have 'rescue' clauses/i )
87
+ end
88
+
89
+
90
+ it "raises an error if it's about to be appended without an opening 'begin'" do
91
+ template = double( "template object" )
92
+ parserstate = Inversion::Template::Parser::State.new( template )
93
+
94
+ expect {
95
+ parserstate << Inversion::Template::RescueTag.new
96
+ }.to raise_exception( Inversion::ParseError, /orphaned 'rescue' tag/i )
97
+ end
98
+
99
+
100
+ it "doesn't render as anything by itself" do
101
+ renderstate = Inversion::RenderState.new
102
+ tag = Inversion::Template::RescueTag.new
103
+ tag.render( renderstate ).should be_nil()
104
+ end
105
+
106
+ end
107
+
108
+
109
+