rjspotter-ramaze 2009.06.29

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 (503) hide show
  1. data/.gitignore +3 -0
  2. data/.mailmap +25 -0
  3. data/MANIFEST +502 -0
  4. data/README.md +457 -0
  5. data/Rakefile +88 -0
  6. data/benchmark/bench_templates/bench.rb +67 -0
  7. data/benchmark/bench_templates/view/large.erb +79 -0
  8. data/benchmark/bench_templates/view/large.haml +41 -0
  9. data/benchmark/bench_templates/view/large.xhtml +79 -0
  10. data/benchmark/bench_templates/view/small.erb +21 -0
  11. data/benchmark/bench_templates/view/small.haml +12 -0
  12. data/benchmark/bench_templates/view/small.xhtml +21 -0
  13. data/benchmark/results.txt +131 -0
  14. data/benchmark/run.rb +355 -0
  15. data/benchmark/suite/minimal.rb +11 -0
  16. data/benchmark/suite/no_informer.rb +7 -0
  17. data/benchmark/suite/no_sessions.rb +9 -0
  18. data/benchmark/suite/no_template.rb +7 -0
  19. data/benchmark/suite/simple.rb +5 -0
  20. data/benchmark/suite/template_erubis.rb +8 -0
  21. data/benchmark/suite/template_etanni.rb +8 -0
  22. data/benchmark/suite/template_ezamar.rb +8 -0
  23. data/benchmark/suite/template_haml.rb +13 -0
  24. data/benchmark/suite/template_liquid.rb +11 -0
  25. data/benchmark/suite/template_markaby.rb +9 -0
  26. data/benchmark/suite/template_nagoro.rb +8 -0
  27. data/benchmark/suite/template_redcloth.rb +13 -0
  28. data/benchmark/suite/template_tenjin.rb +8 -0
  29. data/benchmark/test.rb +35 -0
  30. data/bin/ramaze +15 -0
  31. data/doc/AUTHORS +44 -0
  32. data/doc/CHANGELOG +17362 -0
  33. data/doc/COPYING +56 -0
  34. data/doc/FAQ +92 -0
  35. data/doc/GPL +339 -0
  36. data/doc/INSTALL +92 -0
  37. data/doc/LEGAL +26 -0
  38. data/doc/TODO +29 -0
  39. data/doc/meta/announcement.txt +146 -0
  40. data/doc/meta/configuration.txt +163 -0
  41. data/doc/meta/internals.txt +278 -0
  42. data/doc/meta/users.kml +64 -0
  43. data/doc/tutorial/todolist.html +1379 -0
  44. data/doc/tutorial/todolist.txt +920 -0
  45. data/examples/app/auth/layout/auth.xhtml +25 -0
  46. data/examples/app/auth/start.rb +23 -0
  47. data/examples/app/auth/view/index.xhtml +4 -0
  48. data/examples/app/auth/view/login.xhtml +20 -0
  49. data/examples/app/auth/view/secret.xhtml +1 -0
  50. data/examples/app/blog/README +3 -0
  51. data/examples/app/blog/app.rb +69 -0
  52. data/examples/app/blog/config.ru +17 -0
  53. data/examples/app/blog/controller/comment.rb +45 -0
  54. data/examples/app/blog/controller/entry.rb +85 -0
  55. data/examples/app/blog/controller/init.rb +86 -0
  56. data/examples/app/blog/controller/main.rb +20 -0
  57. data/examples/app/blog/controller/tag.rb +9 -0
  58. data/examples/app/blog/layout/default.nag +31 -0
  59. data/examples/app/blog/model/comment.rb +58 -0
  60. data/examples/app/blog/model/entry.rb +89 -0
  61. data/examples/app/blog/model/init.rb +15 -0
  62. data/examples/app/blog/model/tag.rb +36 -0
  63. data/examples/app/blog/public/css/screen.css +273 -0
  64. data/examples/app/blog/spec/blog.rb +87 -0
  65. data/examples/app/blog/start.rb +5 -0
  66. data/examples/app/blog/view/comment/form.nag +10 -0
  67. data/examples/app/blog/view/comment/show.nag +16 -0
  68. data/examples/app/blog/view/entry/edit.nag +14 -0
  69. data/examples/app/blog/view/entry/feed.atom.nag +8 -0
  70. data/examples/app/blog/view/entry/feed.rss.nag +7 -0
  71. data/examples/app/blog/view/entry/index.nag +7 -0
  72. data/examples/app/blog/view/entry/new.nag +13 -0
  73. data/examples/app/blog/view/entry/show.nag +36 -0
  74. data/examples/app/blog/view/feed.atom.nag +18 -0
  75. data/examples/app/blog/view/feed.rss.nag +25 -0
  76. data/examples/app/blog/view/index.nag +6 -0
  77. data/examples/app/blog/view/tag/index.nag +5 -0
  78. data/examples/app/chat/layout/default.xhtml +13 -0
  79. data/examples/app/chat/model/history.rb +38 -0
  80. data/examples/app/chat/model/message.rb +7 -0
  81. data/examples/app/chat/public/css/chat.css +9 -0
  82. data/examples/app/chat/public/js/chat.js +28 -0
  83. data/examples/app/chat/public/js/jquery.js +3436 -0
  84. data/examples/app/chat/start.rb +39 -0
  85. data/examples/app/chat/view/chat.xhtml +9 -0
  86. data/examples/app/chat/view/index.xhtml +7 -0
  87. data/examples/app/localization/locale/de.yaml +5 -0
  88. data/examples/app/localization/locale/en.yaml +5 -0
  89. data/examples/app/localization/locale/ja.yaml +5 -0
  90. data/examples/app/localization/start.rb +48 -0
  91. data/examples/app/sourceview/public/coderay.css +104 -0
  92. data/examples/app/sourceview/public/images/file.gif +0 -0
  93. data/examples/app/sourceview/public/images/folder.gif +0 -0
  94. data/examples/app/sourceview/public/images/tv-collapsable-last.gif +0 -0
  95. data/examples/app/sourceview/public/images/tv-collapsable.gif +0 -0
  96. data/examples/app/sourceview/public/images/tv-expandable-last.gif +0 -0
  97. data/examples/app/sourceview/public/images/tv-expandable.gif +0 -0
  98. data/examples/app/sourceview/public/images/tv-item-last.gif +0 -0
  99. data/examples/app/sourceview/public/images/tv-item.gif +0 -0
  100. data/examples/app/sourceview/public/jquery.js +11 -0
  101. data/examples/app/sourceview/public/jquery.treeview.css +48 -0
  102. data/examples/app/sourceview/public/jquery.treeview.js +223 -0
  103. data/examples/app/sourceview/public/sourceview.js +52 -0
  104. data/examples/app/sourceview/start.rb +79 -0
  105. data/examples/app/sourceview/view/index.haml +59 -0
  106. data/examples/app/todolist/controller/init.rb +10 -0
  107. data/examples/app/todolist/controller/task.rb +39 -0
  108. data/examples/app/todolist/layout/default.xhtml +14 -0
  109. data/examples/app/todolist/model/init.rb +14 -0
  110. data/examples/app/todolist/model/task.rb +39 -0
  111. data/examples/app/todolist/public/css/screen.css +63 -0
  112. data/examples/app/todolist/public/favicon.ico +0 -0
  113. data/examples/app/todolist/start.rb +11 -0
  114. data/examples/app/todolist/view/index.xhtml +29 -0
  115. data/examples/app/upload/start.rb +19 -0
  116. data/examples/app/upload/view/index.xhtml +25 -0
  117. data/examples/app/whywiki/spec/whywiki.rb +58 -0
  118. data/examples/app/whywiki/start.rb +46 -0
  119. data/examples/app/whywiki/template/edit.xhtml +14 -0
  120. data/examples/app/whywiki/template/show.xhtml +18 -0
  121. data/examples/app/wikore/spec/wikore.rb +109 -0
  122. data/examples/app/wikore/src/controller.rb +78 -0
  123. data/examples/app/wikore/src/model.rb +56 -0
  124. data/examples/app/wikore/start.rb +9 -0
  125. data/examples/app/wikore/view/index.xhtml +8 -0
  126. data/examples/app/wiktacular/README +2 -0
  127. data/examples/app/wiktacular/mkd/link/2007-07-20_19-45-51.mkd +1 -0
  128. data/examples/app/wiktacular/mkd/link/current.mkd +1 -0
  129. data/examples/app/wiktacular/mkd/main/2007-07-20_16-31-33.mkd +1 -0
  130. data/examples/app/wiktacular/mkd/main/2007-07-20_19-21-12.mkd +1 -0
  131. data/examples/app/wiktacular/mkd/main/2007-07-20_19-23-10.mkd +2 -0
  132. data/examples/app/wiktacular/mkd/main/2007-07-20_19-45-07.mkd +2 -0
  133. data/examples/app/wiktacular/mkd/main/current.mkd +2 -0
  134. data/examples/app/wiktacular/mkd/markdown/current.mkd +3 -0
  135. data/examples/app/wiktacular/mkd/testing/2007-07-20_16-43-46.mkd +2 -0
  136. data/examples/app/wiktacular/mkd/testing/2007-07-20_19-43-50.mkd +3 -0
  137. data/examples/app/wiktacular/mkd/testing/2007-07-21_18-46-01.mkd +11 -0
  138. data/examples/app/wiktacular/mkd/testing/2007-07-21_18-46-32.mkd +13 -0
  139. data/examples/app/wiktacular/mkd/testing/2007-07-21_18-47-08.mkd +17 -0
  140. data/examples/app/wiktacular/mkd/testing/2007-07-21_18-47-54.mkd +17 -0
  141. data/examples/app/wiktacular/mkd/testing/current.mkd +17 -0
  142. data/examples/app/wiktacular/public/favicon.ico +0 -0
  143. data/examples/app/wiktacular/public/screen.css +72 -0
  144. data/examples/app/wiktacular/spec/wiktacular.rb +157 -0
  145. data/examples/app/wiktacular/src/controller.rb +55 -0
  146. data/examples/app/wiktacular/src/model.rb +102 -0
  147. data/examples/app/wiktacular/start.rb +8 -0
  148. data/examples/app/wiktacular/template/edit.xhtml +6 -0
  149. data/examples/app/wiktacular/template/html_layout.xhtml +27 -0
  150. data/examples/app/wiktacular/template/index.xhtml +9 -0
  151. data/examples/app/wiktacular/template/new.xhtml +6 -0
  152. data/examples/basic/element.rb +47 -0
  153. data/examples/basic/gestalt.rb +26 -0
  154. data/examples/basic/hello.rb +14 -0
  155. data/examples/basic/layout.rb +28 -0
  156. data/examples/basic/linking.rb +29 -0
  157. data/examples/basic/partial.rb +26 -0
  158. data/examples/basic/simple.rb +52 -0
  159. data/examples/helpers/cache.rb +33 -0
  160. data/examples/helpers/form_with_sequel.rb +24 -0
  161. data/examples/helpers/httpdigest.rb +107 -0
  162. data/examples/helpers/identity.rb +18 -0
  163. data/examples/helpers/nitro_form.rb +23 -0
  164. data/examples/helpers/paginate.rb +71 -0
  165. data/examples/helpers/rest.rb +28 -0
  166. data/examples/helpers/simple_captcha.rb +29 -0
  167. data/examples/misc/css.rb +37 -0
  168. data/examples/misc/facebook.rb +159 -0
  169. data/examples/misc/memleak_detector.rb +37 -0
  170. data/examples/misc/nagoro_element.rb +43 -0
  171. data/examples/misc/ramaise.rb +132 -0
  172. data/examples/misc/rapp.rb +56 -0
  173. data/examples/misc/sequel_scaffolding.rb +34 -0
  174. data/examples/misc/serve_directory.rb +6 -0
  175. data/examples/templates/template_erubis.rb +52 -0
  176. data/examples/templates/template_ezamar.rb +51 -0
  177. data/examples/templates/template_haml.rb +49 -0
  178. data/examples/templates/template_liquid.rb +66 -0
  179. data/examples/templates/template_markaby.rb +57 -0
  180. data/examples/templates/template_nagoro.rb +50 -0
  181. data/examples/templates/template_redcloth.rb +58 -0
  182. data/examples/templates/template_remarkably.rb +54 -0
  183. data/examples/templates/template_tenjin.rb +52 -0
  184. data/examples/templates/view/external.haml +22 -0
  185. data/examples/templates/view/external.liquid +28 -0
  186. data/examples/templates/view/external.mab +30 -0
  187. data/examples/templates/view/external.nag +28 -0
  188. data/examples/templates/view/external.redcloth +19 -0
  189. data/examples/templates/view/external.rem +30 -0
  190. data/examples/templates/view/external.rhtml +28 -0
  191. data/examples/templates/view/external.tenjin +28 -0
  192. data/examples/templates/view/external.zmr +28 -0
  193. data/lib/proto/app.rb +14 -0
  194. data/lib/proto/config.ru +20 -0
  195. data/lib/proto/controller/init.rb +11 -0
  196. data/lib/proto/controller/main.rb +20 -0
  197. data/lib/proto/layout/default.xhtml +24 -0
  198. data/lib/proto/model/init.rb +4 -0
  199. data/lib/proto/public/.htaccess +24 -0
  200. data/lib/proto/public/css/screen.css +30 -0
  201. data/lib/proto/public/dispatch.fcgi +11 -0
  202. data/lib/proto/public/favicon.ico +0 -0
  203. data/lib/proto/public/js/jquery.js +4376 -0
  204. data/lib/proto/public/ramaze.png +0 -0
  205. data/lib/proto/spec/main.rb +20 -0
  206. data/lib/proto/start.rb +8 -0
  207. data/lib/proto/view/index.xhtml +41 -0
  208. data/lib/ramaze.rb +87 -0
  209. data/lib/ramaze/app.rb +124 -0
  210. data/lib/ramaze/cache.rb +19 -0
  211. data/lib/ramaze/cache/localmemcache.rb +56 -0
  212. data/lib/ramaze/cache/memcache.rb +124 -0
  213. data/lib/ramaze/cache/sequel.rb +82 -0
  214. data/lib/ramaze/contrib/addressable_route.rb +55 -0
  215. data/lib/ramaze/contrib/app_graph.rb +64 -0
  216. data/lib/ramaze/contrib/email.rb +88 -0
  217. data/lib/ramaze/contrib/facebook.rb +23 -0
  218. data/lib/ramaze/contrib/facebook/facebook.rb +171 -0
  219. data/lib/ramaze/contrib/gettext.rb +113 -0
  220. data/lib/ramaze/contrib/gettext/mo.rb +155 -0
  221. data/lib/ramaze/contrib/gettext/parser.rb +46 -0
  222. data/lib/ramaze/contrib/gettext/po.rb +109 -0
  223. data/lib/ramaze/contrib/gzip_filter.rb +1 -0
  224. data/lib/ramaze/contrib/maruku_uv.rb +59 -0
  225. data/lib/ramaze/contrib/profiling.rb +36 -0
  226. data/lib/ramaze/contrib/rest.rb +22 -0
  227. data/lib/ramaze/contrib/sequel/create_join.rb +26 -0
  228. data/lib/ramaze/contrib/sequel/form_field.rb +129 -0
  229. data/lib/ramaze/contrib/sequel/image.rb +196 -0
  230. data/lib/ramaze/contrib/sequel/relation.rb +98 -0
  231. data/lib/ramaze/controller.rb +104 -0
  232. data/lib/ramaze/controller/default.rb +12 -0
  233. data/lib/ramaze/current.rb +7 -0
  234. data/lib/ramaze/files.rb +24 -0
  235. data/lib/ramaze/gestalt.rb +132 -0
  236. data/lib/ramaze/helper.rb +13 -0
  237. data/lib/ramaze/helper/auth.rb +84 -0
  238. data/lib/ramaze/helper/bench.rb +41 -0
  239. data/lib/ramaze/helper/cache.rb +117 -0
  240. data/lib/ramaze/helper/disqus.rb +26 -0
  241. data/lib/ramaze/helper/flash.rb +62 -0
  242. data/lib/ramaze/helper/form.rb +127 -0
  243. data/lib/ramaze/helper/formatting.rb +189 -0
  244. data/lib/ramaze/helper/gestalt.rb +47 -0
  245. data/lib/ramaze/helper/gravatar.rb +79 -0
  246. data/lib/ramaze/helper/httpdigest.rb +97 -0
  247. data/lib/ramaze/helper/identity.rb +119 -0
  248. data/lib/ramaze/helper/layout.rb +97 -0
  249. data/lib/ramaze/helper/link.rb +56 -0
  250. data/lib/ramaze/helper/localize.rb +138 -0
  251. data/lib/ramaze/helper/markaby.rb +31 -0
  252. data/lib/ramaze/helper/maruku.rb +16 -0
  253. data/lib/ramaze/helper/nitroform.rb +14 -0
  254. data/lib/ramaze/helper/pager.rb +367 -0
  255. data/lib/ramaze/helper/paginate.rb +242 -0
  256. data/lib/ramaze/helper/partial.rb +100 -0
  257. data/lib/ramaze/helper/remarkably.rb +14 -0
  258. data/lib/ramaze/helper/request_accessor.rb +16 -0
  259. data/lib/ramaze/helper/sequel.rb +55 -0
  260. data/lib/ramaze/helper/sequel_form.rb +284 -0
  261. data/lib/ramaze/helper/simple_captcha.rb +61 -0
  262. data/lib/ramaze/helper/stack.rb +75 -0
  263. data/lib/ramaze/helper/tagz.rb +19 -0
  264. data/lib/ramaze/helper/thread.rb +17 -0
  265. data/lib/ramaze/helper/ultraviolet.rb +46 -0
  266. data/lib/ramaze/helper/user.rb +229 -0
  267. data/lib/ramaze/helper/xhtml.rb +34 -0
  268. data/lib/ramaze/log.rb +39 -0
  269. data/lib/ramaze/log/analogger.rb +39 -0
  270. data/lib/ramaze/log/growl.rb +38 -0
  271. data/lib/ramaze/log/hub.rb +41 -0
  272. data/lib/ramaze/log/informer.rb +129 -0
  273. data/lib/ramaze/log/knotify.rb +28 -0
  274. data/lib/ramaze/log/logger.rb +26 -0
  275. data/lib/ramaze/log/logging.rb +83 -0
  276. data/lib/ramaze/log/rotatinginformer.rb +168 -0
  277. data/lib/ramaze/log/syslog.rb +51 -0
  278. data/lib/ramaze/log/xosd.rb +92 -0
  279. data/lib/ramaze/middleware_compiler.rb +13 -0
  280. data/lib/ramaze/plugin.rb +69 -0
  281. data/lib/ramaze/reloader.rb +172 -0
  282. data/lib/ramaze/reloader/watch_inotify.rb +85 -0
  283. data/lib/ramaze/reloader/watch_stat.rb +58 -0
  284. data/lib/ramaze/request.rb +115 -0
  285. data/lib/ramaze/response.rb +36 -0
  286. data/lib/ramaze/setup.rb +123 -0
  287. data/lib/ramaze/snippets.rb +22 -0
  288. data/lib/ramaze/snippets/array/put_within.rb +44 -0
  289. data/lib/ramaze/snippets/binding/locals.rb +25 -0
  290. data/lib/ramaze/snippets/blankslate.rb +7 -0
  291. data/lib/ramaze/snippets/fiber.rb +63 -0
  292. data/lib/ramaze/snippets/kernel/pretty_inspect.rb +21 -0
  293. data/lib/ramaze/snippets/metaid.rb +17 -0
  294. data/lib/ramaze/snippets/numeric/filesize_format.rb +32 -0
  295. data/lib/ramaze/snippets/numeric/time.rb +63 -0
  296. data/lib/ramaze/snippets/object/__dir__.rb +29 -0
  297. data/lib/ramaze/snippets/object/instance_variable_defined.rb +19 -0
  298. data/lib/ramaze/snippets/object/pretty.rb +16 -0
  299. data/lib/ramaze/snippets/object/scope.rb +18 -0
  300. data/lib/ramaze/snippets/ordered_set.rb +51 -0
  301. data/lib/ramaze/snippets/proc/locals.rb +19 -0
  302. data/lib/ramaze/snippets/ramaze/acquire.rb +31 -0
  303. data/lib/ramaze/snippets/ramaze/deprecated.rb +23 -0
  304. data/lib/ramaze/snippets/ramaze/dictionary.rb +400 -0
  305. data/lib/ramaze/snippets/ramaze/fiber.rb +24 -0
  306. data/lib/ramaze/snippets/ramaze/struct.rb +45 -0
  307. data/lib/ramaze/snippets/string/camel_case.rb +21 -0
  308. data/lib/ramaze/snippets/string/color.rb +31 -0
  309. data/lib/ramaze/snippets/string/end_with.rb +20 -0
  310. data/lib/ramaze/snippets/string/esc.rb +34 -0
  311. data/lib/ramaze/snippets/string/ord.rb +21 -0
  312. data/lib/ramaze/snippets/string/snake_case.rb +21 -0
  313. data/lib/ramaze/snippets/string/start_with.rb +19 -0
  314. data/lib/ramaze/snippets/string/unindent.rb +28 -0
  315. data/lib/ramaze/snippets/thread/into.rb +18 -0
  316. data/lib/ramaze/spec.rb +33 -0
  317. data/lib/ramaze/spec/bacon.rb +34 -0
  318. data/lib/ramaze/spec/helper/bacon.rb +8 -0
  319. data/lib/ramaze/spec/helper/pretty_output.rb +82 -0
  320. data/lib/ramaze/spec/helper/snippets.rb +16 -0
  321. data/lib/ramaze/spec/helper/template_examples.rb +19 -0
  322. data/lib/ramaze/tool/bin.rb +340 -0
  323. data/lib/ramaze/tool/create.rb +48 -0
  324. data/lib/ramaze/tool/project_creator.rb +111 -0
  325. data/lib/ramaze/version.rb +3 -0
  326. data/lib/ramaze/view.rb +39 -0
  327. data/lib/ramaze/view/erubis.rb +23 -0
  328. data/lib/ramaze/view/ezamar.rb +23 -0
  329. data/lib/ramaze/view/gestalt.rb +14 -0
  330. data/lib/ramaze/view/haml.rb +16 -0
  331. data/lib/ramaze/view/liquid.rb +100 -0
  332. data/lib/ramaze/view/maruku.rb +15 -0
  333. data/lib/ramaze/view/nagoro.rb +44 -0
  334. data/lib/ramaze/view/nagoro/render_partial.rb +32 -0
  335. data/lib/ramaze/view/redcloth.rb +21 -0
  336. data/lib/ramaze/view/remarkably.rb +21 -0
  337. data/lib/ramaze/view/sass.rb +21 -0
  338. data/lib/ramaze/view/tagz.rb +63 -0
  339. data/lib/ramaze/view/tenjin.rb +32 -0
  340. data/lib/vendor/etag.rb +22 -0
  341. data/lib/vendor/route_exceptions.rb +42 -0
  342. data/ramaze.gemspec +85 -0
  343. data/spec/contrib/addressable_route.rb +32 -0
  344. data/spec/contrib/rest.rb +28 -0
  345. data/spec/examples/caching.rb +16 -0
  346. data/spec/examples/css.rb +14 -0
  347. data/spec/examples/element.rb +15 -0
  348. data/spec/examples/hello.rb +10 -0
  349. data/spec/examples/helpers/httpdigest.rb +64 -0
  350. data/spec/examples/linking.rb +17 -0
  351. data/spec/examples/simple.rb +40 -0
  352. data/spec/examples/templates/template_erubis.rb +10 -0
  353. data/spec/examples/templates/template_ezamar.rb +10 -0
  354. data/spec/examples/templates/template_haml.rb +10 -0
  355. data/spec/examples/templates/template_liquid.rb +10 -0
  356. data/spec/examples/templates/template_markaby.rb +11 -0
  357. data/spec/examples/templates/template_nagoro.rb +10 -0
  358. data/spec/examples/templates/template_redcloth.rb +10 -0
  359. data/spec/examples/templates/template_remarkably.rb +10 -0
  360. data/spec/examples/templates/template_tenjin.rb +10 -0
  361. data/spec/helper.rb +9 -0
  362. data/spec/ramaze/action/render.rb +21 -0
  363. data/spec/ramaze/action/view/bar.xhtml +1 -0
  364. data/spec/ramaze/action/view/instancevars/layout.xhtml +1 -0
  365. data/spec/ramaze/action/view/other_wrapper.erb +1 -0
  366. data/spec/ramaze/action/view/other_wrapper.xhtml +1 -0
  367. data/spec/ramaze/action/view/single_wrapper.xhtml +1 -0
  368. data/spec/ramaze/action/view/sub/sub_wrapper.erb +1 -0
  369. data/spec/ramaze/action/view/sub/sub_wrapper.xhtml +1 -0
  370. data/spec/ramaze/app.rb +47 -0
  371. data/spec/ramaze/bin/ramaze.rb +91 -0
  372. data/spec/ramaze/cache/localmemcache.rb +49 -0
  373. data/spec/ramaze/cache/memcache.rb +60 -0
  374. data/spec/ramaze/cache/sequel.rb +51 -0
  375. data/spec/ramaze/controller/actionless_templates.rb +36 -0
  376. data/spec/ramaze/controller/lonely_mapping.rb +16 -0
  377. data/spec/ramaze/controller/mapping.rb +43 -0
  378. data/spec/ramaze/controller/provide_inheritance.rb +47 -0
  379. data/spec/ramaze/controller/resolve.rb +30 -0
  380. data/spec/ramaze/controller/subclass.rb +36 -0
  381. data/spec/ramaze/controller/template_resolving.rb +77 -0
  382. data/spec/ramaze/controller/view/bar.xhtml +1 -0
  383. data/spec/ramaze/controller/view/base/another.xhtml +1 -0
  384. data/spec/ramaze/controller/view/greet.xhtml +1 -0
  385. data/spec/ramaze/controller/view/list.xhtml +1 -0
  386. data/spec/ramaze/controller/view/other/greet/other.xhtml +1 -0
  387. data/spec/ramaze/controller/view/other_wrapper.xhtml +1 -0
  388. data/spec/ramaze/dispatcher/directory.rb +69 -0
  389. data/spec/ramaze/dispatcher/file.rb +71 -0
  390. data/spec/ramaze/dispatcher/public/favicon.ico +0 -0
  391. data/spec/ramaze/dispatcher/public/file name.txt +1 -0
  392. data/spec/ramaze/dispatcher/public/test_download.css +141 -0
  393. data/spec/ramaze/error.rb +88 -0
  394. data/spec/ramaze/files.rb +29 -0
  395. data/spec/ramaze/files/public_1/plain.txt +1 -0
  396. data/spec/ramaze/files/public_2/rich.txt +1 -0
  397. data/spec/ramaze/gestalt.rb +135 -0
  398. data/spec/ramaze/helper/auth.rb +83 -0
  399. data/spec/ramaze/helper/bench.rb +18 -0
  400. data/spec/ramaze/helper/cache.rb +124 -0
  401. data/spec/ramaze/helper/flash.rb +41 -0
  402. data/spec/ramaze/helper/form.rb +356 -0
  403. data/spec/ramaze/helper/formatting.rb +111 -0
  404. data/spec/ramaze/helper/gestalt.rb +15 -0
  405. data/spec/ramaze/helper/gravatar.rb +40 -0
  406. data/spec/ramaze/helper/httpdigest.rb +144 -0
  407. data/spec/ramaze/helper/layout.rb +79 -0
  408. data/spec/ramaze/helper/layout/default.xhtml +5 -0
  409. data/spec/ramaze/helper/link.rb +70 -0
  410. data/spec/ramaze/helper/localize.rb +62 -0
  411. data/spec/ramaze/helper/maruku.rb +19 -0
  412. data/spec/ramaze/helper/pager.rb +96 -0
  413. data/spec/ramaze/helper/paginate.rb +68 -0
  414. data/spec/ramaze/helper/request_accessor.rb +19 -0
  415. data/spec/ramaze/helper/sequel_form.rb +91 -0
  416. data/spec/ramaze/helper/simple_captcha.rb +45 -0
  417. data/spec/ramaze/helper/stack.rb +86 -0
  418. data/spec/ramaze/helper/user.rb +72 -0
  419. data/spec/ramaze/helper/view/locals.xhtml +1 -0
  420. data/spec/ramaze/helper/view/loop.xhtml +4 -0
  421. data/spec/ramaze/helper/view/num.xhtml +1 -0
  422. data/spec/ramaze/helper/view/partial.xhtml +1 -0
  423. data/spec/ramaze/helper/view/recursive.xhtml +8 -0
  424. data/spec/ramaze/helper/view/recursive_local_ivars.xhtml +7 -0
  425. data/spec/ramaze/helper/view/recursive_locals.xhtml +7 -0
  426. data/spec/ramaze/helper/view/test_template.xhtml +1 -0
  427. data/spec/ramaze/helper/xhtml.rb +32 -0
  428. data/spec/ramaze/log/informer.rb +73 -0
  429. data/spec/ramaze/log/logging.rb +63 -0
  430. data/spec/ramaze/log/syslog.rb +73 -0
  431. data/spec/ramaze/params.rb +153 -0
  432. data/spec/ramaze/public/favicon.ico +0 -0
  433. data/spec/ramaze/public/ramaze.png +0 -0
  434. data/spec/ramaze/public/test_download.css +141 -0
  435. data/spec/ramaze/request.rb +61 -0
  436. data/spec/ramaze/rewrite/file.css +1 -0
  437. data/spec/ramaze/session/memcache.rb +66 -0
  438. data/spec/ramaze/struct.rb +47 -0
  439. data/spec/ramaze/template/ramaze/external.test +1 -0
  440. data/spec/ramaze/view.rb +36 -0
  441. data/spec/ramaze/view/erubis.rb +73 -0
  442. data/spec/ramaze/view/erubis/external.rhtml +8 -0
  443. data/spec/ramaze/view/erubis/sum.rhtml +1 -0
  444. data/spec/ramaze/view/ezamar.rb +73 -0
  445. data/spec/ramaze/view/ezamar/external.zmr +8 -0
  446. data/spec/ramaze/view/ezamar/sum.zmr +1 -0
  447. data/spec/ramaze/view/gestalt.rb +94 -0
  448. data/spec/ramaze/view/gestalt/external.ges +8 -0
  449. data/spec/ramaze/view/haml.rb +86 -0
  450. data/spec/ramaze/view/haml/external.haml +5 -0
  451. data/spec/ramaze/view/haml/sum.haml +2 -0
  452. data/spec/ramaze/view/liquid.rb +73 -0
  453. data/spec/ramaze/view/liquid/external.liquid +8 -0
  454. data/spec/ramaze/view/liquid/sum.liquid +1 -0
  455. data/spec/ramaze/view/nagoro.rb +73 -0
  456. data/spec/ramaze/view/nagoro/external.nag +8 -0
  457. data/spec/ramaze/view/nagoro/sum.nag +1 -0
  458. data/spec/ramaze/view/redcloth.rb +66 -0
  459. data/spec/ramaze/view/redcloth/external.redcloth +8 -0
  460. data/spec/ramaze/view/remarkably.rb +49 -0
  461. data/spec/ramaze/view/remarkably/external.rem +8 -0
  462. data/spec/ramaze/view/remarkably/sum.rem +1 -0
  463. data/spec/ramaze/view/sass.rb +73 -0
  464. data/spec/ramaze/view/sass/file.css.sass +5 -0
  465. data/spec/ramaze/view/tagz.rb +51 -0
  466. data/spec/ramaze/view/tagz/external.tagz +8 -0
  467. data/spec/ramaze/view/tagz/sum.tagz +1 -0
  468. data/spec/ramaze/view/tenjin.rb +57 -0
  469. data/spec/ramaze/view/tenjin/external.rbhtml +8 -0
  470. data/spec/ramaze/view/tenjin/sum.rbhtml +1 -0
  471. data/spec/snippets/array/put_within.rb +33 -0
  472. data/spec/snippets/binding/locals.rb +9 -0
  473. data/spec/snippets/numeric/filesize_format.rb +12 -0
  474. data/spec/snippets/numeric/time.rb +12 -0
  475. data/spec/snippets/object/__dir__.rb +14 -0
  476. data/spec/snippets/ordered_set.rb +63 -0
  477. data/spec/snippets/ramaze/acquire.rb +77 -0
  478. data/spec/snippets/ramaze/dictionary.rb +110 -0
  479. data/spec/snippets/ramaze/struct.rb +12 -0
  480. data/spec/snippets/string/camel_case.rb +25 -0
  481. data/spec/snippets/string/color.rb +11 -0
  482. data/spec/snippets/string/snake_case.rb +24 -0
  483. data/spec/snippets/string/unindent.rb +43 -0
  484. data/spec/snippets/thread/into.rb +9 -0
  485. data/tasks/authors.rake +30 -0
  486. data/tasks/bacon.rake +66 -0
  487. data/tasks/changelog.rake +20 -0
  488. data/tasks/copyright.rake +21 -0
  489. data/tasks/gem.rake +22 -0
  490. data/tasks/gem_setup.rake +99 -0
  491. data/tasks/git.rake +46 -0
  492. data/tasks/grancher.rake +12 -0
  493. data/tasks/jquery.rake +15 -0
  494. data/tasks/manifest.rake +4 -0
  495. data/tasks/metric_changes.rake +24 -0
  496. data/tasks/rcov.rake +23 -0
  497. data/tasks/release.rake +54 -0
  498. data/tasks/reversion.rake +8 -0
  499. data/tasks/setup.rake +6 -0
  500. data/tasks/todo.rake +27 -0
  501. data/tasks/traits.rake +21 -0
  502. data/tasks/yard.rake +4 -0
  503. metadata +720 -0
@@ -0,0 +1,920 @@
1
+ The official Ramaze Todo-list tutorial
2
+ =====================================
3
+ Michael 'manveru' Fellinger <m.fellinger@gmail.com>
4
+ revision 2.0, March 2009
5
+
6
+ == Abstract
7
+
8
+ Welcome to the official tutorial for http://ramaze.net[Ramaze], the mandatory
9
+ Todo-list.
10
+
11
+ I also assume that you have some experience with HTML and some other basics in
12
+ web-development already (you want to learn a web-framework after all).
13
+
14
+ The tutorial assumes a working installation of http://ruby-lang.org[Ruby] and
15
+ http://rubygems.org/[Rubygems].
16
+
17
+ For more information on how to install these please read the introductory
18
+ documentation of Ramaze, this is not in the scope of this tutorial.
19
+
20
+ To install Ramaze you can `gem install ramaze`, other ways of installation are
21
+ covered by the http://wiki.ramaze.net/[Ramaze Wiki].
22
+
23
+ Should you encounter any problems while doing this tutorial, this might either
24
+ be because Ramaze changed (which happens very often while it is still young)
25
+ or I actually made some mistake while writing it.
26
+
27
+ In either case it would make me (and all other poor fellows who happen to try
28
+ this tutorial) very happy if you could spare some time and report the issue
29
+ either on the http://github.com/manveru/ramaze/issues[Bug tracker] , or just
30
+ drop by on IRC on `irc.freenode.org` in the channel `#ramaze`.
31
+
32
+ If you have trouble with some of the terms used in this tutorial you can
33
+ consult the <<glossary, Glossary>> at the end of this document.
34
+
35
+ We are also working on a book that describes Ramaze in more depth, called
36
+ 'Journey to Ramaze', it is still very much work in progress, but some of the
37
+ contents might interest you.
38
+
39
+ The repository for the book is at http://github.com/manveru/ramaze-book. Every
40
+ once in a while, updates for the book will be put in HTML and PDF form at
41
+ http://book.ramaze.net.
42
+
43
+
44
+ == First Step, Create
45
+
46
+ The last version of this tutorial assumed a generator to produce a skeleton in
47
+ which we do the work. This time around we will do everything from scratch to
48
+ give you a better experience of how exactly the pieces fit together.
49
+
50
+ You can also skip all the boring learning-by-doing part and play around with
51
+ the source of the todo-list example shipping with Ramaze.
52
+
53
+ NOTE: The example and this tutorial differ in some points, it is recommended to
54
+ actually work through the tutorial first and read the example afterwards, it
55
+ takes the basics taught here one step further by utilizing the Model.
56
+
57
+ You can find the example it in the `examples/app/todolist/` directory of your
58
+ Ramaze distribution.
59
+ To find out where that is located (as this differs widely between systems), you
60
+ can follow these steps in `irb`:
61
+
62
+ [source,ruby]
63
+ --------------------------------------------------------------------------------
64
+ require 'rubygems'
65
+ # => true
66
+ require 'ramaze'
67
+ # => true
68
+ File.expand_path(Ramaze::BASEDIR + '/../examples/app/todolist')
69
+ # => "/home/manveru/c/ramaze/examples/app/todolist"
70
+ --------------------------------------------------------------------------------
71
+
72
+ To start things off, we will create a basic directory structure looking like this:
73
+
74
+ --------------------------------------------------------------------------------
75
+ .
76
+ |-- controller
77
+ |-- layout
78
+ |-- model
79
+ |-- public
80
+ | |-- css
81
+ `-- view
82
+ --------------------------------------------------------------------------------
83
+
84
+ Doing that is quite simple: `mkdir -p controller layout model public/css view`
85
+
86
+ Alright, done? Let's go to the next step.
87
+
88
+ == Second Step. Hello, World!
89
+
90
+ To make sure Ramaze is installed, and working correctly we will follow an old
91
+ tradition, we create a file at the root of your application directory called
92
+ 'start.rb' with following content:
93
+
94
+ [source,ruby]
95
+ --------------------------------------------------------------------------------
96
+ require 'rubygems'
97
+ require 'ramaze'
98
+
99
+ class MainController < Ramaze::Controller
100
+ def index
101
+ "Hello, World!"
102
+ end
103
+ end
104
+
105
+ Ramaze.start
106
+ --------------------------------------------------------------------------------
107
+
108
+ Now we run it:
109
+
110
+ --------------------------------------------------------------------------------
111
+ delta ~/tmp/tutorial % ruby start.rb
112
+ D [2009-03-30 14:15:01 $2124] DEBUG | : Using webrick
113
+ I [2009-03-30 14:15:01 $2124] INFO | : WEBrick 1.3.1
114
+ I [2009-03-30 14:15:01 $2124] INFO | : ruby 1.9.2 (2009-03-02) [i686-linux]
115
+ D [2009-03-30 14:15:01 $2124] DEBUG | : TCPServer.new(0.0.0.0, 7000)
116
+ D [2009-03-30 14:15:01 $2124] DEBUG | : Rack::Handler::WEBrick is mounted on /.
117
+ I [2009-03-30 14:15:01 $2124] INFO | : WEBrick::HTTPServer#start: pid=2124 port=7000
118
+ --------------------------------------------------------------------------------
119
+
120
+ The logging output tells us that a server was started, listening to all
121
+ connections at port 7000. If you open your browser and go to
122
+ http://localhost:7000/ you should be able to see 'Hello, World!'.
123
+
124
+
125
+ == Third Step. M, like Model
126
+
127
+ Model is a term from the MVC paradigm, meaning the representation of data
128
+ within your application.
129
+ Ramaze doesn't promote a particular way for this part of your application, and
130
+ how you are supposed to integrate it. Since there are quite a number of ways to
131
+ represent data and none is clearly superior to another, this would be both
132
+ futile and short-sighted.
133
+
134
+ For the purpose of this tutorial we will use a lightweight database access
135
+ toolkit for Ruby called http://sequel.rubyforge.org/[Sequel].
136
+
137
+ Sequel is designed to take the hassle away from connecting to databases and
138
+ manipulating them. Sequel deals with all the boring stuff like maintaining
139
+ connections, formatting SQL correctly and fetching records so you can
140
+ concentrate on your application.
141
+
142
+ Being familiar with it is not a requirement for this tutorial, but will help
143
+ you tremendously when it comes to writing your own applications.
144
+
145
+ Installing Sequel is as simple as installing Ramaze: `gem install sequel`.
146
+
147
+ In this tutorial we are going to use the light-weight
148
+ http://www.sqlite.org/[sqlite] database.
149
+ This requires the http://rubyforge.org/projects/sqlite-ruby[sqlite-ruby]
150
+ bindings.
151
+
152
+ You can try to `gem install sqlite`, which will complain if your system doesn't
153
+ provide bindings, in which case I have to refer you to http://sqlite.org.
154
+
155
+ In order to use Sequel we also need a database connection.
156
+
157
+ So we create a new file at 'model/init.rb' with following content:
158
+
159
+ [source,ruby]
160
+ --------------------------------------------------------------------------------
161
+ require 'sequel'
162
+
163
+ Sequel::Model.plugin(:schema)
164
+
165
+ DB = Sequel.sqlite('todolist.db')
166
+ --------------------------------------------------------------------------------
167
+
168
+ The `:schema` plugin is required since Sequel 3.0, if you run a version prior
169
+ to 2.12 you may remove this line if it gives you any problems.
170
+
171
+ Next we edit 'start.rb', remove the `Hello` class, and add a require for the
172
+ file, 'start.rb' should look like this now:
173
+
174
+ [source,ruby]
175
+ --------------------------------------------------------------------------------
176
+ require 'rubygems'
177
+ require 'ramaze'
178
+
179
+ require 'model/init'
180
+
181
+ Ramaze.start
182
+ --------------------------------------------------------------------------------
183
+
184
+ This should hook us up with a database, but anyone familiar with SQL will now
185
+ ask how we are going to create our schema.
186
+
187
+ So our next step is to create the actual model for our data, for this we create another file at 'model/task.rb':
188
+
189
+ [source,ruby]
190
+ --------------------------------------------------------------------------------
191
+ class Task < Sequel::Model
192
+ set_schema do
193
+ primary_key :id
194
+
195
+ varchar :title, :unique => true, :empty => false
196
+ boolean :done, :default => false
197
+ end
198
+
199
+ create_table unless table_exists?
200
+
201
+ if empty?
202
+ create :title => 'Laundry'
203
+ create :title => 'Wash dishes'
204
+ end
205
+ end
206
+ --------------------------------------------------------------------------------
207
+
208
+ For this tutorial we will not bother with migrations, although Sequel does have
209
+ very good support for them as well, but seriously, this is a really simple
210
+ schema that probably won't change much over the next few years.
211
+
212
+ Finally, add a line to your 'model/init.rb' that requires 'model/task.rb':
213
+
214
+ [source,ruby]
215
+ --------------------------------------------------------------------------------
216
+ require 'sequel'
217
+
218
+ Sequel::Model.plugin(:schema)
219
+
220
+ DB = Sequel.sqlite('todolist.db')
221
+
222
+ require 'model/task'
223
+ --------------------------------------------------------------------------------
224
+
225
+
226
+ == Fourth Step, V, like View
227
+
228
+ To see anything of the data in your Model we will have to add the second
229
+ element in MVC, the View.
230
+
231
+ We are going to use the templating engine shipping with Ramaze, called Etanni.
232
+ It has a very simple syntax compatible with SGML and XML documents.
233
+
234
+ When handling a request to '/', Ramaze will automatically try to find an Action
235
+ called 'index'. Don't bother too much about what Action means just yet, we will
236
+ explain that in more detail later when we come to layouts.
237
+
238
+ To start we put some contents into 'view/index.xhtml' (xhtml is the default
239
+ filename-extension for Etanni templates)
240
+
241
+ [source,html]
242
+ --------------------------------------------------------------------------------
243
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
244
+ <html>
245
+ <head>
246
+ <title>TodoList</title>
247
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
248
+ </head>
249
+ <body>
250
+ <h1>TodoList</h1>
251
+ <ul>
252
+ <?r Task.each do |task| ?>
253
+ <li>#{ h(task.title) }: #{ task.done }</li>
254
+ <?r end ?>
255
+ </ul>
256
+ </body>
257
+ </html>
258
+ --------------------------------------------------------------------------------
259
+
260
+ The '<?r ?>' and '\#{ }' elements enclose ruby code that will be executed when
261
+ the template is being rendered (on every request to 'index').
262
+ Code within '<?r ?>' is only executed and will not show up in the resulting
263
+ document, while code within '#{ }' will be interpolated.
264
+
265
+ In this template we iterate over all the data stored in the Task model,
266
+ yielding a list of task titles and the respective status of the task.
267
+
268
+ That wasn't too hard, right?
269
+
270
+ Now, so we can get our instant pleasure of seeing the result of our (hard)
271
+ work, let's see how this looks like in a browser, start your application like above with `ruby start.rb` and open http://localhost:7000/.
272
+
273
+ The template expanded to something like (only showing the interesting part):
274
+
275
+ [source,html]
276
+ --------------------------------------------------------------------------------
277
+ <ul>
278
+ <li>Laundry: false</li>
279
+ <li>Wash dishes: false</li>
280
+ </ul>
281
+ --------------------------------------------------------------------------------
282
+
283
+ That wasn't too bad, huh?
284
+
285
+
286
+ == Fifth Step, C, like Controller
287
+
288
+ The last part of the MVC paradigm is the Controller. As the name indicates it
289
+ gives you control over the interaction between Model and View.
290
+
291
+ Wouldn't it be nice to have a way to add and remove items on our to-do list?
292
+ Editing the model every time would be quite tiresome and problematic to do
293
+ remotely.
294
+
295
+ Well, come along, I'll give you a short intro to the concept of controllers.
296
+
297
+ In the way MVC is structured, the Controller provides the data in a nice way
298
+ for the View, removing all of the data-preparation and most of the logic from
299
+ the templates. This makes it firstly simple to change the front end of your
300
+ application and secondly provides excellent ways of changing the complete
301
+ Structure of the Model or View independent from each other.
302
+
303
+ OK, enough of the theory, you will see the benefits in an instant, first of all
304
+ we will implement marking a task as done.
305
+
306
+ Go on and create the file 'controller/task.rb' with following contents:
307
+
308
+ [source,ruby]
309
+ --------------------------------------------------------------------------------
310
+ class Tasks < Ramaze::Controller
311
+ map '/'
312
+
313
+ def close(title)
314
+ task = Task[:title => title]
315
+ task.done = true
316
+ task.save
317
+
318
+ redirect_referrer
319
+ end
320
+ end
321
+ --------------------------------------------------------------------------------
322
+
323
+ That does following:
324
+
325
+ * Define a `Tasks` class as a subclass of `Ramaze::Controller`.
326
+ * Tell Ramaze that a request to '/' goes to this Controller.
327
+ * Define a `#close` method that requires a `title` argument.
328
+ * Query for a task that has the given title.
329
+ * Set the status of the task to done and store the change to the database.
330
+ * Redirect the client to where it came from.
331
+
332
+ And we add a require to 'controller/task.rb' to our 'start.rb':
333
+
334
+ [source,ruby]
335
+ --------------------------------------------------------------------------------
336
+ require 'rubygems'
337
+ require 'ramaze'
338
+
339
+ require 'model/init'
340
+ require 'controller/task'
341
+
342
+ Ramaze.start
343
+ --------------------------------------------------------------------------------
344
+
345
+ Next we will have to modify the 'view/index.xhtml' to contain a link that will
346
+ change the status of a task:
347
+
348
+ [source,html]
349
+ --------------------------------------------------------------------------------
350
+ <ul>
351
+ <?r Task.each do |task| ?>
352
+ <li>
353
+ #{ h(task.title) }: #{ task.done },
354
+ (#{ anchor('close', 'close', task.title) })
355
+ </li>
356
+ <?r end ?>
357
+ </ul>
358
+ --------------------------------------------------------------------------------
359
+
360
+ Now we have an additional link next to each task that allows us to set it to
361
+ done.
362
+
363
+ An even shorter way of writing that line using default aliases, that you will
364
+ encounter in other applications, is:
365
+
366
+ [source,ruby]
367
+ --------------------------------------------------------------------------------
368
+ a('close', 'close', task.title)
369
+ --------------------------------------------------------------------------------
370
+
371
+ But for the purpose of this tutorial we'll try to be as explicit as possible.
372
+
373
+ Now that's a lot of things at once, but I'm sure you will be able to keep up,
374
+ the hardest part is behind us.
375
+
376
+ Don't forget to try the new functionality in your browser, wash your dishes and
377
+ do your laundry and come back for the next episode.
378
+
379
+ == Sixth Step, Clean, Rinse, Repeat
380
+
381
+ Now that you have closed (and hopefully done) all of your chores, it's time to
382
+ open them again, so you won't be without work tomorrow.
383
+
384
+ Let's add a method to our Controller that will let us open a closed task:
385
+
386
+ [source,ruby]
387
+ --------------------------------------------------------------------------------
388
+ class Tasks < Ramaze::Controller
389
+ map '/'
390
+
391
+ def close(title)
392
+ task = Task[:title => title]
393
+ task.done = true
394
+ task.save
395
+
396
+ redirect_referrer
397
+ end
398
+
399
+ def open(title)
400
+ task = Task[:title => title]
401
+ task.done = false
402
+ task.save
403
+
404
+ redirect_referrer
405
+ end
406
+ end
407
+ --------------------------------------------------------------------------------
408
+
409
+ And add a link to that action:
410
+
411
+ [source,html]
412
+ --------------------------------------------------------------------------------
413
+ <ul>
414
+ <?r Task.each do |task| ?>
415
+ <li>
416
+ #{ h(task.title) }: #{ task.done },
417
+ (#{ anchor('close', 'close', task.title) })
418
+ (#{ anchor('open', 'open', task.title) })
419
+ </li>
420
+ <?r end ?>
421
+ </ul>
422
+ --------------------------------------------------------------------------------
423
+
424
+ OK, nothing new here, move along.
425
+
426
+ Oh, wait!
427
+
428
+ Rumor has it that some mad Japanese scientist got screwed by his company (they
429
+ produce dishwashers), so he filed a patent for the ultimate dish washing robot
430
+ that will take care of that for you.
431
+
432
+ Time to get rid of that task once and for all. No more dish washing yay!
433
+
434
+ A little modification to Controller, using destructive force.
435
+
436
+ [source,ruby]
437
+ --------------------------------------------------------------------------------
438
+ class Tasks < Ramaze::Controller
439
+ map '/'
440
+
441
+ def close(title)
442
+ task = Task[:title => title]
443
+ task.done = true
444
+ task.save
445
+
446
+ redirect_referrer
447
+ end
448
+
449
+ def open(title)
450
+ task = Task[:title => title]
451
+ task.done = false
452
+ task.save
453
+
454
+ redirect_referrer
455
+ end
456
+
457
+ def delete(title)
458
+ task = Task[:title => title]
459
+ task.destroy
460
+
461
+ redirect_referrer
462
+ end
463
+ end
464
+ --------------------------------------------------------------------------------
465
+
466
+ And a link to the `delete` action.
467
+
468
+ [source,html]
469
+ --------------------------------------------------------------------------------
470
+ <ul>
471
+ <?r Task.each do |task| ?>
472
+ <li>
473
+ #{ h(task.title) }: #{ task.done },
474
+ (#{ anchor('close', 'close', task.title)})
475
+ (#{ anchor('open', 'open', task.title)})
476
+ (#{ anchor('delete', 'delete', task.title)})
477
+ </li>
478
+ <?r end ?>
479
+ </ul>
480
+ --------------------------------------------------------------------------------
481
+
482
+ And dish-washing begone!
483
+
484
+
485
+ == Seventh Step, More Tasks
486
+
487
+ Sure, it would be nice if life was so simple and you only have to do your
488
+ laundry, but that would mean a premature end for this tutorial and an obstacle
489
+ for GTD evangelists (not that they couldn't overcome it).
490
+
491
+ So now you got a smart new robot that washes your dishes, but unfortunately it
492
+ wasn't programmed to recharge once in a while and buy soap, no biggie, we can
493
+ do that with little effort, but since reddit takes up all your time you keep
494
+ forgetting about it.
495
+
496
+ No problem, I say, adding following code to our 'view/index.xhtml' will give us
497
+ a nice little form that we can fill out in the few seconds between proving
498
+ people on the internet wrong.
499
+
500
+ [source,html]
501
+ --------------------------------------------------------------------------------
502
+ <form method="post" action="#{ route('create') }">
503
+ <fieldset>
504
+ <legend>Add a task by entering a title.</legend>
505
+ <label for="form-title">Task title:</label>
506
+ <input id="form-title" name="title" type="text" />
507
+ <input type="submit" value="Create" />
508
+ </fieldset>
509
+ </form>
510
+ --------------------------------------------------------------------------------
511
+
512
+ Unfortunately, you see, this references the `create` action, and we have none
513
+ yet. Trying to create a task will result in an error.
514
+
515
+ So what we have to do is adding one more method to our Controller that will
516
+ take care of actually creating the Task.
517
+
518
+ [source,ruby]
519
+ --------------------------------------------------------------------------------
520
+ def create
521
+ if request.post? and title = request[:title]
522
+ title.strip!
523
+
524
+ unless title.empty?
525
+ Task.create :title => title
526
+ end
527
+ end
528
+
529
+ redirect route('/')
530
+ end
531
+ --------------------------------------------------------------------------------
532
+
533
+ What is going on here?
534
+
535
+ * Check whether the request was using the HTTP POST method and actually sent a
536
+ title with it.
537
+ * Strip all whitespace from beginning and end of the title.
538
+ * If the title still has something in it we go on and create a task with that
539
+ title.
540
+ * Redirect back to the `index`
541
+
542
+ == Eighth Step, Eep, Exceptions!
543
+
544
+ So far, so good, but remember, when we defined the schema for `Task` we said we
545
+ really want to have unique titles.
546
+
547
+ So once you created the task 'recharge DishBot9000' and try to create another
548
+ one with the same title, you will get a nice error:
549
+
550
+ Sequel::DatabaseError: SQLite3::SQLException column title is not unique
551
+
552
+ OK, programmers ignore warnings and hide errors, let's rescue the exception and
553
+ just act as if nothing has happened.
554
+
555
+ [source,ruby]
556
+ --------------------------------------------------------------------------------
557
+ class Tasks < Ramaze::Controller
558
+ map '/'
559
+
560
+ def create
561
+ if request.post? and title = request[:title]
562
+ title.strip!
563
+
564
+ unless title.empty?
565
+ Task.create :title => title
566
+ end
567
+ end
568
+
569
+ redirect route('/')
570
+ rescue Sequel::DatabaseError
571
+ redirect route('/')
572
+ end
573
+
574
+ def close(title)
575
+ # ...
576
+ --------------------------------------------------------------------------------
577
+
578
+ Easy as pie, we can try to create as many identical tasks as we want, all we
579
+ get is the same old set.
580
+
581
+
582
+ == Ninth Step, Curing your RSI
583
+
584
+ Something you might notice is that every time you hit the submit button and you are redirected to `index`, the title you just input is gone.
585
+ What a waste of our honest effort to create a duplicate task, we all know if we
586
+ try often enough it will eventually have to work, so let's save us some typing.
587
+
588
+ In our 'view/index.xhtml' we modify the form input to have a default value:
589
+
590
+ [source,html]
591
+ --------------------------------------------------------------------------------
592
+ <form method="post" action="#{ route('create') }">
593
+ <fieldset>
594
+ <legend>Add a task by entering a title.</legend>
595
+ <label for="form-title">Task title:</label>
596
+ <input id="form-title" name="title" type="text" value="#{ @title }"/>
597
+ <input type="submit" value="Create" />
598
+ </fieldset>
599
+ </form>
600
+ --------------------------------------------------------------------------------
601
+
602
+ The `@title` is an instance-variable, those are shared between the Controller
603
+ and View.
604
+ We didn't set any such variable in the Controller yet, so do it now:
605
+
606
+ [source,ruby]
607
+ --------------------------------------------------------------------------------
608
+ class Tasks < Ramaze::Controller
609
+ map '/'
610
+
611
+ def index
612
+ @title = 'recharge DishBot9000'
613
+ end
614
+
615
+ def create
616
+ # ...
617
+ --------------------------------------------------------------------------------
618
+
619
+ Yes, that wasn't too bad, but is there a way to change the value of the
620
+ `@title` without editing the source all the time?
621
+
622
+ Turns out we have to revisit the `create` method to give us a hint in form of a
623
+ GET parameter and change `index` to pick it up.
624
+
625
+ [source,ruby]
626
+ --------------------------------------------------------------------------------
627
+ def index
628
+ @title = request[:title]
629
+ end
630
+
631
+ def create
632
+ if request.post? and title = request[:title]
633
+ title.strip!
634
+
635
+ unless title.empty?
636
+ Task.create :title => title
637
+ end
638
+ end
639
+
640
+ redirect route('/', :title => title)
641
+ rescue Sequel::DatabaseError
642
+ redirect route('/', :title => title)
643
+ end
644
+ --------------------------------------------------------------------------------
645
+
646
+ And that's it.
647
+ Endless hours of fun hitting the submit button lie before us!
648
+
649
+
650
+ == Tenth Step, Laying out a different View of things
651
+
652
+ We have one template, it's a nice one, but unfortunately we've got ourselves
653
+ into quite a mess here after creating hundreds of tasks.
654
+
655
+ Our way out of this is to provide some visual feedback -- when a task is done,
656
+ it's gone.
657
+ Not forever, but at least it will not show up anymore on the `index` action.
658
+
659
+ So we filter out all tasks that haven't been done yet in the
660
+ 'view/index.xhtml':
661
+
662
+ [source,html]
663
+ --------------------------------------------------------------------------------
664
+ <ul>
665
+ <?r Task.filter(:done => false).each do |task| ?>
666
+ <li>
667
+ # ...
668
+ --------------------------------------------------------------------------------
669
+
670
+
671
+ So off we go and add a new template at 'view/done.xhtml'.
672
+
673
+ [source,html]
674
+ --------------------------------------------------------------------------------
675
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
676
+ <html>
677
+ <head>
678
+ <title>TodoList</title>
679
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
680
+ </head>
681
+ <body>
682
+ <h1>TodoList</h1>
683
+
684
+ <form method="post" action="#{ route('create') }">
685
+ <fieldset>
686
+ <legend>Add a task by entering a title.</legend>
687
+ <label for="form-title">Task title:</label>
688
+ <input id="form-title" name="title" type="text" value="#{ @title }"/>
689
+ <input type="submit" value="Create" />
690
+ </fieldset>
691
+ </form>
692
+
693
+ <h2>Tasks done</h2>
694
+
695
+ <ul>
696
+ <?r Task.filter(:done => true).each do |task| ?>
697
+ <li>
698
+ #{ h(task.title) }: #{ task.done },
699
+ (#{ anchor('open', 'open', task.title) })
700
+ (#{ anchor('delete', 'delete', task.title) })
701
+ </li>
702
+ <?r end ?>
703
+ </ul>
704
+ </body>
705
+ </html>
706
+ --------------------------------------------------------------------------------
707
+
708
+ Having a déjà vu?
709
+
710
+ Yes, me too, must be an error in the matrix.
711
+
712
+ If we want one thing from a web-framework, it's to spare us writing repetitive
713
+ code like this (I hope you did copy&paste).
714
+
715
+ What we actually wanted to do is _sharing_ the boilerplate around our listing
716
+ of tasks, that's what we call 'layout'.
717
+
718
+ Every action can have a layout associated with it, remember that empty 'layout'
719
+ directory in your application? That's exactly where we will put it.
720
+
721
+ [source,html]
722
+ --------------------------------------------------------------------------------
723
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
724
+ <html>
725
+ <head>
726
+ <title>TodoList</title>
727
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
728
+ </head>
729
+ <body>
730
+ <h1>TodoList</h1>
731
+ <form method="post" action="#{ route('create') }">
732
+ <fieldset>
733
+ <legend>Add a task by entering a title.</legend>
734
+ <label for="form-title">Task title:</label>
735
+ <input id="form-title" name="title" type="text" value="#{ @title }"/>
736
+ <input type="submit" value="Create" />
737
+ </fieldset>
738
+ </form>
739
+ #{ @content }
740
+ </body>
741
+ </html>
742
+ --------------------------------------------------------------------------------
743
+
744
+ And to tell Ramaze which layout to use for our `Tasks` we'll have to add a line
745
+ to the Controller.
746
+
747
+ [source,ruby]
748
+ --------------------------------------------------------------------------------
749
+ class Tasks < Ramaze::Controller
750
+ map '/'
751
+ layout 'default'
752
+ end
753
+ --------------------------------------------------------------------------------
754
+
755
+ And finally, since we are fond of valid HTML and just love to get rid of boring
756
+ boilerplate we can delete the slack from our templates.
757
+
758
+ 'view/index.xhtml' becomes:
759
+
760
+ [source,html]
761
+ --------------------------------------------------------------------------------
762
+ <h2>Done Tasks</h2>
763
+
764
+ #{ anchor('Pending tasks', 'done') }
765
+
766
+ <ul>
767
+ <?r Task.filter(:done => false).each do |task| ?>
768
+ <li>
769
+ #{ h(task.title) },
770
+ (#{ anchor('close', 'close', task.title) })
771
+ (#{ anchor('delete', 'delete', task.title) })
772
+ </li>
773
+ <?r end ?>
774
+ </ul>
775
+ --------------------------------------------------------------------------------
776
+
777
+ 'view/done.xhtml' becomes:
778
+
779
+ [source,html]
780
+ --------------------------------------------------------------------------------
781
+ <h2>Pending Tasks</h2>
782
+
783
+ #{ anchor('Done tasks', 'done') }
784
+
785
+ <ul>
786
+ <?r Task.filter(:done => true).each do |task| ?>
787
+ <li>
788
+ #{ h(task.title) },
789
+ (#{ anchor('open', 'open', task.title) })
790
+ (#{ anchor('delete', 'delete', task.title) })
791
+ </li>
792
+ <?r end ?>
793
+ </ul>
794
+ --------------------------------------------------------------------------------
795
+
796
+ Well, that's so much better, we even included links between the actions.
797
+
798
+
799
+ == Eleventh Step, not all that is gold glitters...
800
+
801
+ You have to admit, it's a lot of fun having such a sophisticated application,
802
+ but what good is it if it's too ugly to show it even to your closest friends?
803
+ They will never become addicted enough to your fancy todo-list to actually do
804
+ all the work for you.
805
+
806
+ Let's do things with style, with a style-sheet.
807
+
808
+ Now is the time to fire up your editor, point it at 'public/css/screen.css' and
809
+ churn out something of your liking.
810
+
811
+ We will not cover this part in the tutorial, an example style-sheet is located
812
+ in the example todo-list.
813
+
814
+ What we do cover is adding it to your application, or the `<head>` in
815
+ 'layout/default.xhtml' to be exact:
816
+
817
+ [source,html]
818
+ --------------------------------------------------------------------------------
819
+ <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01//EN">
820
+ <html>
821
+ <head>
822
+ <title>TodoList</title>
823
+ <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
824
+ <link rel="stylesheet" type="text/css" href="/css/screen.css" />
825
+ </head>
826
+ --------------------------------------------------------------------------------
827
+
828
+ Voilà, you now have acquired the Certificate of Ramazeness and all your friends
829
+ and enemies envy you.
830
+
831
+
832
+ == Twelfth Step, configuring configurable configurability
833
+
834
+ To round up this tutorial a bit, let's introduce you to configuration in Ramaze.
835
+ There are a number of ways to configure Ramaze, but here we'll just see the
836
+ most common ones with some options you'll most likely want to change.
837
+
838
+ First of all, you have been running your ramaze application always on the same
839
+ port, `7000`, which prevents you from starting more than one instance or other
840
+ applications.
841
+
842
+ To change the port, you can, for example:
843
+
844
+ [source,ruby]
845
+ --------------------------------------------------------------------------------
846
+ Ramaze.options.adapter.port = 80
847
+ --------------------------------------------------------------------------------
848
+
849
+ NOTE: Running a server on a port below 1024 will require root privileges and is
850
+ generally not advised for applications that don't drop their privileges
851
+ after establishing a connection.
852
+ Please have a look at http://wiki.ramaze.net/Deployment for better ways
853
+ to deploy your site using a reverse proxy like apache, lighttpd, or
854
+ nginx.
855
+
856
+ OK, a different port is fine, but how about some speed-boost? For this we will
857
+ need a faster server like http://mongrel.rubyforge.org[Mongrel] or
858
+ http://thin.rubyforge.org[Thin].
859
+
860
+ You can install either one via:
861
+
862
+ --------------------------------------------------------------------------------
863
+ gem install thin
864
+ gem install mongrel
865
+ --------------------------------------------------------------------------------
866
+
867
+ Now to the configuration:
868
+
869
+ [source,ruby]
870
+ --------------------------------------------------------------------------------
871
+ # The default is WEBrick
872
+ Ramaze.options.adapter.adapter = :webrick
873
+
874
+ # How about using Mongrel instead?
875
+ Ramaze.options.adapter.adapter = :mongrel
876
+
877
+ # Or maybe Thin?
878
+ Ramaze.options.adapter.adapter = :thin
879
+ --------------------------------------------------------------------------------
880
+
881
+ For the full performance, switch Ramaze into `:live` mode:
882
+
883
+ [source,ruby]
884
+ --------------------------------------------------------------------------------
885
+ # The default is :dev
886
+ Ramaze.options.mode = :live
887
+
888
+ # And here comes :live
889
+ Ramaze.options.mode = :live
890
+ --------------------------------------------------------------------------------
891
+
892
+ The major differences between `:dev` and `:live` are that in `:live` mode your
893
+ code won't be automatically reloaded if it has changed and we don't run every
894
+ request through `Rack::Lint`, which helps you to stay within the
895
+ request/response specifications required by Rack.
896
+
897
+
898
+ [[glossary]]
899
+ == Glossary
900
+
901
+ [glossary]
902
+ RDBMS::
903
+ Relational Database Management System
904
+ ORM::
905
+ Object Relationship Mapper: Maps data into objects and assists in querying
906
+ and manipulation
907
+ MVC::
908
+ Model, View, Controller: one of the patterns traditionally used for GUIs in Smalltalk.
909
+ Etanni::
910
+ Innate spelled backwards.
911
+ Innate::
912
+ Core of Ramaze.
913
+ Rack::
914
+ HTTP abstraction layer and interface used by the majority of Ruby web-frameworks.
915
+ Templating engine::
916
+ Used to process so-called templates with inlined source code or instructions
917
+ to produce dynamic resulting documents. Examples for traditional templating
918
+ engines are XSLT, SSI, ERB.
919
+ RSI::
920
+ Repetive Strain Injury, prevalent among the members of the church of Emacs.