tadpole 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. data/LICENSE +22 -0
  2. data/README.html +222 -0
  3. data/README.markdown +259 -0
  4. data/benchmarks/eval-vs-non-eval.rb +13 -0
  5. data/benchmarks/require-vs-none.rb +10 -0
  6. data/benchmarks/run-caching.rb +20 -0
  7. data/examples/example1/custom/html/body/important.html +4 -0
  8. data/examples/example1/custom/html/body/setup.rb +6 -0
  9. data/examples/example1/custom/html/setup.rb +3 -0
  10. data/examples/example1/default/html/body/info.erb +3 -0
  11. data/examples/example1/default/html/body/setup.rb +11 -0
  12. data/examples/example1/default/html/main.haml +6 -0
  13. data/examples/example1/default/html/setup.rb +3 -0
  14. data/examples/example1/run.rb +6 -0
  15. data/examples/example2/run.rb +5 -0
  16. data/examples/example2/tadpole/html/content.haml +5 -0
  17. data/examples/example2/tadpole/html/main.haml +17 -0
  18. data/examples/example2/tadpole/html/readme/setup.rb +6 -0
  19. data/examples/example2/tadpole/html/setup.rb +6 -0
  20. data/examples/example2/tadpole/markdown/copyright.md +5 -0
  21. data/examples/example2/tadpole/markdown/examples.md +76 -0
  22. data/examples/example2/tadpole/markdown/quick/create.md +34 -0
  23. data/examples/example2/tadpole/markdown/quick/heirarchical.md +34 -0
  24. data/examples/example2/tadpole/markdown/quick/override.md +28 -0
  25. data/examples/example2/tadpole/markdown/quick/quick.erb +5 -0
  26. data/examples/example2/tadpole/markdown/quick/setup.rb +4 -0
  27. data/examples/example2/tadpole/markdown/readme/readme_notice.txt +7 -0
  28. data/examples/example2/tadpole/markdown/readme/setup.rb +4 -0
  29. data/examples/example2/tadpole/markdown/setup.rb +3 -0
  30. data/examples/example2/tadpole/markdown/title.md +5 -0
  31. data/examples/example2/tadpole/markdown/what.md +25 -0
  32. data/examples/example2/tadpole/markdown/why.md +41 -0
  33. data/lib/tadpole/filters.rb +50 -0
  34. data/lib/tadpole/local_template.rb +32 -0
  35. data/lib/tadpole/main.rb +125 -0
  36. data/lib/tadpole/providers/erb.rb +26 -0
  37. data/lib/tadpole/providers/file.rb +9 -0
  38. data/lib/tadpole/providers/haml.rb +21 -0
  39. data/lib/tadpole/providers/markaby.rb +7 -0
  40. data/lib/tadpole/providers/section_provider.rb +62 -0
  41. data/lib/tadpole/providers/template.rb +24 -0
  42. data/lib/tadpole/template.rb +258 -0
  43. data/lib/tadpole.rb +32 -0
  44. data/spec/basic_spec.rb +88 -0
  45. data/spec/examples/filters/a.txt +0 -0
  46. data/spec/examples/filters/b.txt +0 -0
  47. data/spec/examples/filters/setup.rb +9 -0
  48. data/spec/examples/render/1/a.txt +1 -0
  49. data/spec/examples/render/1/b.txt +1 -0
  50. data/spec/examples/render/1/d.erb +1 -0
  51. data/spec/examples/render/1/setup.rb +13 -0
  52. data/spec/examples/render/2/setup.rb +9 -0
  53. data/spec/examples/render/3/setup.rb +12 -0
  54. data/spec/examples/render/4/a.erb +1 -0
  55. data/spec/examples/render/4/setup.rb +9 -0
  56. data/spec/examples/render/5/setup.rb +17 -0
  57. data/spec/examples/render/6/setup.rb +12 -0
  58. data/spec/filters_spec.rb +37 -0
  59. data/spec/render_spec.rb +32 -0
  60. metadata +136 -0
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2008 Loren Segal
2
+
3
+ Permission is hereby granted, free of charge, to any person
4
+ obtaining a copy of this software and associated documentation
5
+ files (the "Software"), to deal in the Software without
6
+ restriction, including without limitation the rights to use,
7
+ copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ copies of the Software, and to permit persons to whom the
9
+ Software is furnished to do so, subject to the following
10
+ conditions:
11
+
12
+ The above copyright notice and this permission notice shall be
13
+ included in all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
17
+ OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
19
+ HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
20
+ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21
+ FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
22
+ OTHER DEALINGS IN THE SOFTWARE.
data/README.html ADDED
@@ -0,0 +1,222 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
2
+ <html>
3
+ <head>
4
+ <title>Tadpole: A Small but Extensible Templating Engine</title>
5
+ </head>
6
+ <body>
7
+ <div id='page'>
8
+ <div id='title'>
9
+ <h1>Tadpole: A Small but Extensible Templating Engine for Ruby</h1>
10
+
11
+ <p><em>Created by <a href="http://www.gnuu.org">Loren Segal</a> in 2008</em></p>
12
+ </div>
13
+ <div id='content'>
14
+ <ol>
15
+ <li id='#&lt;Tadpole::SectionProviders::TemplateProvider:0x5bba6c&gt;'>
16
+ <h2>Quick How-To's</h2>
17
+
18
+ <h3>Create a Template</h3>
19
+
20
+ <p>Creating a template is literally as easy as 1-2-3:</p>
21
+
22
+ <ol>
23
+ <li><p>Create your templates in a directory. All directories are templates and all templates
24
+ are directories. The directory name will be the (or part of) the name of your template.
25
+ Example for template <code>mytemplate</code>:</p>
26
+
27
+ <pre><code>templates/&#x000A; mytemplate/&#x000A; setup.rb&#x000A; section1.erb&#x000A; section2.haml&#x000A; copyright.html&#x000A;</code></pre></li>
28
+ <li><p>Setup the "<em>table of contents</em>" of your sections in the <code>setup.rb</code>:</p>
29
+
30
+ <pre><code>def init&#x000A; super&#x000A; sections 'section1', 'section2', 'copyright'&#x000A;end&#x000A;</code></pre>
31
+
32
+ <p>Your sections can include another template (directory). This will call whatever
33
+ sections were part of that other template.</p>
34
+
35
+ <p>A directory does not <em>require</em> a <code>section.rb</code>. If it is not supplied, it will inherit
36
+ the setup file from its parent (including its sections).</p></li>
37
+ <li><p>Register the <code>templates</code> path as your root template directory and run the template:</p>
38
+
39
+ <pre><code>require 'tadpole'&#x000A;Tadpole.register_template_path 'path/to/templates'&#x000A;Tadpole('mytemplate').run&#x000A;</code></pre></li>
40
+ </ol>
41
+
42
+ <h3>Override a Template</h3>
43
+
44
+ <p>You can override templates by simply registering another template_path and creating
45
+ a template of the same name in the new path. Using the <code>mytemplate</code> example from above
46
+ we can now make a directory:</p>
47
+
48
+ <pre><code>custom_templates/&#x000A; mytemplate/&#x000A; setup.rb&#x000A; header.erb&#x000A;</code></pre>
49
+
50
+ <p>This template will <em>inherit</em> from the template above. Our <code>setup.rb</code> will therefore
51
+ contain:</p>
52
+
53
+ <pre><code>def init&#x000A; super&#x000A; sections.unshift 'header'&#x000A;end&#x000A;</code></pre>
54
+
55
+ <p>And to run this file all we need to do is:</p>
56
+
57
+ <pre><code>require 'tadpole'&#x000A;Tadpole.register_template_path 'path/to/templates' # Register base template path&#x000A;Tadpole.register_template_path 'path/to/custom_templates' # Register overridden template path&#x000A;&#x000A;# Running our template will now add our 'header' file to the output&#x000A;Tadpole('mytemplate').run&#x000A;</code></pre>
58
+
59
+ <h3>Heirarchical Sections</h3>
60
+
61
+ <p>Sometimes you may need to encapsulate the output of some sections inside another one. An HTML
62
+ template, for example, will usually contain the page body inside the body tag of a more general
63
+ "header" template. To set this up, you use the following <code>sections</code> call:</p>
64
+
65
+ <pre><code>sections 'header', ['section1', 'section2', 'copyright']&#x000A;</code></pre>
66
+
67
+ <p>You can then call these from your <code>header.erb</code> file as simple yields. Each yield renders
68
+ one section in the sub-list:</p>
69
+
70
+ <pre><code>&lt;html&gt;&#x000A; &lt;body&gt;&#x000A; &lt;h1&gt;Section 1&lt;/h1&gt;&#x000A; &lt;%= yield %&gt;&#x000A;&#x000A; &lt;h1&gt;Section 2&lt;/h1&gt;&#x000A; &lt;%= yield %&gt;&#x000A;&#x000A; &lt;h1&gt;Copyright&lt;/h1&gt;&#x000A; &lt;%= yield %&gt;&#x000A; &lt;/body&gt;&#x000A;&lt;/html&gt;&#x000A;</code></pre>
71
+
72
+ <p>Alternatively you can yield all sub-sections with the convenience call <code>all_sections</code>
73
+ (in the following <a href="http://haml.hamptoncatlin.com">Haml</a> example, yield param 's'
74
+ contains the section name which would serve as the li's id attribute):</p>
75
+
76
+ <pre><code>%html&#x000A; %body&#x000A; %ol&#x000A; - all_sections do |s|&#x000A; %li{:id =&gt; s}= yield&#x000A;</code></pre>
77
+ </li>
78
+ <li id='#&lt;Tadpole::SectionProviders::FileProvider:0x5a7f1c&gt;'>
79
+ <h2>What is Tadpole?</h2>
80
+
81
+ <p><strong>Tadpole</strong> is a small templating engine that attempts to solve a problem that
82
+ no other templating engine does: <em>extensibility</em>. When dealing with templates,
83
+ most engines focus on the formatting of the output content while forgetting about
84
+ the important task a developer faces of hooking all these 'views' together. While
85
+ it may seem trivial and worth ignoring, in reality, many templates become plagued
86
+ with complexity and coupling due to the lack of support beyond the mere presentation
87
+ of a single file.</p>
88
+
89
+ <p><strong>Tadpole</strong> deals not with the formatting or translation or markup, but rather
90
+ with the organization of the data as it is outputted. In fact, <strong>Tadpole</strong> is not
91
+ markup at all, nor does it care what markup you use, having out of the box support
92
+ for the obvious template languages in Ruby (ERB, <a href="http://www.haml.hamptoncatlin.com">Haml</a>,
93
+ <a href="http://code.whytheluckystiff.net/markaby">Markaby</a>, <a href="http://builder.rubyforge.org">Builder</a>)
94
+ and the ability to add more. <strong>Tadpole is all about information organization, not formatting</strong>.</p>
95
+
96
+ <p>If you need a good visualization of what <strong>Tadpole</strong> is, think of it as <em>the table of</em>
97
+ <em>contents for your views</em>. Just as it is important to designing each view and partial of
98
+ your template, it is important to decide in what order these views will ultimately be
99
+ organized. <strong>Tadpole</strong>'s job is to store nothing but your table of contents, and then
100
+ spit it out when you're ready to show it to the world. This technique becomes very
101
+ powerful in some potentially familiar scenarios. (<em>See the "Real World Examples"</em>)</p>
102
+ </li>
103
+ <li id='#&lt;Tadpole::SectionProviders::FileProvider:0x5a76c0&gt;'>
104
+ <h2>Why Tadpole?</h2>
105
+
106
+ <p>Sufficed to say, you might be wondering what the <em>big deal</em> is. I mean, you're
107
+ probably getting along just fine without this new concept of tables of contents
108
+ ...<em>or so you think</em>. The truth is that there are a lot of real-world scenarios
109
+ where the old-style template production simply doesn't cut it. I can say this
110
+ because <strong>Tadpole</strong> was <a href="http://www.github.com/lsegal/yard">born from one of them</a>.</p>
111
+
112
+ <p>I'll be honest, <strong>Tadpole</strong> does not meet every use-case scenario, and it probably
113
+ never will. But if you're writing a <em>blog app</em>, <em>CMS</em>, customizable <em>forum software</em> or
114
+ anything that will eventually support <em>customizable templates</em> or <em>theming</em>,
115
+ <em><strong>Tadpole</strong> was made for you</em>. Even if you're just dealing with a lot of <em>template</em>
116
+ <em>coupling</em> or <em>internationalization code</em>, there's a good chance you're looking at the
117
+ right tool as well.</p>
118
+
119
+ <h3>Good With Customizable Themes, You Say?</h3>
120
+
121
+ <p>Anyone who writes customizable software knows that it requires a lot of de-coupled code.
122
+ While templates are sometimes considered support files rather than actual software, the
123
+ same law holds true for them. Coupled templates are bad for theming because your users
124
+ can't get at the data they want.</p>
125
+
126
+ <p>The standard solution to this problem is to split your templates up into many 'partials'.
127
+ That way, any user can just go into the right partial and easily edit what they need
128
+ without copying <em>all</em> of the template data, right? <strong>Wrong</strong>. The problem starts when a
129
+ user wants to start adding or removing partials altogether. In fact, it's actually the
130
+ smallest changes that cause the biggest problems. Everytime they add one line to every
131
+ new partial, they pull in another entire file. Once <em>you</em> update that file, the changes
132
+ no longer sync to the user. Fixed a typo in your template? Your user may never get the
133
+ memo if he pulled in the file you touched. However, because <strong>Tadpole</strong> never actually
134
+ deals with template <em>data</em>, the same setup in <strong>Tadpole</strong> would not be problematic.
135
+ Using <strong>Tadpole</strong>, the user would never even have to touch your templates given a good
136
+ set of insertion points.</p>
137
+
138
+ <p>The lesson is, when it comes to customization, there is no partial that is partial enough.
139
+ <strong>Tadpole</strong> inevitably suffers from this problem as well. However, once you start thinking
140
+ in terms of template organization you'll find that it's much harder to decide what part
141
+ of a view deserves a 'partial' than it is to simply split your template up into a series
142
+ of cohesive "<em>sections</em>".</p>
143
+ </li>
144
+ <li id='#&lt;Tadpole::SectionProviders::FileProvider:0x5a7094&gt;'>
145
+ <h2>Some <em>Theoretically</em>-Real-World Examples of Tadpole in Action</h2>
146
+
147
+ <ol>
148
+ <li><p><em>Bob</em> made a Blogging application called <em>"Boblog"</em> and distributed it under the
149
+ MIT license over the internet. <em>Janet</em> found this application and decided to
150
+ use it to power her upcoming "100 Carrot Recipes" blog. She was mostly happy with
151
+ the provided themes but wanted to customize the look of the sidebar by adding a
152
+ "Favourite Recipes" links section and writing a tidbit about herself. Now "Boblog"
153
+ was a simplistic blog tool and did not support a multitude of plugins, but did use
154
+ <strong>Tadpole</strong> for theming. Janet read about the way customization was done using "Boblog"
155
+ and got to work making her changes. Janet went into her custom templates directory and
156
+ created her own new template <code>janet</code> because she had a bad feeling about directly playing
157
+ with the existing template files (<em>and "Boblog" docs said she didn't need to</em>). Inside
158
+ that directory she created her new files <code>fav_recipes.html</code> and <code>about.html</code> where she
159
+ inserted her links to various world renowned Carrot Chefs and a story about her dreams
160
+ of one day meeting them. Now, she wanted her about section to go at the top of the sidebar,
161
+ but she wanted her own links section to go beneath the regular links section (already
162
+ provided by "Boblog"). So, as per the docs, she continued to add a <code>setup.rb</code> file which
163
+ would connect her new files together with the template. In this file, she simply wrote:</p>
164
+
165
+ <pre><code>inherits 'default_theme'&#x000A;&#x000A;&#x000A;def init&#x000A; super&#x000A; sections.unshift 'about'&#x000A; sections.place('fav_recipes').before('links')&#x000A;end&#x000A;</code></pre>
166
+
167
+ <p>She then went into "Boblog"'s administration interface and selected the new <code>janet</code>
168
+ theme. Voila, her dream of tasty success would finally come true.</p>
169
+
170
+ <p>Three days later, <em>Bob</em> got word from an anonymous tipster of a nasty bug in his software
171
+ that could potentially lead to harmful attacks if left unfixed. Guess what, that bug was
172
+ in the sidebar template that Janet was using! He quickly patched the bug and released a
173
+ fix, notifying all of his users of the changes (Janet was on his mailing list). Because
174
+ Janet never edited any of the files belonging to "Boblog", all she had to do was download
175
+ the patch and restart the application without ever having to remake all of her ever-so-
176
+ important theming changes to her blog.</p></li>
177
+ <li><p>Midget Inc. is working on a colourful new site redesign for their mobile widget business.
178
+ They sell mobile widgets to customers all across the globe and have very strict legal
179
+ procedures they need to follow when advertising their mobile widgets. In one specific
180
+ region, they are required by law to show a disclaimer above any advertising images they
181
+ display. Rather than place region specific logic inside a partial view, they decide to
182
+ use <strong>Tadpole</strong> to handle their templating system. They decide to use a folder structure
183
+ of the following to display their advertising page:</p>
184
+
185
+ <pre><code>advertising/&#x000A; setup.rb&#x000A; content.erb&#x000A; images.erb&#x000A; fr/&#x000A; setup.rb&#x000A; disclaimer.erb&#x000A;</code></pre>
186
+
187
+ <p><code>advertising/setup.rb</code> contains the following:</p>
188
+
189
+ <pre><code>def init; super; sections 'content', 'images' end&#x000A;</code></pre>
190
+
191
+ <p>The <code>fr/</code> subdirectory contains the specific content they need for the law-requiring region
192
+ and the logic to render this template only in that region is controlled by the controller.
193
+ Because the <code>fr/</code> template automatically inherits its sections from its parent, all they need
194
+ to do to set up this new logic is put the following in the <code>fr/setup.rb</code>:</p>
195
+
196
+ <pre><code>def init&#x000A; super&#x000A; sections.place('disclaimer').before('images')&#x000A;end&#x000A;</code></pre>
197
+
198
+ <p>And the templates can be rendered with:</p>
199
+
200
+ <pre><code>Tadpole('advertising').run&#x000A;Tadpole('advertising/fr').run&#x000A;</code></pre>
201
+
202
+ <p>Respectively.</p></li>
203
+ </ol>
204
+ </li>
205
+ <li id='#&lt;Tadpole::SectionProviders::FileProvider:0x5a6aa4&gt;'>
206
+ <h2>You Should Also Know</h2>
207
+
208
+ <p>That this <code>README</code> was generated by <strong>Tadpole</strong>. Try it:</p>
209
+
210
+ <pre><code>ruby examples/example2/run.rb markdown/readme&#x000A;</code></pre>
211
+ </li>
212
+ </ol>
213
+ </div>
214
+ <div id='copyright'>
215
+ <h2>Copyright &amp; Licensing Information</h2>
216
+
217
+ <p><em>Copyright 2008 Loren Segal.</em>
218
+ <em>All code licensed under the MIT License.</em></p>
219
+ </div>
220
+ </div>
221
+ </body>
222
+ </html>
data/README.markdown ADDED
@@ -0,0 +1,259 @@
1
+ Tadpole: A Small but Extensible Templating Engine for Ruby
2
+ ==========================================================
3
+
4
+ _Created by [Loren Segal](http://www.gnuu.org) in 2008_
5
+
6
+ Quick How-To's
7
+ --------------
8
+
9
+ ### Create a Template
10
+
11
+ Creating a template is literally as easy as 1-2-3:
12
+
13
+ 1. Create your templates in a directory. All directories are templates and all templates
14
+ are directories. The directory name will be the (or part of) the name of your template.
15
+ Example for template `mytemplate`:
16
+
17
+ templates/
18
+ mytemplate/
19
+ setup.rb
20
+ section1.erb
21
+ section2.haml
22
+ copyright.html
23
+
24
+ 2. Setup the "_table of contents_" of your sections in the `setup.rb`:
25
+
26
+ def init
27
+ super
28
+ sections 'section1', 'section2', 'copyright'
29
+ end
30
+
31
+ Your sections can include another template (directory). This will call whatever
32
+ sections were part of that other template.
33
+
34
+ A directory does not _require_ a `section.rb`. If it is not supplied, it will inherit
35
+ the setup file from its parent (including its sections).
36
+
37
+ 3. Register the `templates` path as your root template directory and run the template:
38
+
39
+ require 'tadpole'
40
+ Tadpole.register_template_path 'path/to/templates'
41
+ Tadpole('mytemplate').run
42
+
43
+ ### Override a Template
44
+
45
+ You can override templates by simply registering another template_path and creating
46
+ a template of the same name in the new path. Using the `mytemplate` example from above
47
+ we can now make a directory:
48
+
49
+ custom_templates/
50
+ mytemplate/
51
+ setup.rb
52
+ header.erb
53
+
54
+ This template will _inherit_ from the template above. Our `setup.rb` will therefore
55
+ contain:
56
+
57
+ def init
58
+ super
59
+ sections.unshift 'header'
60
+ end
61
+
62
+ And to run this file all we need to do is:
63
+
64
+ require 'tadpole'
65
+ Tadpole.register_template_path 'path/to/templates' # Register base template path
66
+ Tadpole.register_template_path 'path/to/custom_templates' # Register overridden template path
67
+
68
+ # Running our template will now add our 'header' file to the output
69
+ Tadpole('mytemplate').run
70
+
71
+ ### Heirarchical Sections
72
+
73
+ Sometimes you may need to encapsulate the output of some sections inside another one. An HTML
74
+ template, for example, will usually contain the page body inside the body tag of a more general
75
+ "header" template. To set this up, you use the following `sections` call:
76
+
77
+ sections 'header', ['section1', 'section2', 'copyright']
78
+
79
+ You can then call these from your `header.erb` file as simple yields. Each yield renders
80
+ one section in the sub-list:
81
+
82
+ <html>
83
+ <body>
84
+ <h1>Section 1</h1>
85
+ <%= yield %>
86
+
87
+ <h1>Section 2</h1>
88
+ <%= yield %>
89
+
90
+ <h1>Copyright</h1>
91
+ <%= yield %>
92
+ </body>
93
+ </html>
94
+
95
+ Alternatively you can yield all sub-sections with the convenience call `all_sections`
96
+ (in the following [Haml](http://haml.hamptoncatlin.com) example, yield param 's'
97
+ contains the section name which would serve as the li's id attribute):
98
+
99
+ %html
100
+ %body
101
+ %ol
102
+ - all_sections do |s|
103
+ %li{:id => s}= yield
104
+
105
+
106
+ What is Tadpole?
107
+ ----------------
108
+
109
+ **Tadpole** is a small templating engine that attempts to solve a problem that
110
+ no other templating engine does: _extensibility_. When dealing with templates,
111
+ most engines focus on the formatting of the output content while forgetting about
112
+ the important task a developer faces of hooking all these 'views' together. While
113
+ it may seem trivial and worth ignoring, in reality, many templates become plagued
114
+ with complexity and coupling due to the lack of support beyond the mere presentation
115
+ of a single file.
116
+
117
+ **Tadpole** deals not with the formatting or translation or markup, but rather
118
+ with the organization of the data as it is outputted. In fact, **Tadpole** is not
119
+ markup at all, nor does it care what markup you use, having out of the box support
120
+ for the obvious template languages in Ruby (ERB, [Haml](http://www.haml.hamptoncatlin.com),
121
+ [Markaby](http://code.whytheluckystiff.net/markaby), [Builder](http://builder.rubyforge.org))
122
+ and the ability to add more. **Tadpole is all about information organization, not formatting**.
123
+
124
+ If you need a good visualization of what **Tadpole** is, think of it as _the table of_
125
+ _contents for your views_. Just as it is important to designing each view and partial of
126
+ your template, it is important to decide in what order these views will ultimately be
127
+ organized. **Tadpole**'s job is to store nothing but your table of contents, and then
128
+ spit it out when you're ready to show it to the world. This technique becomes very
129
+ powerful in some potentially familiar scenarios. (_See the "Real World Examples"_)
130
+
131
+ Why Tadpole?
132
+ ------------
133
+
134
+ Sufficed to say, you might be wondering what the _big deal_ is. I mean, you're
135
+ probably getting along just fine without this new concept of tables of contents
136
+ ..._or so you think_. The truth is that there are a lot of real-world scenarios
137
+ where the old-style template production simply doesn't cut it. I can say this
138
+ because **Tadpole** was [born from one of them](http://www.github.com/lsegal/yard).
139
+
140
+ I'll be honest, **Tadpole** does not meet every use-case scenario, and it probably
141
+ never will. But if you're writing a _blog app_, _CMS_, customizable _forum software_ or
142
+ anything that will eventually support _customizable templates_ or _theming_,
143
+ _**Tadpole** was made for you_. Even if you're just dealing with a lot of _template_
144
+ _coupling_ or _internationalization code_, there's a good chance you're looking at the
145
+ right tool as well.
146
+
147
+ ### Good With Customizable Themes, You Say?
148
+
149
+ Anyone who writes customizable software knows that it requires a lot of de-coupled code.
150
+ While templates are sometimes considered support files rather than actual software, the
151
+ same law holds true for them. Coupled templates are bad for theming because your users
152
+ can't get at the data they want.
153
+
154
+ The standard solution to this problem is to split your templates up into many 'partials'.
155
+ That way, any user can just go into the right partial and easily edit what they need
156
+ without copying _all_ of the template data, right? __Wrong__. The problem starts when a
157
+ user wants to start adding or removing partials altogether. In fact, it's actually the
158
+ smallest changes that cause the biggest problems. Everytime they add one line to every
159
+ new partial, they pull in another entire file. Once _you_ update that file, the changes
160
+ no longer sync to the user. Fixed a typo in your template? Your user may never get the
161
+ memo if he pulled in the file you touched. However, because **Tadpole** never actually
162
+ deals with template _data_, the same setup in **Tadpole** would not be problematic.
163
+ Using **Tadpole**, the user would never even have to touch your templates given a good
164
+ set of insertion points.
165
+
166
+ The lesson is, when it comes to customization, there is no partial that is partial enough.
167
+ **Tadpole** inevitably suffers from this problem as well. However, once you start thinking
168
+ in terms of template organization you'll find that it's much harder to decide what part
169
+ of a view deserves a 'partial' than it is to simply split your template up into a series
170
+ of cohesive "_sections_".
171
+
172
+ Some _Theoretically_-Real-World Examples of Tadpole in Action
173
+ -----------------------------------------------------------
174
+
175
+ 1. _Bob_ made a Blogging application called _"Boblog"_ and distributed it under the
176
+ MIT license over the internet. _Janet_ found this application and decided to
177
+ use it to power her upcoming "100 Carrot Recipes" blog. She was mostly happy with
178
+ the provided themes but wanted to customize the look of the sidebar by adding a
179
+ "Favourite Recipes" links section and writing a tidbit about herself. Now "Boblog"
180
+ was a simplistic blog tool and did not support a multitude of plugins, but did use
181
+ **Tadpole** for theming. Janet read about the way customization was done using "Boblog"
182
+ and got to work making her changes. Janet went into her custom templates directory and
183
+ created her own new template `janet` because she had a bad feeling about directly playing
184
+ with the existing template files (_and "Boblog" docs said she didn't need to_). Inside
185
+ that directory she created her new files `fav_recipes.html` and `about.html` where she
186
+ inserted her links to various world renowned Carrot Chefs and a story about her dreams
187
+ of one day meeting them. Now, she wanted her about section to go at the top of the sidebar,
188
+ but she wanted her own links section to go beneath the regular links section (already
189
+ provided by "Boblog"). So, as per the docs, she continued to add a `setup.rb` file which
190
+ would connect her new files together with the template. In this file, she simply wrote:
191
+
192
+ inherits 'default_theme'
193
+
194
+ def init
195
+ super
196
+ sections.unshift 'about'
197
+ sections.place('fav_recipes').before('links')
198
+ end
199
+
200
+ She then went into "Boblog"'s administration interface and selected the new `janet`
201
+ theme. Voila, her dream of tasty success would finally come true.
202
+
203
+ Three days later, _Bob_ got word from an anonymous tipster of a nasty bug in his software
204
+ that could potentially lead to harmful attacks if left unfixed. Guess what, that bug was
205
+ in the sidebar template that Janet was using! He quickly patched the bug and released a
206
+ fix, notifying all of his users of the changes (Janet was on his mailing list). Because
207
+ Janet never edited any of the files belonging to "Boblog", all she had to do was download
208
+ the patch and restart the application without ever having to remake all of her ever-so-
209
+ important theming changes to her blog.
210
+
211
+ 2. Midget Inc. is working on a colourful new site redesign for their mobile widget business.
212
+ They sell mobile widgets to customers all across the globe and have very strict legal
213
+ procedures they need to follow when advertising their mobile widgets. In one specific
214
+ region, they are required by law to show a disclaimer above any advertising images they
215
+ display. Rather than place region specific logic inside a partial view, they decide to
216
+ use **Tadpole** to handle their templating system. They decide to use a folder structure
217
+ of the following to display their advertising page:
218
+
219
+ advertising/
220
+ setup.rb
221
+ content.erb
222
+ images.erb
223
+ fr/
224
+ setup.rb
225
+ disclaimer.erb
226
+
227
+ `advertising/setup.rb` contains the following:
228
+
229
+ def init; super; sections 'content', 'images' end
230
+
231
+ The `fr/` subdirectory contains the specific content they need for the law-requiring region
232
+ and the logic to render this template only in that region is controlled by the controller.
233
+ Because the `fr/` template automatically inherits its sections from its parent, all they need
234
+ to do to set up this new logic is put the following in the `fr/setup.rb`:
235
+
236
+ def init
237
+ super
238
+ sections.place('disclaimer').before('images')
239
+ end
240
+
241
+ And the templates can be rendered with:
242
+
243
+ Tadpole('advertising').run
244
+ Tadpole('advertising/fr').run
245
+
246
+ Respectively.
247
+
248
+ You Should Also Know
249
+ --------------------
250
+
251
+ That this `README` was generated by **Tadpole**. Try it:
252
+
253
+ ruby examples/example2/run.rb markdown/readme
254
+
255
+ Copyright & Licensing Information
256
+ ---------------------------------
257
+
258
+ _Copyright 2008 Loren Segal._
259
+ _All code licensed under the MIT License._
@@ -0,0 +1,13 @@
1
+ require "benchmark"
2
+
3
+ TIMES = 10_000
4
+
5
+ module A
6
+ Benchmark.bmbm do |x|
7
+ x.report("eval") { TIMES.times { eval("x = 2", binding) } }
8
+ x.report("instance-eval") { TIMES.times { instance_eval "x = 2" } }
9
+ x.report("module-eval") { TIMES.times { module_eval "x = 2"} }
10
+ x.report("class-eval") { TIMES.times { class_eval "x = 2"} }
11
+ x.report("non-eval") { TIMES.times { x = 2 } }
12
+ end
13
+ end
@@ -0,0 +1,10 @@
1
+ require "benchmark"
2
+
3
+ TIMES = 10_000
4
+
5
+ Benchmark.bmbm do |x|
6
+ x.report("require") { TIMES.times { require 'benchmark' } }
7
+ x.report("none") { TIMES.times { } }
8
+ end
9
+
10
+ # Conclusion: require is expensive.
@@ -0,0 +1,20 @@
1
+ require "benchmark"
2
+ require File.dirname(__FILE__) + '/../lib/tadpole'
3
+
4
+ Tadpole.register_template_path File.dirname(__FILE__) + '/../examples/example1'
5
+
6
+ TESTS = 1
7
+
8
+ Benchmark.bm do |b|
9
+ b.report("no-cache") do
10
+ Tadpole.caching = false
11
+ t = Tadpole('custom/html').new
12
+ TESTS.times { t.run(:object => 1) }
13
+ end
14
+
15
+ b.report("cache ") do
16
+ Tadpole.caching = true
17
+ t = Tadpole('custom/html').new
18
+ TESTS.times { t.run(:object => 1) }
19
+ end
20
+ end
@@ -0,0 +1,4 @@
1
+ <!-- custom template only -->
2
+ <h1>Important note from the offices of the president:</h1>
3
+ <p>All your base are belong to us.</p>
4
+ <!-- end custom template -->
@@ -0,0 +1,6 @@
1
+ inherits '/default/html/body'
2
+
3
+ def init
4
+ super
5
+ sections[1,0] = 'important.html'
6
+ end
@@ -0,0 +1,3 @@
1
+ inherits '/default/html'
2
+
3
+
@@ -0,0 +1,3 @@
1
+ <% helper_method do |number| %>
2
+ <p><%= number %></p>
3
+ <% end %>
@@ -0,0 +1,11 @@
1
+ def init
2
+ sections 'info', :copyright
3
+ end
4
+
5
+ def copyright; "<div id='copyright'>Copyright 2008 Loren Segal</div>" end
6
+
7
+ def helper_method
8
+ [1,2,3,4,5].each do |num|
9
+ yield num
10
+ end
11
+ end
@@ -0,0 +1,6 @@
1
+ %html
2
+ %head
3
+ %title This is my page
4
+ %body
5
+ %h1= object
6
+ #content= render(:body)
@@ -0,0 +1,3 @@
1
+ def init
2
+ sections 'main'
3
+ end
@@ -0,0 +1,6 @@
1
+ require File.dirname(__FILE__) + '/../../lib/tadpole'
2
+
3
+ Tadpole.register_template_path File.dirname(__FILE__)
4
+
5
+ myobj = "Tadpole!"
6
+ puts Tadpole(:custom, :html).run(:object => myobj)
@@ -0,0 +1,5 @@
1
+ require File.dirname(__FILE__) + '/../../lib/tadpole'
2
+
3
+ Tadpole.register_template_path File.dirname(__FILE__)
4
+
5
+ puts Tadpole(:tadpole, ARGV[0]||'html').run
@@ -0,0 +1,5 @@
1
+ %ol
2
+ - all_sections do |s|
3
+ %li{:id => s}
4
+ :markdown
5
+ #{yield}
@@ -0,0 +1,17 @@
1
+ !!!
2
+ %html
3
+ %head
4
+ %title Tadpole: A Small but Extensible Templating Engine
5
+
6
+ %body
7
+ #page
8
+ #title
9
+ :markdown
10
+ #{yield}
11
+
12
+ #content= yield
13
+
14
+ #copyright
15
+ :markdown
16
+ #{yield}
17
+
@@ -0,0 +1,6 @@
1
+ inherits '../../markdown/readme'
2
+
3
+ def init
4
+ super
5
+ sections[1][2].push('readme_notice')
6
+ end