porthole 0.99.4

Sign up to get free protection for your applications and to get access to all the features.
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