porthole 0.99.4

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.
Files changed (70) hide show
  1. data/LICENSE +20 -0
  2. data/README.md +415 -0
  3. data/Rakefile +89 -0
  4. data/bin/porthole +94 -0
  5. data/lib/porthole.rb +304 -0
  6. data/lib/porthole/context.rb +142 -0
  7. data/lib/porthole/generator.rb +195 -0
  8. data/lib/porthole/parser.rb +263 -0
  9. data/lib/porthole/settings.rb +226 -0
  10. data/lib/porthole/sinatra.rb +205 -0
  11. data/lib/porthole/template.rb +58 -0
  12. data/lib/porthole/version.rb +3 -0
  13. data/lib/rack/bug/panels/mustache_panel.rb +81 -0
  14. data/lib/rack/bug/panels/mustache_panel/mustache_extension.rb +27 -0
  15. data/lib/rack/bug/panels/mustache_panel/view.mustache +46 -0
  16. data/man/porthole.1 +165 -0
  17. data/man/porthole.1.html +213 -0
  18. data/man/porthole.1.ron +127 -0
  19. data/man/porthole.5 +539 -0
  20. data/man/porthole.5.html +422 -0
  21. data/man/porthole.5.ron +324 -0
  22. data/test/autoloading_test.rb +56 -0
  23. data/test/fixtures/comments.porthole +1 -0
  24. data/test/fixtures/comments.rb +14 -0
  25. data/test/fixtures/complex_view.porthole +17 -0
  26. data/test/fixtures/complex_view.rb +34 -0
  27. data/test/fixtures/crazy_recursive.porthole +9 -0
  28. data/test/fixtures/crazy_recursive.rb +31 -0
  29. data/test/fixtures/delimiters.porthole +8 -0
  30. data/test/fixtures/delimiters.rb +23 -0
  31. data/test/fixtures/dot_notation.porthole +10 -0
  32. data/test/fixtures/dot_notation.rb +25 -0
  33. data/test/fixtures/double_section.porthole +7 -0
  34. data/test/fixtures/double_section.rb +14 -0
  35. data/test/fixtures/escaped.porthole +1 -0
  36. data/test/fixtures/escaped.rb +14 -0
  37. data/test/fixtures/inner_partial.porthole +1 -0
  38. data/test/fixtures/inner_partial.txt +1 -0
  39. data/test/fixtures/inverted_section.porthole +7 -0
  40. data/test/fixtures/inverted_section.rb +14 -0
  41. data/test/fixtures/lambda.porthole +7 -0
  42. data/test/fixtures/lambda.rb +31 -0
  43. data/test/fixtures/method_missing.rb +19 -0
  44. data/test/fixtures/namespaced.porthole +1 -0
  45. data/test/fixtures/namespaced.rb +25 -0
  46. data/test/fixtures/nested_objects.porthole +17 -0
  47. data/test/fixtures/nested_objects.rb +35 -0
  48. data/test/fixtures/node.porthole +8 -0
  49. data/test/fixtures/partial_with_module.porthole +4 -0
  50. data/test/fixtures/partial_with_module.rb +37 -0
  51. data/test/fixtures/passenger.conf +5 -0
  52. data/test/fixtures/passenger.rb +27 -0
  53. data/test/fixtures/recursive.porthole +4 -0
  54. data/test/fixtures/recursive.rb +14 -0
  55. data/test/fixtures/simple.porthole +5 -0
  56. data/test/fixtures/simple.rb +26 -0
  57. data/test/fixtures/template_partial.porthole +2 -0
  58. data/test/fixtures/template_partial.rb +18 -0
  59. data/test/fixtures/template_partial.txt +4 -0
  60. data/test/fixtures/unescaped.porthole +1 -0
  61. data/test/fixtures/unescaped.rb +14 -0
  62. data/test/fixtures/utf8.porthole +3 -0
  63. data/test/fixtures/utf8_partial.porthole +1 -0
  64. data/test/helper.rb +7 -0
  65. data/test/parser_test.rb +78 -0
  66. data/test/partial_test.rb +168 -0
  67. data/test/porthole_test.rb +677 -0
  68. data/test/spec_test.rb +68 -0
  69. data/test/template_test.rb +20 -0
  70. metadata +127 -0
data/LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2009 Chris Wanstrath
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,415 @@
1
+ # GO AWAY
2
+
3
+ You ended up here by mistake. This project is stupid and is only valuable
4
+ if you need (not "want") to use "%%foo%%" for your templates, rather than
5
+ "{{foo}}".
6
+
7
+ Porthole
8
+ ========
9
+
10
+ Inspired by [ctemplate][1] and [et][2], Porthole is a
11
+ framework-agnostic way to render logic-free views.
12
+
13
+ As ctemplates says, "It emphasizes separating logic from presentation:
14
+ it is impossible to embed application logic in this template language."
15
+
16
+ For a list of implementations (other than Ruby) and tips, see
17
+ <http://porthole.github.com/>.
18
+
19
+
20
+ Overview
21
+ --------
22
+
23
+ Think of Porthole as a replacement for your views. Instead of views
24
+ consisting of ERB or HAML with random helpers and arbitrary logic,
25
+ your views are broken into two parts: a Ruby class and an HTML
26
+ template.
27
+
28
+ We call the Ruby class the "view" and the HTML template the
29
+ "template."
30
+
31
+ All your logic, decisions, and code is contained in your view. All
32
+ your markup is contained in your template. The template does nothing
33
+ but reference methods in your view.
34
+
35
+ This strict separation makes it easier to write clean templates,
36
+ easier to test your views, and more fun to work on your app's front end.
37
+
38
+
39
+ Why?
40
+ ----
41
+
42
+ I like writing Ruby. I like writing HTML. I like writing JavaScript.
43
+
44
+ I don't like writing ERB, Haml, Liquid, Django Templates, putting Ruby
45
+ in my HTML, or putting JavaScript in my HTML.
46
+
47
+
48
+ Usage
49
+ -----
50
+
51
+ Quick example:
52
+
53
+ >> require 'porthole'
54
+ => true
55
+ >> Porthole.render("Hello %%planet%%", :planet => "World!")
56
+ => "Hello World!"
57
+
58
+ We've got an `examples` folder but here's the canonical one:
59
+
60
+ class Simple < Porthole
61
+ def name
62
+ "Chris"
63
+ end
64
+
65
+ def value
66
+ 10_000
67
+ end
68
+
69
+ def taxed_value
70
+ value * 0.6
71
+ end
72
+
73
+ def in_ca
74
+ true
75
+ end
76
+ end
77
+
78
+ We simply create a normal Ruby class and define methods. Some methods
79
+ reference others, some return values, some return only booleans.
80
+
81
+ Now let's write the template:
82
+
83
+ Hello %%name%%
84
+ You have just won %%value%% dollars!
85
+ %%#in_ca%%
86
+ Well, %%taxed_value%% dollars, after taxes.
87
+ %%/in_ca%%
88
+
89
+ This template references our view methods. To bring it all together,
90
+ here's the code to render actual HTML;
91
+
92
+ Simple.render
93
+
94
+ Which returns the following:
95
+
96
+ Hello Chris
97
+ You have just won 10000 dollars!
98
+ Well, 6000.0 dollars, after taxes.
99
+
100
+ Simple.
101
+
102
+
103
+ Tag Types
104
+ ---------
105
+
106
+ For a language-agnostic overview of Porthole's template syntax, see
107
+ the `porthole(5)` manpage or
108
+ <http://porthole.github.com/porthole.5.html>.
109
+
110
+
111
+ Escaping
112
+ --------
113
+
114
+ Porthole does escape all values when using the standard double
115
+ Porthole syntax. Characters which will be escaped: `& \ " < >`. To
116
+ disable escaping, simply use triple portholes like
117
+ `%%%unescaped_variable%%%`.
118
+
119
+ Example: Using `%%variable%%` inside a template for `5 > 2` will
120
+ result in `5 &gt; 2`, where as the usage of `%%%variable%%%` will
121
+ result in `5 > 2`.
122
+
123
+
124
+ Dict-Style Views
125
+ ----------------
126
+
127
+ ctemplate and friends want you to hand a dictionary to the template
128
+ processor. Porthole supports a similar concept. Feel free to mix the
129
+ class-based and this more procedural style at your leisure.
130
+
131
+ Given this template (winner.porthole):
132
+
133
+ Hello %%name%%
134
+ You have just won %%value%% bucks!
135
+
136
+ We can fill in the values at will:
137
+
138
+ view = Winner.new
139
+ view[:name] = 'George'
140
+ view[:value] = 100
141
+ view.render
142
+
143
+ Which returns:
144
+
145
+ Hello George
146
+ You have just won 100 bucks!
147
+
148
+ We can re-use the same object, too:
149
+
150
+ view[:name] = 'Tony'
151
+ view.render
152
+ Hello Tony
153
+ You have just won 100 bucks!
154
+
155
+
156
+ Templates
157
+ ---------
158
+
159
+ A word on templates. By default, a view will try to find its template
160
+ on disk by searching for an HTML file in the current directory that
161
+ follows the classic Ruby naming convention.
162
+
163
+ TemplatePartial => ./template_partial.porthole
164
+
165
+ You can set the search path using `Porthole.template_path`. It can be set on a
166
+ class by class basis:
167
+
168
+ class Simple < Porthole
169
+ self.template_path = File.dirname(__FILE__)
170
+ ... etc ...
171
+ end
172
+
173
+ Now `Simple` will look for `simple.porthole` in the directory it resides
174
+ in, no matter the cwd.
175
+
176
+ If you want to just change what template is used you can set
177
+ `Porthole.template_file` directly:
178
+
179
+ Simple.template_file = './blah.porthole'
180
+
181
+ Porthole also allows you to define the extension it'll use.
182
+
183
+ Simple.template_extension = 'xml'
184
+
185
+ Given all other defaults, the above line will cause Porthole to look
186
+ for './blah.xml'
187
+
188
+ Feel free to set the template directly:
189
+
190
+ Simple.template = 'Hi %%person%%!'
191
+
192
+ Or set a different template for a single instance:
193
+
194
+ Simple.new.template = 'Hi %%person%%!'
195
+
196
+ Whatever works.
197
+
198
+
199
+ Views
200
+ -----
201
+
202
+ Porthole supports a bit of magic when it comes to views. If you're
203
+ authoring a plugin or extension for a web framework (Sinatra, Rails,
204
+ etc), check out the `view_namespace` and `view_path` settings on the
205
+ `Porthole` class. They will surely provide needed assistance.
206
+
207
+
208
+ Helpers
209
+ -------
210
+
211
+ What about global helpers? Maybe you have a nifty `gravatar` function
212
+ you want to use in all your views? No problem.
213
+
214
+ This is just Ruby, after all.
215
+
216
+ module ViewHelpers
217
+ def gravatar
218
+ gravatar_id = Digest::MD5.hexdigest(self[:email].to_s.strip.downcase)
219
+ gravatar_for_id(gravatar_id)
220
+ end
221
+
222
+ def gravatar_for_id(gid, size = 30)
223
+ "#{gravatar_host}/avatar/#{gid}?s=#{size}"
224
+ end
225
+
226
+ def gravatar_host
227
+ @ssl ? 'https://secure.gravatar.com' : 'http://www.gravatar.com'
228
+ end
229
+ end
230
+
231
+ Then just include it:
232
+
233
+ class Simple < Porthole
234
+ include ViewHelpers
235
+
236
+ def name
237
+ "Chris"
238
+ end
239
+
240
+ def value
241
+ 10_000
242
+ end
243
+
244
+ def taxed_value
245
+ value * 0.6
246
+ end
247
+
248
+ def in_ca
249
+ true
250
+ end
251
+
252
+ def users
253
+ User.all
254
+ end
255
+ end
256
+
257
+ Great, but what about that `@ssl` ivar in `gravatar_host`? There are
258
+ many ways we can go about setting it.
259
+
260
+ Here's on example which illustrates a key feature of Porthole: you
261
+ are free to use the `initialize` method just as you would in any
262
+ normal class.
263
+
264
+ class Simple < Porthole
265
+ include ViewHelpers
266
+
267
+ def initialize(ssl = false)
268
+ @ssl = ssl
269
+ end
270
+
271
+ ... etc ...
272
+ end
273
+
274
+ Now:
275
+
276
+ Simple.new(request.ssl?).render
277
+
278
+ Finally, our template might look like this:
279
+
280
+ <ul>
281
+ %%# users%%
282
+ <li><img src="%% gravatar %%"> %% login %%</li>
283
+ %%/ users%%
284
+ </ul>
285
+
286
+
287
+ Sinatra
288
+ -------
289
+
290
+ Porthole ships with Sinatra integration. Please see
291
+ `lib/porthole/sinatra.rb` or
292
+ <http://github.com/defunkt/porthole/blob/master/lib/porthole/sinatra.rb>
293
+ for complete documentation.
294
+
295
+ An example Sinatra application is also provided:
296
+ <http://github.com/defunkt/porthole-sinatra-example>
297
+
298
+ If you are upgrading to Sinatra 1.0 and Porthole 0.9.0+ from Porthole
299
+ 0.7.0 or lower, the settings have changed. But not that much.
300
+
301
+ See [this diff](http://gist.github.com/345490) for what you need to
302
+ do. Basically, things are named properly now and all should be
303
+ contained in a hash set using `set :porthole, hash`.
304
+
305
+
306
+ [Rack::Bug][4]
307
+ --------------
308
+
309
+ Porthole also ships with a `Rack::Bug` panel. In your `config.ru` add
310
+ the following code:
311
+
312
+ require 'rack/bug/panels/porthole_panel'
313
+ use Rack::Bug::PortholePanel
314
+
315
+ Using Rails? Add this to your initializer or environment file:
316
+
317
+ require 'rack/bug/panels/porthole_panel'
318
+ config.middleware.use "Rack::Bug::PortholePanel"
319
+
320
+ [![Rack::Bug](http://img.skitch.com/20091027-xyf4h1yxnefpp7usyddrcmc7dn.png)][5]
321
+
322
+
323
+ Vim
324
+ ---
325
+
326
+ Thanks to [Juvenn Woo](http://github.com/juvenn) for porthole.vim. It
327
+ is included under the contrib/ directory.
328
+
329
+ See <http://gist.github.com/323622> for installation instructions.
330
+
331
+
332
+ Emacs
333
+ -----
334
+
335
+ porthole-mode.el is available at https://github.com/porthole/emacs
336
+
337
+
338
+ TextMate
339
+ --------
340
+
341
+ [Porthole.tmbundle](http://github.com/defunkt/Porthole.tmbundle)
342
+
343
+ See <http://gist.github.com/323624> for installation instructions.
344
+
345
+
346
+ Command Line
347
+ ------------
348
+
349
+ See `porthole(1)` man page or
350
+ <http://porthole.github.com/porthole.1.html>
351
+ for command line docs.
352
+
353
+
354
+ Installation
355
+ ------------
356
+
357
+ ### [RubyGems](http://rubygems.org/)
358
+
359
+ $ gem install porthole
360
+
361
+
362
+ Acknowledgements
363
+ ----------------
364
+
365
+ Thanks to [Tom Preston-Werner](http://github.com/mojombo) for showing
366
+ me ctemplate and [Leah Culver](http://github.com/leah) for the name "Porthole."
367
+
368
+ Special thanks to [Magnus Holm](http://judofyr.net/) for all his
369
+ awesome work on Porthole's parser.
370
+
371
+
372
+ Contributing
373
+ ------------
374
+
375
+ Once you've made your great commits:
376
+
377
+ 1. [Fork][fk] Porthole
378
+ 2. Create a topic branch - `git checkout -b my_branch`
379
+ 3. Push to your branch - `git push origin my_branch`
380
+ 4. Create an [Issue][is] with a link to your branch
381
+ 5. That's it!
382
+
383
+ You might want to checkout Resque's [Contributing][cb] wiki page for information
384
+ on coding standards, new features, etc.
385
+
386
+
387
+ Mailing List
388
+ ------------
389
+
390
+ To join the list simply send an email to <porthole@librelist.com>. This
391
+ will subscribe you and send you information about your subscription,
392
+ including unsubscribe information.
393
+
394
+ The archive can be found at <http://librelist.com/browser/>.
395
+
396
+
397
+ Meta
398
+ ----
399
+
400
+ * Code: `git clone git://github.com/defunkt/porthole.git`
401
+ * Home: <http://porthole.github.com>
402
+ * Bugs: <http://github.com/defunkt/porthole/issues>
403
+ * List: <porthole@librelist.com>
404
+ * Gems: <http://rubygems.org/gems/porthole>
405
+
406
+ You can also find us in `#{` on irc.freenode.net.
407
+
408
+ [1]: http://code.google.com/p/google-ctemplate/
409
+ [2]: http://www.ivan.fomichev.name/2008/05/erlang-template-engine-prototype.html
410
+ [3]: http://google-ctemplate.googlecode.com/svn/trunk/doc/howto.html
411
+ [4]: http://github.com/brynary/rack-bug/
412
+ [5]: http://img.skitch.com/20091027-n8pxwwx8r61tc318a15q1n6m14.png
413
+ [cb]: http://wiki.github.com/defunkt/resque/contributing
414
+ [fk]: http://help.github.com/forking/
415
+ [is]: http://github.com/defunkt/porthole/issues
@@ -0,0 +1,89 @@
1
+ require 'rake/testtask'
2
+ require 'rake/rdoctask'
3
+
4
+ #
5
+ # Helpers
6
+ #
7
+
8
+ def command?(command)
9
+ system("type #{command} &> /dev/null")
10
+ end
11
+
12
+
13
+ #
14
+ # Tests
15
+ #
16
+
17
+ task :default => :test
18
+
19
+ if command? :turn
20
+ desc "Run tests"
21
+ task :test do
22
+ suffix = "-n #{ENV['TEST']}" if ENV['TEST']
23
+ sh "turn test/*.rb #{suffix}"
24
+ end
25
+ else
26
+ Rake::TestTask.new do |t|
27
+ t.libs << 'lib'
28
+ t.pattern = 'test/**/*_test.rb'
29
+ t.verbose = false
30
+ end
31
+ end
32
+
33
+
34
+ #
35
+ # Ron
36
+ #
37
+
38
+ if command? :ronn
39
+ desc "Show the manual"
40
+ task :man => "man:build" do
41
+ exec "man man/porthole.1"
42
+ end
43
+
44
+ desc "Build the manual"
45
+ task "man:build" do
46
+ sh "ronn -br5 --organization=DEFUNKT --manual='Porthole Manual' man/*.ron"
47
+ end
48
+ end
49
+
50
+
51
+ #
52
+ # Gems
53
+ #
54
+
55
+ desc "Push a new version to Gemcutter and publish docs."
56
+ task :publish do
57
+ require File.dirname(__FILE__) + '/lib/porthole/version'
58
+
59
+ system "git tag v#{Porthole::Version}"
60
+ sh "gem build porthole.gemspec"
61
+ sh "gem push porthole-#{Porthole::Version}.gem"
62
+ sh "git push origin master --tags"
63
+ sh "git clean -fd"
64
+ exec "rake pages"
65
+ end
66
+
67
+ #
68
+ # Documentation
69
+ #
70
+
71
+ desc "Publish to GitHub Pages"
72
+ task :pages => [ "man:build" ] do
73
+ Dir['man/*.html'].each do |f|
74
+ cp f, File.basename(f).sub('.html', '.newhtml')
75
+ end
76
+
77
+ `git commit -am 'generated manual'`
78
+ `git checkout site`
79
+
80
+ Dir['*.newhtml'].each do |f|
81
+ mv f, f.sub('.newhtml', '.html')
82
+ end
83
+
84
+ `git add .`
85
+ `git commit -m updated`
86
+ `git push site site:master`
87
+ `git checkout master`
88
+ puts :done
89
+ end