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,278 @@
1
+ This document is a humble attempt to explain the internal workings of Ramaze and
2
+ how the different parts fit into the big picture.
3
+
4
+ It does not try to describe every little detail, as you will be better off
5
+ reading the actual source instead. But you will at least get an idea of where to
6
+ look.
7
+
8
+ ### Ramaze
9
+
10
+ Ramaze is a web framework and therefor tries to make it simple to deploy your
11
+ own applications on top of it.
12
+ Let's outline the realms that Ramaze works in as to show what the current
13
+ limitations and features are.
14
+
15
+
16
+ #### Life of a request/response cycle
17
+
18
+ This is a small summary of how a request creates a response in the
19
+ examples/hello.rb and webrick (to keep it simple and short).
20
+ All files referenced here are in lib/ramaze/ unless indicated otherwise.
21
+ We don't explain the startup/shutdown process, only what happens from request to
22
+ the eventual response.
23
+
24
+ Browser sends request, webrick receives it and hands the ENV over to our rack
25
+ handler (adapter/webrick.rb and adapter/base.rb).
26
+ There it gets converted into a Ramaze::Request (trinity/request.rb) and
27
+ a new blank Ramaze::Response (trinity/response.rb) is created.
28
+ These two objects are then sent to Dispatcher::handle (dispatcher.rb).
29
+
30
+ This all happens inside a new Thread, which is what Ramaze takes advantage of by
31
+ assigning Thread-variables. You can see this now in
32
+ Dispatcher::setup_environment which sets :request/:session/:response in
33
+ Thread.current.
34
+
35
+ After that, Dispatcher::dispatch is called with the path from request.path_info
36
+ which in turn takes every class/module set in Dispatcher::FILTER and calls
37
+ ::process with the path.
38
+
39
+
40
+ ##### First, `/favicon.ico` (for most browsers)
41
+
42
+ The first in FILTER is Dispatcher::File (dispatcher/file.rb) which searches
43
+ Global.public_root and afterwards Global.public_proto for a matching file on
44
+ this path. In our example the file found is a favicon.ico from
45
+ Global.public_proto.
46
+
47
+ The contents of FILTER have to return a Ramaze::Response, either the (possibly
48
+ modified) original (Response#build helps with that) or a totally new
49
+ one.
50
+
51
+ In our case, Dispatcher::File uses response#build with an opened filehandler as
52
+ body, '200 OK' as status and the Content-Type set to what Tool::MIME.type_for
53
+ tells it is the correct mimetype for this file.
54
+
55
+
56
+ ##### Second, `/hello`
57
+
58
+ We start in the processing of FILTER, since the previous steps are the same for
59
+ every request.
60
+
61
+ Here we now get only a nil value back from Dispatcher::File since no file in our
62
+ two public directories exists for the given path.
63
+
64
+ So, this time, Dispatcher::Action is called via ::process and the first thing
65
+ this dispatcher does is trying to set the body of the request to the answer of
66
+ Controller.handle (controller.rb) for the given path.
67
+
68
+ Controller::handle doesn't do much either, but calls Controller::resolve
69
+ (controller/resolve.rb) for the path.
70
+
71
+ Here we get now into the guts of Ramaze, despite our efforts it's no easy
72
+ reading since the underlying theory is a bit complex and many edge-cases have to
73
+ be solved.
74
+
75
+ Let me try to quickly sketch what happens here, maybe we can add a chapter about
76
+ this aspect of Ramaze later.
77
+
78
+ First we generate a pattern of how the requested path could fit into our
79
+ controller and template structure. `/hello` only has 3 possible outcomes:
80
+
81
+ Controller on '/', template or method `hello`
82
+ Controller on '/', method `index` with parameter `hello`
83
+ Controller on '/hello', method or template `index`
84
+
85
+ After matching (in the order we wrote here) these possibilities against your
86
+ application we get only one possibility, MainController on '/' with method
87
+ `index`.
88
+
89
+ The result is stored into an instance of Action and cached for repeated lookups,
90
+ then passed back into Dispatcher::handle which subsequently calls Action#render
91
+ (action/render.rb) on it.
92
+
93
+ From here, Thread.current[:action] gets set and #uncached_render is called. This
94
+ calls #before_process which only has effects if you have the AspectHelper
95
+ activated and next on comes engine.transform with self as parameter.
96
+ #engine is a method that figures out which engine this Action has to be rendered
97
+ with, according to things like trait[:engine] in your controller and the
98
+ extension of a template. In this case we have neither and the default engine
99
+ Template::Ezamar (template/ezamar.rb) is used.
100
+
101
+ So off we go, to Template::Ezamar::transform with the current instance of Action
102
+ as parameter.
103
+
104
+ ::transform first calls ::wrap_compile which is inherited from Template
105
+ (template.rb) and manages caching of compiled templates, calling ::compile with
106
+ the action and template.
107
+
108
+ The template again is retrieved through two attempts, firstly, we always call
109
+ the method (if specified from Controller::resolve) on the controller, we
110
+ temporarily store its result and replace it if a path for a template is set with
111
+ the contents of the file on this path. The result of this is the final template
112
+ that is ready for compilation.
113
+
114
+ In the case of Ezamar, we first walk the TRANSFORM_PIPELINE (only
115
+ Ezamar::Element (template/ezamar/element.rb) with ::transform and pass each the
116
+ template for manipulation. In the example we don't have any elements, so we get
117
+ back what we gave and generate a new instance of Ezamar::Template
118
+ (template/ezamar/engine.rb) with the template and a path that indicates eval
119
+ where we currently are supposed to be (templates path or the transformer).
120
+
121
+ This instance is passed back to Ezamar::transform and we call #result with the
122
+ actions binding (retrieved from earlier instantiation of the controller and
123
+ subsequently eval `binding` inside of it).
124
+
125
+ Now it's all done, we have got our body for the response which will be sent back
126
+ to our handler as body.
127
+
128
+
129
+ #### The Ramaze module
130
+
131
+ Ramaze is also the main module or so-called namespace that the framework lives
132
+ in. It has
133
+
134
+ Tasks on require
135
+
136
+ * Inform
137
+ * LogHub.new(Informer)
138
+ * Global
139
+ * GlobalStruct.new
140
+
141
+
142
+ Tasks on startup as defined in Ramaze.trait[:internals] in lib/ramaze.rb
143
+
144
+ * Global::startup
145
+ * passed options to Ramaze.start
146
+ * CLI options from bin/ramaze (treat as passed.merge)
147
+ * Global options set before startup (fake Global?)
148
+
149
+ * Cache::startup
150
+ * adds the following caches via Cache.add:
151
+ * compiled
152
+ If Global.compile is set true this cache is used to store the compiled
153
+ templates.
154
+
155
+ * actions
156
+ Caching compiled actions.
157
+
158
+ * patterns
159
+ This is used in Controller::resolve to cache the generated patterns for a
160
+ path.
161
+
162
+ * resolved
163
+ Caching the resolved but not yet compiled actions by their path.
164
+
165
+ * shield
166
+ Caching the generated errors for the path, so on repeated erronous
167
+ requests no new error-page has to be generated.
168
+
169
+ * Controller::startup
170
+ * mapping of all subclassed Controller
171
+ * validation of mapping
172
+ * validation of template_root
173
+
174
+ * Session::startup
175
+ * adds Cache.sessions if Global.sessions is true
176
+ This cache is used to store all sessions with their session-id as key.
177
+
178
+ * SourceReload::startup
179
+ * start with Global.reload_interval
180
+ * assign Global.sourcereload
181
+
182
+ * Adapter::startup
183
+ * interpret Global.adapter
184
+ * add every created adapter to Global.adapters
185
+
186
+
187
+ Tasks on shutdown
188
+
189
+ * Adapter::shutdown (iterates Global.adapters)
190
+ * Inform::shutdown (iterates all in LogHub)
191
+
192
+
193
+
194
+ #### Global configuration
195
+
196
+ Any serious application or framework needs to be configured.
197
+ Yes, I wished there was a silver bullet to serve all your needs as well, but at
198
+ the current stage of programming development there is no such thing.
199
+ So, since we need to configure, we should make it as simple and painless as
200
+ possible, and, thanks to Ruby, it is actually quite enjoyable to do that.
201
+ You can find a very detailed description about Global in the section about
202
+ Configuration, for now just the basics.
203
+
204
+ The basis of Ramaze::Global, the instance that is holding most part of your
205
+ configuration or at least links to the actual places, is the
206
+ Ramaze::GlobalStruct (ramaze/global.rb), which is a subclass of OpenStruct. If
207
+ you are not yet familiar with OpenStruct, I very much recommend to read its
208
+ documentation and play around a bit, it is basically just a wrapper around a
209
+ normal Hash where you can access the keys instead of ostruct[:foo] with
210
+ ostruct.foo.
211
+ It simply defines a new accessors on assignment by catching things in
212
+ method_missing. I won't go into more details here, I hope you got the principle.
213
+
214
+ Now, based on this technique, GlobalStruct adds things like defaults and a
215
+ couple of convenience methods like they are common in Ruby, giving you more
216
+ power by tapping to the internal Hash of the GlobalStruct and adding
217
+ update/setup methods so you can assign many key/value pairs at once.
218
+ The RDocs will give you a very good overview of what is available and how one is
219
+ supposed to work with it.
220
+
221
+ Now back to the big picture.
222
+
223
+ Ramaze accesses Global all over the place, there have been made several choices
224
+ as to why using something like Global is considered beneficial against choosing
225
+ for example global variables, which would be considered as a fatal choice by
226
+ any respected Rubyist anyway.
227
+
228
+ Now to something more subtle, which has to do with Global. I speak about traits,
229
+ which is a very different concept in most of its implementations, but it is
230
+ something that basically fits this name. It is configuration of single Objects
231
+ and whole ancestries.
232
+ You can give an object a trait, and most likely will use it along the lines of
233
+ something like MyController.trait(:map => '/'), which would be picked up on
234
+ startup and used to create Global.mapping - where we are at configuration again.
235
+ Choosing this style of configuration complementary to a central place to put all
236
+ your configuration was made very early in the development of Ramaze, and the
237
+ basic code of how traits are implemented and used has proven very efficient both
238
+ in understanding and using them.
239
+
240
+ There is a basic distinction when to use Global and when to use traits and when
241
+ to generate or assume one based on the other.
242
+
243
+ If something affects your whole application and is either used directly in the
244
+ Ramaze module or throughout the framework it is considered to be put into Global
245
+ to gain benefits of better documentation and accessibility.
246
+
247
+ On the other hand - if something is used in a configuring manner by a class that
248
+ is instantiated often (like Controller is for example), or a module that cannot
249
+ hold instance variables in a nice manner and is also not a constant - then it is
250
+ configured using traits.
251
+
252
+
253
+ Ramaze
254
+ Global
255
+ Adapter
256
+ Dispatcher
257
+ Controller
258
+ Action
259
+
260
+ Session
261
+ Helper
262
+ Tool
263
+
264
+
265
+ #### The Web
266
+
267
+ The so called web consists of a plethora of data, most of it is browsable
268
+ through a web browser that just about every toaster has installed these days.
269
+ The browser is the target of a web author, trying to utilize common standards
270
+ like HTML and CSS which are means for data and layout to be combined, giving the
271
+ browser a way to display the data.
272
+ Ramaze works on the URI-scale web, meaning that addresses like
273
+ http://someserver.com/blog/article/1 have a unique representation on your
274
+ server.
275
+ If we stay with this example, we see already everything Ramaze needs to see to
276
+ serve a page based on your instructions.
277
+ We assume that blog/article is a Controller named ArticleController in the blog
278
+ application.
@@ -0,0 +1,64 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <kml xmlns="http://earth.google.com/kml/2.2">
3
+ <Document>
4
+ <Placemark>
5
+ <name>manveru</name>
6
+ <description><![CDATA[ <img src="http://manveru.mine.nu/public/me.png" /><br />
7
+ Tokyo, Japan ]]>
8
+ </description>
9
+ <Point>
10
+ <coordinates>139.667846,35.614759</coordinates>
11
+ </Point>
12
+ </Placemark>
13
+ <Placemark>
14
+ <name>Pistos</name>
15
+ <description>
16
+ <![CDATA[
17
+ <img src="http://purepistos.net/favicon32.png" alt="Pistos" /><br />
18
+ Toronto, Canada<br />
19
+ <a href="http://blog.purepistos.net">blog.purepistos.net</a>
20
+ ]]>
21
+ </description>
22
+ <Point>
23
+ <coordinates>-79.386985,43.642515,0</coordinates>
24
+ </Point>
25
+ </Placemark>
26
+ <Placemark>
27
+ <name>MonoDelDiablo</name>
28
+ <description><![CDATA[ Seattle, Washington, United States ]]></description>
29
+ <Point>
30
+ <coordinates>-122.266881,47.682765,0</coordinates>
31
+ </Point>
32
+ </Placemark>
33
+ <Placemark>
34
+ <name>Kashia</name>
35
+ <description><![CDATA[ Helsinki, Etela-Suomen Laani, Finland ]]></description>
36
+ <Point>
37
+ <coordinates>8.447204,49.028928,0</coordinates>
38
+ </Point>
39
+ </Placemark>
40
+ <Placemark>
41
+ <name>zenix</name>
42
+ <description><![CDATA[ Gaithersburg, Maryland, United States ]]></description>
43
+ <Point>
44
+ <coordinates>-77.183338,39.137049,0</coordinates>
45
+ </Point>
46
+ </Placemark>
47
+ <Placemark>
48
+ <name>tmm1</name>
49
+ <description><![CDATA[ <img src="http://tmm1.net/me.jpg" /><br />
50
+ Boston, Massachussetts ]]>
51
+ </description>
52
+ <Point>
53
+ <coordinates>-71.084371,42.365975,0</coordinates>
54
+ </Point>
55
+ </Placemark>
56
+ <Placemark>
57
+ <name>riffraff</name>
58
+ <description><![CDATA[ Rome, Italia ]]></description>
59
+ <Point>
60
+ <coordinates>41.993372,12.087193,0</coordinates>
61
+ </Point>
62
+ </Placemark>
63
+ </Document>
64
+ </kml>
@@ -0,0 +1,1379 @@
1
+ <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
2
+ "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
3
+ <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
4
+ <head>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
6
+ <meta name="generator" content="AsciiDoc 8.4.2" />
7
+ <title>The official Ramaze Todo-list tutorial</title>
8
+ <style type="text/css">
9
+ /* Debug borders */
10
+ p, li, dt, dd, div, pre, h1, h2, h3, h4, h5, h6 {
11
+ /*
12
+ border: 1px solid red;
13
+ */
14
+ }
15
+
16
+ body {
17
+ margin: 1em 5% 1em 5%;
18
+ }
19
+
20
+ a {
21
+ color: blue;
22
+ text-decoration: underline;
23
+ }
24
+ a:visited {
25
+ color: fuchsia;
26
+ }
27
+
28
+ em {
29
+ font-style: italic;
30
+ color: navy;
31
+ }
32
+
33
+ strong {
34
+ font-weight: bold;
35
+ color: #083194;
36
+ }
37
+
38
+ tt {
39
+ color: navy;
40
+ }
41
+
42
+ h1, h2, h3, h4, h5, h6 {
43
+ color: #527bbd;
44
+ font-family: sans-serif;
45
+ margin-top: 1.2em;
46
+ margin-bottom: 0.5em;
47
+ line-height: 1.3;
48
+ }
49
+
50
+ h1, h2, h3 {
51
+ border-bottom: 2px solid silver;
52
+ }
53
+ h2 {
54
+ padding-top: 0.5em;
55
+ }
56
+ h3 {
57
+ float: left;
58
+ }
59
+ h3 + * {
60
+ clear: left;
61
+ }
62
+
63
+ div.sectionbody {
64
+ font-family: serif;
65
+ margin-left: 0;
66
+ }
67
+
68
+ hr {
69
+ border: 1px solid silver;
70
+ }
71
+
72
+ p {
73
+ margin-top: 0.5em;
74
+ margin-bottom: 0.5em;
75
+ }
76
+
77
+ ul, ol, li > p {
78
+ margin-top: 0;
79
+ }
80
+
81
+ pre {
82
+ padding: 0;
83
+ margin: 0;
84
+ }
85
+
86
+ span#author {
87
+ color: #527bbd;
88
+ font-family: sans-serif;
89
+ font-weight: bold;
90
+ font-size: 1.1em;
91
+ }
92
+ span#email {
93
+ }
94
+ span#revision {
95
+ font-family: sans-serif;
96
+ }
97
+
98
+ div#footer {
99
+ font-family: sans-serif;
100
+ font-size: small;
101
+ border-top: 2px solid silver;
102
+ padding-top: 0.5em;
103
+ margin-top: 4.0em;
104
+ }
105
+ div#footer-text {
106
+ float: left;
107
+ padding-bottom: 0.5em;
108
+ }
109
+ div#footer-badges {
110
+ float: right;
111
+ padding-bottom: 0.5em;
112
+ }
113
+
114
+ div#preamble {
115
+ margin-top: 1.5em;
116
+ margin-bottom: 1.5em;
117
+ }
118
+ div.tableblock, div.imageblock, div.exampleblock, div.verseblock,
119
+ div.quoteblock, div.literalblock, div.listingblock, div.sidebarblock,
120
+ div.admonitionblock {
121
+ margin-top: 1.5em;
122
+ margin-bottom: 1.5em;
123
+ }
124
+ div.admonitionblock {
125
+ margin-top: 2.5em;
126
+ margin-bottom: 2.5em;
127
+ }
128
+
129
+ div.content { /* Block element content. */
130
+ padding: 0;
131
+ }
132
+
133
+ /* Block element titles. */
134
+ div.title, caption.title {
135
+ color: #527bbd;
136
+ font-family: sans-serif;
137
+ font-weight: bold;
138
+ text-align: left;
139
+ margin-top: 1.0em;
140
+ margin-bottom: 0.5em;
141
+ }
142
+ div.title + * {
143
+ margin-top: 0;
144
+ }
145
+
146
+ td div.title:first-child {
147
+ margin-top: 0.0em;
148
+ }
149
+ div.content div.title:first-child {
150
+ margin-top: 0.0em;
151
+ }
152
+ div.content + div.title {
153
+ margin-top: 0.0em;
154
+ }
155
+
156
+ div.sidebarblock > div.content {
157
+ background: #ffffee;
158
+ border: 1px solid silver;
159
+ padding: 0.5em;
160
+ }
161
+
162
+ div.listingblock > div.content {
163
+ border: 1px solid silver;
164
+ background: #f4f4f4;
165
+ padding: 0.5em;
166
+ }
167
+
168
+ div.quoteblock {
169
+ padding-left: 2.0em;
170
+ margin-right: 10%;
171
+ }
172
+ div.quoteblock > div.attribution {
173
+ padding-top: 0.5em;
174
+ text-align: right;
175
+ }
176
+
177
+ div.verseblock {
178
+ padding-left: 2.0em;
179
+ margin-right: 10%;
180
+ }
181
+ div.verseblock > div.content {
182
+ white-space: pre;
183
+ }
184
+ div.verseblock > div.attribution {
185
+ padding-top: 0.75em;
186
+ text-align: left;
187
+ }
188
+ /* DEPRECATED: Pre version 8.2.7 verse style literal block. */
189
+ div.verseblock + div.attribution {
190
+ text-align: left;
191
+ }
192
+
193
+ div.admonitionblock .icon {
194
+ vertical-align: top;
195
+ font-size: 1.1em;
196
+ font-weight: bold;
197
+ text-decoration: underline;
198
+ color: #527bbd;
199
+ padding-right: 0.5em;
200
+ }
201
+ div.admonitionblock td.content {
202
+ padding-left: 0.5em;
203
+ border-left: 2px solid silver;
204
+ }
205
+
206
+ div.exampleblock > div.content {
207
+ border-left: 2px solid silver;
208
+ padding: 0.5em;
209
+ }
210
+
211
+ div.imageblock div.content { padding-left: 0; }
212
+ div.imageblock img { border: 1px solid silver; }
213
+ span.image img { border-style: none; }
214
+
215
+ dl {
216
+ margin-top: 0.8em;
217
+ margin-bottom: 0.8em;
218
+ }
219
+ dt {
220
+ margin-top: 0.5em;
221
+ margin-bottom: 0;
222
+ font-style: normal;
223
+ color: navy;
224
+ }
225
+ dd > *:first-child {
226
+ margin-top: 0.1em;
227
+ }
228
+
229
+ ul, ol {
230
+ list-style-position: outside;
231
+ }
232
+ ol.arabic {
233
+ list-style-type: decimal;
234
+ }
235
+ ol.loweralpha {
236
+ list-style-type: lower-alpha;
237
+ }
238
+ ol.upperalpha {
239
+ list-style-type: upper-alpha;
240
+ }
241
+ ol.lowerroman {
242
+ list-style-type: lower-roman;
243
+ }
244
+ ol.upperroman {
245
+ list-style-type: upper-roman;
246
+ }
247
+
248
+ div.compact ul, div.compact ol,
249
+ div.compact p, div.compact p,
250
+ div.compact div, div.compact div {
251
+ margin-top: 0.1em;
252
+ margin-bottom: 0.1em;
253
+ }
254
+
255
+ div.tableblock > table {
256
+ border: 3px solid #527bbd;
257
+ }
258
+ thead {
259
+ font-family: sans-serif;
260
+ font-weight: bold;
261
+ }
262
+ tfoot {
263
+ font-weight: bold;
264
+ }
265
+ td > div.verse {
266
+ white-space: pre;
267
+ }
268
+ p.table {
269
+ margin-top: 0;
270
+ }
271
+ /* Because the table frame attribute is overriden by CSS in most browsers. */
272
+ div.tableblock > table[frame="void"] {
273
+ border-style: none;
274
+ }
275
+ div.tableblock > table[frame="hsides"] {
276
+ border-left-style: none;
277
+ border-right-style: none;
278
+ }
279
+ div.tableblock > table[frame="vsides"] {
280
+ border-top-style: none;
281
+ border-bottom-style: none;
282
+ }
283
+
284
+
285
+ div.hdlist {
286
+ margin-top: 0.8em;
287
+ margin-bottom: 0.8em;
288
+ }
289
+ div.hdlist tr {
290
+ padding-bottom: 15px;
291
+ }
292
+ dt.hdlist1.strong, td.hdlist1.strong {
293
+ font-weight: bold;
294
+ }
295
+ td.hdlist1 {
296
+ vertical-align: top;
297
+ font-style: normal;
298
+ padding-right: 0.8em;
299
+ color: navy;
300
+ }
301
+ td.hdlist2 {
302
+ vertical-align: top;
303
+ }
304
+ div.hdlist.compact tr {
305
+ margin: 0;
306
+ padding-bottom: 0;
307
+ }
308
+
309
+ .comment {
310
+ background: yellow;
311
+ }
312
+
313
+ @media print {
314
+ div#footer-badges { display: none; }
315
+ }
316
+
317
+ div#toctitle {
318
+ color: #527bbd;
319
+ font-family: sans-serif;
320
+ font-size: 1.1em;
321
+ font-weight: bold;
322
+ margin-top: 1.0em;
323
+ margin-bottom: 0.1em;
324
+ }
325
+
326
+ div.toclevel1, div.toclevel2, div.toclevel3, div.toclevel4 {
327
+ margin-top: 0;
328
+ margin-bottom: 0;
329
+ }
330
+ div.toclevel2 {
331
+ margin-left: 2em;
332
+ font-size: 0.9em;
333
+ }
334
+ div.toclevel3 {
335
+ margin-left: 4em;
336
+ font-size: 0.9em;
337
+ }
338
+ div.toclevel4 {
339
+ margin-left: 6em;
340
+ font-size: 0.9em;
341
+ }
342
+ </style>
343
+ <script type="text/javascript">
344
+ /*<![CDATA[*/
345
+ window.onload = function(){generateToc(2)}
346
+ /* Author: Mihai Bazon, September 2002
347
+ * http://students.infoiasi.ro/~mishoo
348
+ *
349
+ * Table Of Content generator
350
+ * Version: 0.4
351
+ *
352
+ * Feel free to use this script under the terms of the GNU General Public
353
+ * License, as long as you do not remove or alter this notice.
354
+ */
355
+
356
+ /* modified by Troy D. Hanson, September 2006. License: GPL */
357
+ /* modified by Stuart Rackham, October 2006. License: GPL */
358
+
359
+ function getText(el) {
360
+ var text = "";
361
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
362
+ if (i.nodeType == 3 /* Node.TEXT_NODE */) // IE doesn't speak constants.
363
+ text += i.data;
364
+ else if (i.firstChild != null)
365
+ text += getText(i);
366
+ }
367
+ return text;
368
+ }
369
+
370
+ function TocEntry(el, text, toclevel) {
371
+ this.element = el;
372
+ this.text = text;
373
+ this.toclevel = toclevel;
374
+ }
375
+
376
+ function tocEntries(el, toclevels) {
377
+ var result = new Array;
378
+ var re = new RegExp('[hH]([2-'+(toclevels+1)+'])');
379
+ // Function that scans the DOM tree for header elements (the DOM2
380
+ // nodeIterator API would be a better technique but not supported by all
381
+ // browsers).
382
+ var iterate = function (el) {
383
+ for (var i = el.firstChild; i != null; i = i.nextSibling) {
384
+ if (i.nodeType == 1 /* Node.ELEMENT_NODE */) {
385
+ var mo = re.exec(i.tagName)
386
+ if (mo)
387
+ result[result.length] = new TocEntry(i, getText(i), mo[1]-1);
388
+ iterate(i);
389
+ }
390
+ }
391
+ }
392
+ iterate(el);
393
+ return result;
394
+ }
395
+
396
+ // This function does the work. toclevels = 1..4.
397
+ function generateToc(toclevels) {
398
+ var toc = document.getElementById("toc");
399
+ var entries = tocEntries(document.getElementsByTagName("body")[0], toclevels);
400
+ for (var i = 0; i < entries.length; ++i) {
401
+ var entry = entries[i];
402
+ if (entry.element.id == "")
403
+ entry.element.id = "toc" + i;
404
+ var a = document.createElement("a");
405
+ a.href = "#" + entry.element.id;
406
+ a.appendChild(document.createTextNode(entry.text));
407
+ var div = document.createElement("div");
408
+ div.appendChild(a);
409
+ div.className = "toclevel" + entry.toclevel;
410
+ toc.appendChild(div);
411
+ }
412
+ if (entries.length == 0)
413
+ document.getElementById("header").removeChild(toc);
414
+ }
415
+ /*]]>*/
416
+ </script>
417
+ </head>
418
+ <body>
419
+ <div id="header">
420
+ <h1>The official Ramaze Todo-list tutorial</h1>
421
+ <span id="author">Michael 'manveru' Fellinger</span><br />
422
+ <span id="email"><tt>&lt;<a href="mailto:m.fellinger@gmail.com">m.fellinger@gmail.com</a>&gt;</tt></span><br />
423
+ <span id="revision">version 2.0,</span>
424
+ March 2009
425
+ <div id="toc">
426
+ <div id="toctitle">Table of Contents</div>
427
+ <noscript><p><b>JavaScript must be enabled in your browser to display the table of contents.</b></p></noscript>
428
+ </div>
429
+ </div>
430
+ <h2 id="_abstract">Abstract</h2>
431
+ <div class="sectionbody">
432
+ <div class="paragraph"><p>Welcome to the official tutorial for <a href="http://ramaze.net">Ramaze</a>, the mandatory
433
+ Todo-list.</p></div>
434
+ <div class="paragraph"><p>I also assume that you have some experience with HTML and some other basics in
435
+ web-development already (you want to learn a web-framework after all).</p></div>
436
+ <div class="paragraph"><p>The tutorial assumes a working installation of <a href="http://ruby-lang.org">Ruby</a> and
437
+ <a href="http://rubygems.org/">Rubygems</a>.</p></div>
438
+ <div class="paragraph"><p>For more information on how to install these please read the introductory
439
+ documentation of Ramaze, this is not in the scope of this tutorial.</p></div>
440
+ <div class="paragraph"><p>To install Ramaze you can <tt>gem install ramaze</tt>, other ways of installation are
441
+ covered by the <a href="http://wiki.ramaze.net/">Ramaze Wiki</a>.</p></div>
442
+ <div class="paragraph"><p>Should you encounter any problems while doing this tutorial, this might either
443
+ be because Ramaze changed (which happens very often while it is still young)
444
+ or I actually made some mistake while writing it.</p></div>
445
+ <div class="paragraph"><p>In either case it would make me (and all other poor fellows who happen to try
446
+ this tutorial) very happy if you could spare some time and report the issue
447
+ either on the <a href="http://github.com/manveru/ramaze/issues">Bug tracker</a> , or just
448
+ drop by on IRC on <tt>irc.freenode.org</tt> in the channel <tt>#ramaze</tt>.</p></div>
449
+ <div class="paragraph"><p>If you have trouble with some of the terms used in this tutorial you can
450
+ consult the <a href="#glossary">Glossary</a> at the end of this document.</p></div>
451
+ <div class="paragraph"><p>We are also working on a book that describes Ramaze in more depth, called
452
+ <em>Journey to Ramaze</em>, it is still very much work in progress, but some of the
453
+ contents might interest you.</p></div>
454
+ <div class="paragraph"><p>The repository for the book is at <a href="http://github.com/manveru/ramaze-book">http://github.com/manveru/ramaze-book</a>. Every
455
+ once in a while, updates for the book will be put in HTML and PDF form at
456
+ <a href="http://book.ramaze.net">http://book.ramaze.net</a>.</p></div>
457
+ </div>
458
+ <h2 id="_first_step_create">First Step, Create</h2>
459
+ <div class="sectionbody">
460
+ <div class="paragraph"><p>The last version of this tutorial assumed a generator to produce a skeleton in
461
+ which we do the work. This time around we will do everything from scratch to
462
+ give you a better experience of how exactly the pieces fit together.</p></div>
463
+ <div class="paragraph"><p>You can also skip all the boring learning-by-doing part and play around with
464
+ the source of the todo-list example shipping with Ramaze.</p></div>
465
+ <div class="admonitionblock">
466
+ <table><tr>
467
+ <td class="icon">
468
+ <div class="title">Note</div>
469
+ </td>
470
+ <td class="content">The example and this tutorial differ in some points, it is recommended to
471
+ actually work through the tutorial first and read the example afterwards, it
472
+ takes the basics taught here one step further by utilizing the Model.</td>
473
+ </tr></table>
474
+ </div>
475
+ <div class="paragraph"><p>You can find the example it in the <tt>examples/app/todolist/</tt> directory of your
476
+ Ramaze distribution.
477
+ To find out where that is located (as this differs widely between systems), you
478
+ can follow these steps in <tt>irb</tt>:</p></div>
479
+ <div class="listingblock">
480
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
481
+ by Lorenzo Bettini
482
+ http://www.lorenzobettini.it
483
+ http://www.gnu.org/software/src-highlite -->
484
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'rubygems'</span>
485
+ <span style="font-style: italic"><span style="color: #9A1900"># =&gt; true</span></span>
486
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'ramaze'</span>
487
+ <span style="font-style: italic"><span style="color: #9A1900"># =&gt; true</span></span>
488
+ File<span style="color: #990000">.</span>expand_path<span style="color: #990000">(</span>Ramaze<span style="color: #990000">::</span>BASEDIR <span style="color: #990000">+</span> <span style="color: #FF0000">'/../examples/app/todolist'</span><span style="color: #990000">)</span>
489
+ <span style="font-style: italic"><span style="color: #9A1900"># =&gt; "/home/manveru/c/ramaze/examples/app/todolist"</span></span></tt></pre></div></div>
490
+ <div class="paragraph"><p>To start things off, we will create a basic directory structure looking like this:</p></div>
491
+ <div class="listingblock">
492
+ <div class="content">
493
+ <pre><tt>.
494
+ |-- controller
495
+ |-- layout
496
+ |-- model
497
+ |-- public
498
+ | |-- css
499
+ `-- view</tt></pre>
500
+ </div></div>
501
+ <div class="paragraph"><p>Doing that is quite simple: <tt>mkdir -p controller layout model public/css view</tt></p></div>
502
+ <div class="paragraph"><p>Alright, done? Let&#8217;s go to the next step.</p></div>
503
+ </div>
504
+ <h2 id="_second_step_hello_world">Second Step. Hello, World!</h2>
505
+ <div class="sectionbody">
506
+ <div class="paragraph"><p>To make sure Ramaze is installed, and working correctly we will follow an old
507
+ tradition, we create a file at the root of your application directory called
508
+ <em>start.rb</em> with following content:</p></div>
509
+ <div class="listingblock">
510
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
511
+ by Lorenzo Bettini
512
+ http://www.lorenzobettini.it
513
+ http://www.gnu.org/software/src-highlite -->
514
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'rubygems'</span>
515
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'ramaze'</span>
516
+
517
+ <span style="font-weight: bold"><span style="color: #0000FF">class</span></span> MainController <span style="color: #990000">&lt;</span> Ramaze<span style="color: #990000">::</span>Controller
518
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> index
519
+ <span style="color: #FF0000">"Hello, World!"</span>
520
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
521
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
522
+
523
+ Ramaze<span style="color: #990000">.</span>start</tt></pre></div></div>
524
+ <div class="paragraph"><p>Now we run it:</p></div>
525
+ <div class="listingblock">
526
+ <div class="content">
527
+ <pre><tt>delta ~/tmp/tutorial % ruby start.rb
528
+ D [2009-03-30 14:15:01 $2124] DEBUG | : Using webrick
529
+ I [2009-03-30 14:15:01 $2124] INFO | : WEBrick 1.3.1
530
+ I [2009-03-30 14:15:01 $2124] INFO | : ruby 1.9.2 (2009-03-02) [i686-linux]
531
+ D [2009-03-30 14:15:01 $2124] DEBUG | : TCPServer.new(0.0.0.0, 7000)
532
+ D [2009-03-30 14:15:01 $2124] DEBUG | : Rack::Handler::WEBrick is mounted on /.
533
+ I [2009-03-30 14:15:01 $2124] INFO | : WEBrick::HTTPServer#start: pid=2124 port=7000</tt></pre>
534
+ </div></div>
535
+ <div class="paragraph"><p>The logging output tells us that a server was started, listening to all
536
+ connections at port 7000. If you open your browser and go to
537
+ <a href="http://localhost:7000/">http://localhost:7000/</a> you should be able to see <em>Hello, World!</em>.</p></div>
538
+ </div>
539
+ <h2 id="_third_step_m_like_model">Third Step. M, like Model</h2>
540
+ <div class="sectionbody">
541
+ <div class="paragraph"><p>Model is a term from the MVC paradigm, meaning the representation of data
542
+ within your application.
543
+ Ramaze doesn&#8217;t promote a particular way for this part of your application, and
544
+ how you are supposed to integrate it. Since there are quite a number of ways to
545
+ represent data and none is clearly superior to another, this would be both
546
+ futile and short-sighted.</p></div>
547
+ <div class="paragraph"><p>For the purpose of this tutorial we will use a lightweight database access
548
+ toolkit for Ruby called <a href="http://sequel.rubyforge.org/">Sequel</a>.</p></div>
549
+ <div class="paragraph"><p>Sequel is designed to take the hassle away from connecting to databases and
550
+ manipulating them. Sequel deals with all the boring stuff like maintaining
551
+ connections, formatting SQL correctly and fetching records so you can
552
+ concentrate on your application.</p></div>
553
+ <div class="paragraph"><p>Being familiar with it is not a requirement for this tutorial, but will help
554
+ you tremendously when it comes to writing your own applications.</p></div>
555
+ <div class="paragraph"><p>Installing Sequel is as simple as installing Ramaze: <tt>gem install sequel</tt>.</p></div>
556
+ <div class="paragraph"><p>In this tutorial we are going to use the light-weight
557
+ <a href="http://www.sqlite.org/">sqlite</a> database.
558
+ This requires the <a href="http://rubyforge.org/projects/sqlite-ruby">sqlite-ruby</a>
559
+ bindings.</p></div>
560
+ <div class="paragraph"><p>You can try to <tt>gem install sqlite</tt>, which will complain if your system doesn&#8217;t
561
+ provide bindings, in which case I have to refer you to <a href="http://sqlite.org">http://sqlite.org</a>.</p></div>
562
+ <div class="paragraph"><p>In order to use Sequel we also need a database connection.</p></div>
563
+ <div class="paragraph"><p>So we create a new file at <em>model/init.rb</em> with following content:</p></div>
564
+ <div class="listingblock">
565
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
566
+ by Lorenzo Bettini
567
+ http://www.lorenzobettini.it
568
+ http://www.gnu.org/software/src-highlite -->
569
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'sequel'</span>
570
+
571
+ Sequel<span style="color: #990000">::</span>Model<span style="color: #990000">.</span>plugin<span style="color: #990000">(:</span>schema<span style="color: #990000">)</span>
572
+
573
+ DB <span style="color: #990000">=</span> Sequel<span style="color: #990000">.</span>sqlite<span style="color: #990000">(</span><span style="color: #FF0000">'todolist.db'</span><span style="color: #990000">)</span></tt></pre></div></div>
574
+ <div class="paragraph"><p>The <tt>:schema</tt> plugin is required since Sequel 3.0, if you run a version prior
575
+ to 2.12 you may remove this line if it gives you any problems.</p></div>
576
+ <div class="paragraph"><p>Next we edit <em>start.rb</em>, remove the <tt>Hello</tt> class, and add a require for the
577
+ file, <em>start.rb</em> should look like this now:</p></div>
578
+ <div class="listingblock">
579
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
580
+ by Lorenzo Bettini
581
+ http://www.lorenzobettini.it
582
+ http://www.gnu.org/software/src-highlite -->
583
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'rubygems'</span>
584
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'ramaze'</span>
585
+
586
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'model/init'</span>
587
+
588
+ Ramaze<span style="color: #990000">.</span>start</tt></pre></div></div>
589
+ <div class="paragraph"><p>This should hook us up with a database, but anyone familiar with SQL will now
590
+ ask how we are going to create our schema.</p></div>
591
+ <div class="paragraph"><p>So our next step is to create the actual model for our data, for this we create another file at <em>model/task.rb</em>:</p></div>
592
+ <div class="listingblock">
593
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
594
+ by Lorenzo Bettini
595
+ http://www.lorenzobettini.it
596
+ http://www.gnu.org/software/src-highlite -->
597
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Task <span style="color: #990000">&lt;</span> Sequel<span style="color: #990000">::</span>Model
598
+ set_schema <span style="font-weight: bold"><span style="color: #0000FF">do</span></span>
599
+ primary_key <span style="color: #990000">:</span>id
600
+
601
+ varchar <span style="color: #990000">:</span>title<span style="color: #990000">,</span> <span style="color: #990000">:</span>unique <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span><span style="color: #990000">,</span> <span style="color: #990000">:</span>empty <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span>
602
+ boolean <span style="color: #990000">:</span>done<span style="color: #990000">,</span> <span style="color: #990000">:</span>default <span style="color: #990000">=&gt;</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span>
603
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
604
+
605
+ create_table <span style="font-weight: bold"><span style="color: #0000FF">unless</span></span> table_exists?
606
+
607
+ <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> empty?
608
+ create <span style="color: #990000">:</span>title <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Laundry'</span>
609
+ create <span style="color: #990000">:</span>title <span style="color: #990000">=&gt;</span> <span style="color: #FF0000">'Wash dishes'</span>
610
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
611
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
612
+ <div class="paragraph"><p>For this tutorial we will not bother with migrations, although Sequel does have
613
+ very good support for them as well, but seriously, this is a really simple
614
+ schema that probably won&#8217;t change much over the next few years.</p></div>
615
+ <div class="paragraph"><p>Finally, add a line to your <em>model/init.rb</em> that requires <em>model/task.rb</em>:</p></div>
616
+ <div class="listingblock">
617
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
618
+ by Lorenzo Bettini
619
+ http://www.lorenzobettini.it
620
+ http://www.gnu.org/software/src-highlite -->
621
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'sequel'</span>
622
+
623
+ Sequel<span style="color: #990000">::</span>Model<span style="color: #990000">.</span>plugin<span style="color: #990000">(:</span>schema<span style="color: #990000">)</span>
624
+
625
+ DB <span style="color: #990000">=</span> Sequel<span style="color: #990000">.</span>sqlite<span style="color: #990000">(</span><span style="color: #FF0000">'todolist.db'</span><span style="color: #990000">)</span>
626
+
627
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'model/task'</span></tt></pre></div></div>
628
+ </div>
629
+ <h2 id="_fourth_step_v_like_view">Fourth Step, V, like View</h2>
630
+ <div class="sectionbody">
631
+ <div class="paragraph"><p>To see anything of the data in your Model we will have to add the second
632
+ element in MVC, the View.</p></div>
633
+ <div class="paragraph"><p>We are going to use the templating engine shipping with Ramaze, called Etanni.
634
+ It has a very simple syntax compatible with SGML and XML documents.</p></div>
635
+ <div class="paragraph"><p>When handling a request to <em>/</em>, Ramaze will automatically try to find an Action
636
+ called <em>index</em>. Don&#8217;t bother too much about what Action means just yet, we will
637
+ explain that in more detail later when we come to layouts.</p></div>
638
+ <div class="paragraph"><p>To start we put some contents into <em>view/index.xhtml</em> (xhtml is the default
639
+ filename-extension for Etanni templates)</p></div>
640
+ <div class="listingblock">
641
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
642
+ by Lorenzo Bettini
643
+ http://www.lorenzobettini.it
644
+ http://www.gnu.org/software/src-highlite -->
645
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">&lt;!DOCTYPE</span></span> <span style="color: #009900">html</span> <span style="color: #009900">PUBLIC</span> <span style="color: #FF0000">"-//W3C//DTD HTML 4.01//EN"</span><span style="font-weight: bold"><span style="color: #000080">&gt;</span></span>
646
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;html&gt;</span></span>
647
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;head&gt;</span></span>
648
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;title&gt;</span></span>TodoList<span style="font-weight: bold"><span style="color: #0000FF">&lt;/title&gt;</span></span>
649
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;meta</span></span> <span style="color: #009900">http-equiv</span><span style="color: #990000">=</span><span style="color: #FF0000">"content-type"</span> <span style="color: #009900">content</span><span style="color: #990000">=</span><span style="color: #FF0000">"text/html; charset=UTF-8"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
650
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/head&gt;</span></span>
651
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;body&gt;</span></span>
652
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;h1&gt;</span></span>TodoList<span style="font-weight: bold"><span style="color: #0000FF">&lt;/h1&gt;</span></span>
653
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
654
+ &lt;?r Task.each do |task| ?&gt;
655
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>#{ h(task.title) }: #{ task.done }<span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
656
+ &lt;?r end ?&gt;
657
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span>
658
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/body&gt;</span></span>
659
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/html&gt;</span></span></tt></pre></div></div>
660
+ <div class="paragraph"><p>The <em>&lt;?r ?&gt;</em> and <em>#{ }</em> elements enclose ruby code that will be executed when
661
+ the template is being rendered (on every request to <em>index</em>).
662
+ Code within <em>&lt;?r ?&gt;</em> is only executed and will not show up in the resulting
663
+ document, while code within <em>#{ }</em> will be interpolated.</p></div>
664
+ <div class="paragraph"><p>In this template we iterate over all the data stored in the Task model,
665
+ yielding a list of task titles and the respective status of the task.</p></div>
666
+ <div class="paragraph"><p>That wasn&#8217;t too hard, right?</p></div>
667
+ <div class="paragraph"><p>Now, so we can get our instant pleasure of seeing the result of our (hard)
668
+ work, let&#8217;s see how this looks like in a browser, start your application like above with <tt>ruby start.rb</tt> and open <a href="http://localhost:7000/">http://localhost:7000/</a>.</p></div>
669
+ <div class="paragraph"><p>The template expanded to something like (only showing the interesting part):</p></div>
670
+ <div class="listingblock">
671
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
672
+ by Lorenzo Bettini
673
+ http://www.lorenzobettini.it
674
+ http://www.gnu.org/software/src-highlite -->
675
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
676
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>Laundry: false<span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
677
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>Wash dishes: false<span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
678
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span></tt></pre></div></div>
679
+ <div class="paragraph"><p>That wasn&#8217;t too bad, huh?</p></div>
680
+ </div>
681
+ <h2 id="_fifth_step_c_like_controller">Fifth Step, C, like Controller</h2>
682
+ <div class="sectionbody">
683
+ <div class="paragraph"><p>The last part of the MVC paradigm is the Controller. As the name indicates it
684
+ gives you control over the interaction between Model and View.</p></div>
685
+ <div class="paragraph"><p>Wouldn&#8217;t it be nice to have a way to add and remove items on our to-do list?
686
+ Editing the model every time would be quite tiresome and problematic to do
687
+ remotely.</p></div>
688
+ <div class="paragraph"><p>Well, come along, I&#8217;ll give you a short intro to the concept of controllers.</p></div>
689
+ <div class="paragraph"><p>In the way MVC is structured, the Controller provides the data in a nice way
690
+ for the View, removing all of the data-preparation and most of the logic from
691
+ the templates. This makes it firstly simple to change the front end of your
692
+ application and secondly provides excellent ways of changing the complete
693
+ Structure of the Model or View independent from each other.</p></div>
694
+ <div class="paragraph"><p>OK, enough of the theory, you will see the benefits in an instant, first of all
695
+ we will implement marking a task as done.</p></div>
696
+ <div class="paragraph"><p>Go on and create the file <em>controller/task.rb</em> with following contents:</p></div>
697
+ <div class="listingblock">
698
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
699
+ by Lorenzo Bettini
700
+ http://www.lorenzobettini.it
701
+ http://www.gnu.org/software/src-highlite -->
702
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Tasks <span style="color: #990000">&lt;</span> Ramaze<span style="color: #990000">::</span>Controller
703
+ map <span style="color: #FF0000">'/'</span>
704
+
705
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> close<span style="color: #990000">(</span>title<span style="color: #990000">)</span>
706
+ task <span style="color: #990000">=</span> Task<span style="color: #990000">[:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">]</span>
707
+ task<span style="color: #990000">.</span>done <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span>
708
+ task<span style="color: #990000">.</span>save
709
+
710
+ redirect_referrer
711
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
712
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
713
+ <div class="paragraph"><p>That does following:</p></div>
714
+ <div class="ulist"><ul>
715
+ <li>
716
+ <p>
717
+ Define a <tt>Tasks</tt> class as a subclass of <tt>Ramaze::Controller</tt>.
718
+ </p>
719
+ </li>
720
+ <li>
721
+ <p>
722
+ Tell Ramaze that a request to <em>/</em> goes to this Controller.
723
+ </p>
724
+ </li>
725
+ <li>
726
+ <p>
727
+ Define a <tt>#close</tt> method that requires a <tt>title</tt> argument.
728
+ </p>
729
+ </li>
730
+ <li>
731
+ <p>
732
+ Query for a task that has the given title.
733
+ </p>
734
+ </li>
735
+ <li>
736
+ <p>
737
+ Set the status of the task to done and store the change to the database.
738
+ </p>
739
+ </li>
740
+ <li>
741
+ <p>
742
+ Redirect the client to where it came from.
743
+ </p>
744
+ </li>
745
+ </ul></div>
746
+ <div class="paragraph"><p>And we add a require to <em>controller/task.rb</em> to our <em>start.rb</em>:</p></div>
747
+ <div class="listingblock">
748
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
749
+ by Lorenzo Bettini
750
+ http://www.lorenzobettini.it
751
+ http://www.gnu.org/software/src-highlite -->
752
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'rubygems'</span>
753
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'ramaze'</span>
754
+
755
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'model/init'</span>
756
+ <span style="font-weight: bold"><span style="color: #000080">require</span></span> <span style="color: #FF0000">'controller/task'</span>
757
+
758
+ Ramaze<span style="color: #990000">.</span>start</tt></pre></div></div>
759
+ <div class="paragraph"><p>Next we will have to modify the <em>view/index.xhtml</em> to contain a link that will
760
+ change the status of a task:</p></div>
761
+ <div class="listingblock">
762
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
763
+ by Lorenzo Bettini
764
+ http://www.lorenzobettini.it
765
+ http://www.gnu.org/software/src-highlite -->
766
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
767
+ &lt;?r Task.each do |task| ?&gt;
768
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>
769
+ #{ h(task.title) }: #{ task.done },
770
+ (#{ anchor('close', 'close', task.title) })
771
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
772
+ &lt;?r end ?&gt;
773
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span></tt></pre></div></div>
774
+ <div class="paragraph"><p>Now we have an additional link next to each task that allows us to set it to
775
+ done.</p></div>
776
+ <div class="paragraph"><p>An even shorter way of writing that line using default aliases, that you will
777
+ encounter in other applications, is:</p></div>
778
+ <div class="listingblock">
779
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
780
+ by Lorenzo Bettini
781
+ http://www.lorenzobettini.it
782
+ http://www.gnu.org/software/src-highlite -->
783
+ <pre><tt>a<span style="color: #990000">(</span><span style="color: #FF0000">'close'</span><span style="color: #990000">,</span> <span style="color: #FF0000">'close'</span><span style="color: #990000">,</span> task<span style="color: #990000">.</span>title<span style="color: #990000">)</span></tt></pre></div></div>
784
+ <div class="paragraph"><p>But for the purpose of this tutorial we&#8217;ll try to be as explicit as possible.</p></div>
785
+ <div class="paragraph"><p>Now that&#8217;s a lot of things at once, but I&#8217;m sure you will be able to keep up,
786
+ the hardest part is behind us.</p></div>
787
+ <div class="paragraph"><p>Don&#8217;t forget to try the new functionality in your browser, wash your dishes and
788
+ do your laundry and come back for the next episode.</p></div>
789
+ </div>
790
+ <h2 id="_sixth_step_clean_rinse_repeat">Sixth Step, Clean, Rinse, Repeat</h2>
791
+ <div class="sectionbody">
792
+ <div class="paragraph"><p>Now that you have closed (and hopefully done) all of your chores, it&#8217;s time to
793
+ open them again, so you won&#8217;t be without work tomorrow.</p></div>
794
+ <div class="paragraph"><p>Let&#8217;s add a method to our Controller that will let us open a closed task:</p></div>
795
+ <div class="listingblock">
796
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
797
+ by Lorenzo Bettini
798
+ http://www.lorenzobettini.it
799
+ http://www.gnu.org/software/src-highlite -->
800
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Tasks <span style="color: #990000">&lt;</span> Ramaze<span style="color: #990000">::</span>Controller
801
+ map <span style="color: #FF0000">'/'</span>
802
+
803
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> close<span style="color: #990000">(</span>title<span style="color: #990000">)</span>
804
+ task <span style="color: #990000">=</span> Task<span style="color: #990000">[:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">]</span>
805
+ task<span style="color: #990000">.</span>done <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span>
806
+ task<span style="color: #990000">.</span>save
807
+
808
+ redirect_referrer
809
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
810
+
811
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> open<span style="color: #990000">(</span>title<span style="color: #990000">)</span>
812
+ task <span style="color: #990000">=</span> Task<span style="color: #990000">[:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">]</span>
813
+ task<span style="color: #990000">.</span>done <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span>
814
+ task<span style="color: #990000">.</span>save
815
+
816
+ redirect_referrer
817
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
818
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
819
+ <div class="paragraph"><p>And add a link to that action:</p></div>
820
+ <div class="listingblock">
821
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
822
+ by Lorenzo Bettini
823
+ http://www.lorenzobettini.it
824
+ http://www.gnu.org/software/src-highlite -->
825
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
826
+ &lt;?r Task.each do |task| ?&gt;
827
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>
828
+ #{ h(task.title) }: #{ task.done },
829
+ (#{ anchor('close', 'close', task.title) })
830
+ (#{ anchor('open', 'open', task.title) })
831
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
832
+ &lt;?r end ?&gt;
833
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span></tt></pre></div></div>
834
+ <div class="paragraph"><p>OK, nothing new here, move along.</p></div>
835
+ <div class="paragraph"><p>Oh, wait!</p></div>
836
+ <div class="paragraph"><p>Rumor has it that some mad Japanese scientist got screwed by his company (they
837
+ produce dishwashers), so he filed a patent for the ultimate dish washing robot
838
+ that will take care of that for you.</p></div>
839
+ <div class="paragraph"><p>Time to get rid of that task once and for all. No more dish washing yay!</p></div>
840
+ <div class="paragraph"><p>A little modification to Controller, using destructive force.</p></div>
841
+ <div class="listingblock">
842
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
843
+ by Lorenzo Bettini
844
+ http://www.lorenzobettini.it
845
+ http://www.gnu.org/software/src-highlite -->
846
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Tasks <span style="color: #990000">&lt;</span> Ramaze<span style="color: #990000">::</span>Controller
847
+ map <span style="color: #FF0000">'/'</span>
848
+
849
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> close<span style="color: #990000">(</span>title<span style="color: #990000">)</span>
850
+ task <span style="color: #990000">=</span> Task<span style="color: #990000">[:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">]</span>
851
+ task<span style="color: #990000">.</span>done <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">true</span></span>
852
+ task<span style="color: #990000">.</span>save
853
+
854
+ redirect_referrer
855
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
856
+
857
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> open<span style="color: #990000">(</span>title<span style="color: #990000">)</span>
858
+ task <span style="color: #990000">=</span> Task<span style="color: #990000">[:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">]</span>
859
+ task<span style="color: #990000">.</span>done <span style="color: #990000">=</span> <span style="font-weight: bold"><span style="color: #0000FF">false</span></span>
860
+ task<span style="color: #990000">.</span>save
861
+
862
+ redirect_referrer
863
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
864
+
865
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> delete<span style="color: #990000">(</span>title<span style="color: #990000">)</span>
866
+ task <span style="color: #990000">=</span> Task<span style="color: #990000">[:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">]</span>
867
+ task<span style="color: #990000">.</span>destroy
868
+
869
+ redirect_referrer
870
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
871
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
872
+ <div class="paragraph"><p>And a link to the <tt>delete</tt> action.</p></div>
873
+ <div class="listingblock">
874
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
875
+ by Lorenzo Bettini
876
+ http://www.lorenzobettini.it
877
+ http://www.gnu.org/software/src-highlite -->
878
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
879
+ &lt;?r Task.each do |task| ?&gt;
880
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>
881
+ #{ h(task.title) }: #{ task.done },
882
+ (#{ anchor('close', 'close', task.title)})
883
+ (#{ anchor('open', 'open', task.title)})
884
+ (#{ anchor('delete', 'delete', task.title)})
885
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
886
+ &lt;?r end ?&gt;
887
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span></tt></pre></div></div>
888
+ <div class="paragraph"><p>And dish-washing begone!</p></div>
889
+ </div>
890
+ <h2 id="_seventh_step_more_tasks">Seventh Step, More Tasks</h2>
891
+ <div class="sectionbody">
892
+ <div class="paragraph"><p>Sure, it would be nice if life was so simple and you only have to do your
893
+ laundry, but that would mean a premature end for this tutorial and an obstacle
894
+ for GTD evangelists (not that they couldn&#8217;t overcome it).</p></div>
895
+ <div class="paragraph"><p>So now you got a smart new robot that washes your dishes, but unfortunately it
896
+ wasn&#8217;t programmed to recharge once in a while and buy soap, no biggie, we can
897
+ do that with little effort, but since reddit takes up all your time you keep
898
+ forgetting about it.</p></div>
899
+ <div class="paragraph"><p>No problem, I say, adding following code to our <em>view/index.xhtml</em> will give us
900
+ a nice little form that we can fill out in the few seconds between proving
901
+ people on the internet wrong.</p></div>
902
+ <div class="listingblock">
903
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
904
+ by Lorenzo Bettini
905
+ http://www.lorenzobettini.it
906
+ http://www.gnu.org/software/src-highlite -->
907
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;form</span></span> <span style="color: #009900">method</span><span style="color: #990000">=</span><span style="color: #FF0000">"post"</span> <span style="color: #009900">action</span><span style="color: #990000">=</span><span style="color: #FF0000">"#{ route('create') }"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>
908
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;fieldset&gt;</span></span>
909
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;legend&gt;</span></span>Add a task by entering a title.<span style="font-weight: bold"><span style="color: #0000FF">&lt;/legend&gt;</span></span>
910
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;label</span></span> <span style="color: #009900">for</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>Task title:<span style="font-weight: bold"><span style="color: #0000FF">&lt;/label&gt;</span></span>
911
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">id</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span> <span style="color: #009900">name</span><span style="color: #990000">=</span><span style="color: #FF0000">"title"</span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"text"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
912
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"submit"</span> <span style="color: #009900">value</span><span style="color: #990000">=</span><span style="color: #FF0000">"Create"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
913
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/fieldset&gt;</span></span>
914
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/form&gt;</span></span></tt></pre></div></div>
915
+ <div class="paragraph"><p>Unfortunately, you see, this references the <tt>create</tt> action, and we have none
916
+ yet. Trying to create a task will result in an error.</p></div>
917
+ <div class="paragraph"><p>So what we have to do is adding one more method to our Controller that will
918
+ take care of actually creating the Task.</p></div>
919
+ <div class="listingblock">
920
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
921
+ by Lorenzo Bettini
922
+ http://www.lorenzobettini.it
923
+ http://www.gnu.org/software/src-highlite -->
924
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
925
+ <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> request<span style="color: #990000">.</span>post? <span style="font-weight: bold"><span style="color: #0000FF">and</span></span> title <span style="color: #990000">=</span> request<span style="color: #990000">[:</span>title<span style="color: #990000">]</span>
926
+ title<span style="color: #990000">.</span>strip!
927
+
928
+ <span style="font-weight: bold"><span style="color: #0000FF">unless</span></span> title<span style="color: #990000">.</span>empty?
929
+ Task<span style="color: #990000">.</span>create <span style="color: #990000">:</span>title <span style="color: #990000">=&gt;</span> title
930
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
931
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
932
+
933
+ redirect route<span style="color: #990000">(</span><span style="color: #FF0000">'/'</span><span style="color: #990000">)</span>
934
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
935
+ <div class="paragraph"><p>What is going on here?</p></div>
936
+ <div class="ulist"><ul>
937
+ <li>
938
+ <p>
939
+ Check whether the request was using the HTTP POST method and actually sent a
940
+ title with it.
941
+ </p>
942
+ </li>
943
+ <li>
944
+ <p>
945
+ Strip all whitespace from beginning and end of the title.
946
+ </p>
947
+ </li>
948
+ <li>
949
+ <p>
950
+ If the title still has something in it we go on and create a task with that
951
+ title.
952
+ </p>
953
+ </li>
954
+ <li>
955
+ <p>
956
+ Redirect back to the <tt>index</tt>
957
+ </p>
958
+ </li>
959
+ </ul></div>
960
+ </div>
961
+ <h2 id="_eighth_step_eep_exceptions">Eighth Step, Eep, Exceptions!</h2>
962
+ <div class="sectionbody">
963
+ <div class="paragraph"><p>So far, so good, but remember, when we defined the schema for <tt>Task</tt> we said we
964
+ really want to have unique titles.</p></div>
965
+ <div class="paragraph"><p>So once you created the task <em>recharge DishBot9000</em> and try to create another
966
+ one with the same title, you will get a nice error:</p></div>
967
+ <div class="literalblock">
968
+ <div class="content">
969
+ <pre><tt>Sequel::DatabaseError: SQLite3::SQLException column title is not unique</tt></pre>
970
+ </div></div>
971
+ <div class="paragraph"><p>OK, programmers ignore warnings and hide errors, let&#8217;s rescue the exception and
972
+ just act as if nothing has happened.</p></div>
973
+ <div class="listingblock">
974
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
975
+ by Lorenzo Bettini
976
+ http://www.lorenzobettini.it
977
+ http://www.gnu.org/software/src-highlite -->
978
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Tasks <span style="color: #990000">&lt;</span> Ramaze<span style="color: #990000">::</span>Controller
979
+ map <span style="color: #FF0000">'/'</span>
980
+
981
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
982
+ <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> request<span style="color: #990000">.</span>post? <span style="font-weight: bold"><span style="color: #0000FF">and</span></span> title <span style="color: #990000">=</span> request<span style="color: #990000">[:</span>title<span style="color: #990000">]</span>
983
+ title<span style="color: #990000">.</span>strip!
984
+
985
+ <span style="font-weight: bold"><span style="color: #0000FF">unless</span></span> title<span style="color: #990000">.</span>empty?
986
+ Task<span style="color: #990000">.</span>create <span style="color: #990000">:</span>title <span style="color: #990000">=&gt;</span> title
987
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
988
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
989
+
990
+ redirect route<span style="color: #990000">(</span><span style="color: #FF0000">'/'</span><span style="color: #990000">)</span>
991
+ <span style="font-weight: bold"><span style="color: #0000FF">rescue</span></span> Sequel<span style="color: #990000">::</span>DatabaseError
992
+ redirect route<span style="color: #990000">(</span><span style="color: #FF0000">'/'</span><span style="color: #990000">)</span>
993
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
994
+
995
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> close<span style="color: #990000">(</span>title<span style="color: #990000">)</span>
996
+ <span style="font-style: italic"><span style="color: #9A1900"># ...</span></span></tt></pre></div></div>
997
+ <div class="paragraph"><p>Easy as pie, we can try to create as many identical tasks as we want, all we
998
+ get is the same old set.</p></div>
999
+ </div>
1000
+ <h2 id="_ninth_step_curing_your_rsi">Ninth Step, Curing your RSI</h2>
1001
+ <div class="sectionbody">
1002
+ <div class="paragraph"><p>Something you might notice is that every time you hit the submit button and you are redirected to <tt>index</tt>, the title you just input is gone.
1003
+ What a waste of our honest effort to create a duplicate task, we all know if we
1004
+ try often enough it will eventually have to work, so let&#8217;s save us some typing.</p></div>
1005
+ <div class="paragraph"><p>In our <em>view/index.xhtml</em> we modify the form input to have a default value:</p></div>
1006
+ <div class="listingblock">
1007
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1008
+ by Lorenzo Bettini
1009
+ http://www.lorenzobettini.it
1010
+ http://www.gnu.org/software/src-highlite -->
1011
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;form</span></span> <span style="color: #009900">method</span><span style="color: #990000">=</span><span style="color: #FF0000">"post"</span> <span style="color: #009900">action</span><span style="color: #990000">=</span><span style="color: #FF0000">"#{ route('create') }"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>
1012
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;fieldset&gt;</span></span>
1013
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;legend&gt;</span></span>Add a task by entering a title.<span style="font-weight: bold"><span style="color: #0000FF">&lt;/legend&gt;</span></span>
1014
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;label</span></span> <span style="color: #009900">for</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>Task title:<span style="font-weight: bold"><span style="color: #0000FF">&lt;/label&gt;</span></span>
1015
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">id</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span> <span style="color: #009900">name</span><span style="color: #990000">=</span><span style="color: #FF0000">"title"</span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"text"</span> <span style="color: #009900">value</span><span style="color: #990000">=</span><span style="color: #FF0000">"#{ @title }"</span><span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1016
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"submit"</span> <span style="color: #009900">value</span><span style="color: #990000">=</span><span style="color: #FF0000">"Create"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1017
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/fieldset&gt;</span></span>
1018
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/form&gt;</span></span></tt></pre></div></div>
1019
+ <div class="paragraph"><p>The <tt>@title</tt> is an instance-variable, those are shared between the Controller
1020
+ and View.
1021
+ We didn&#8217;t set any such variable in the Controller yet, so do it now:</p></div>
1022
+ <div class="listingblock">
1023
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1024
+ by Lorenzo Bettini
1025
+ http://www.lorenzobettini.it
1026
+ http://www.gnu.org/software/src-highlite -->
1027
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Tasks <span style="color: #990000">&lt;</span> Ramaze<span style="color: #990000">::</span>Controller
1028
+ map <span style="color: #FF0000">'/'</span>
1029
+
1030
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> index
1031
+ <span style="color: #009900">@title</span> <span style="color: #990000">=</span> <span style="color: #FF0000">'recharge DishBot9000'</span>
1032
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
1033
+
1034
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
1035
+ <span style="font-style: italic"><span style="color: #9A1900"># ...</span></span></tt></pre></div></div>
1036
+ <div class="paragraph"><p>Yes, that wasn&#8217;t too bad, but is there a way to change the value of the
1037
+ <tt>@title</tt> without editing the source all the time?</p></div>
1038
+ <div class="paragraph"><p>Turns out we have to revisit the <tt>create</tt> method to give us a hint in form of a
1039
+ GET parameter and change <tt>index</tt> to pick it up.</p></div>
1040
+ <div class="listingblock">
1041
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1042
+ by Lorenzo Bettini
1043
+ http://www.lorenzobettini.it
1044
+ http://www.gnu.org/software/src-highlite -->
1045
+ <pre><tt> <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> index
1046
+ <span style="color: #009900">@title</span> <span style="color: #990000">=</span> request<span style="color: #990000">[:</span>title<span style="color: #990000">]</span>
1047
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
1048
+
1049
+ <span style="font-weight: bold"><span style="color: #0000FF">def</span></span> create
1050
+ <span style="font-weight: bold"><span style="color: #0000FF">if</span></span> request<span style="color: #990000">.</span>post? <span style="font-weight: bold"><span style="color: #0000FF">and</span></span> title <span style="color: #990000">=</span> request<span style="color: #990000">[:</span>title<span style="color: #990000">]</span>
1051
+ title<span style="color: #990000">.</span>strip!
1052
+
1053
+ <span style="font-weight: bold"><span style="color: #0000FF">unless</span></span> title<span style="color: #990000">.</span>empty?
1054
+ Task<span style="color: #990000">.</span>create <span style="color: #990000">:</span>title <span style="color: #990000">=&gt;</span> title
1055
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
1056
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span>
1057
+
1058
+ redirect route<span style="color: #990000">(</span><span style="color: #FF0000">'/'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">)</span>
1059
+ <span style="font-weight: bold"><span style="color: #0000FF">rescue</span></span> Sequel<span style="color: #990000">::</span>DatabaseError
1060
+ redirect route<span style="color: #990000">(</span><span style="color: #FF0000">'/'</span><span style="color: #990000">,</span> <span style="color: #990000">:</span>title <span style="color: #990000">=&gt;</span> title<span style="color: #990000">)</span>
1061
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
1062
+ <div class="paragraph"><p>And that&#8217;s it.
1063
+ Endless hours of fun hitting the submit button lie before us!</p></div>
1064
+ </div>
1065
+ <h2 id="_tenth_step_laying_out_a_different_view_of_things">Tenth Step, Laying out a different View of things</h2>
1066
+ <div class="sectionbody">
1067
+ <div class="paragraph"><p>We have one template, it&#8217;s a nice one, but unfortunately we&#8217;ve got ourselves
1068
+ into quite a mess here after creating hundreds of tasks.</p></div>
1069
+ <div class="paragraph"><p>Our way out of this is to provide some visual feedback&#8201;&#8212;&#8201;when a task is done,
1070
+ it&#8217;s gone.
1071
+ Not forever, but at least it will not show up anymore on the <tt>index</tt> action.</p></div>
1072
+ <div class="paragraph"><p>So we filter out all tasks that haven&#8217;t been done yet in the
1073
+ <em>view/index.xhtml</em>:</p></div>
1074
+ <div class="listingblock">
1075
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1076
+ by Lorenzo Bettini
1077
+ http://www.lorenzobettini.it
1078
+ http://www.gnu.org/software/src-highlite -->
1079
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
1080
+ &lt;?r Task.filter(:done =&gt; false).each do |task| ?&gt;
1081
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>
1082
+ # ...</tt></pre></div></div>
1083
+ <div class="paragraph"><p>So off we go and add a new template at <em>view/done.xhtml</em>.</p></div>
1084
+ <div class="listingblock">
1085
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1086
+ by Lorenzo Bettini
1087
+ http://www.lorenzobettini.it
1088
+ http://www.gnu.org/software/src-highlite -->
1089
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">&lt;!DOCTYPE</span></span> <span style="color: #009900">html</span> <span style="color: #009900">PUBLIC</span> <span style="color: #FF0000">"-//W3C//DTD HTML 4.01//EN"</span><span style="font-weight: bold"><span style="color: #000080">&gt;</span></span>
1090
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;html&gt;</span></span>
1091
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;head&gt;</span></span>
1092
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;title&gt;</span></span>TodoList<span style="font-weight: bold"><span style="color: #0000FF">&lt;/title&gt;</span></span>
1093
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;meta</span></span> <span style="color: #009900">http-equiv</span><span style="color: #990000">=</span><span style="color: #FF0000">"content-type"</span> <span style="color: #009900">content</span><span style="color: #990000">=</span><span style="color: #FF0000">"text/html; charset=UTF-8"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1094
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/head&gt;</span></span>
1095
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;body&gt;</span></span>
1096
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;h1&gt;</span></span>TodoList<span style="font-weight: bold"><span style="color: #0000FF">&lt;/h1&gt;</span></span>
1097
+
1098
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;form</span></span> <span style="color: #009900">method</span><span style="color: #990000">=</span><span style="color: #FF0000">"post"</span> <span style="color: #009900">action</span><span style="color: #990000">=</span><span style="color: #FF0000">"#{ route('create') }"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>
1099
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;fieldset&gt;</span></span>
1100
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;legend&gt;</span></span>Add a task by entering a title.<span style="font-weight: bold"><span style="color: #0000FF">&lt;/legend&gt;</span></span>
1101
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;label</span></span> <span style="color: #009900">for</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>Task title:<span style="font-weight: bold"><span style="color: #0000FF">&lt;/label&gt;</span></span>
1102
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">id</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span> <span style="color: #009900">name</span><span style="color: #990000">=</span><span style="color: #FF0000">"title"</span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"text"</span> <span style="color: #009900">value</span><span style="color: #990000">=</span><span style="color: #FF0000">"#{ @title }"</span><span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1103
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"submit"</span> <span style="color: #009900">value</span><span style="color: #990000">=</span><span style="color: #FF0000">"Create"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1104
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/fieldset&gt;</span></span>
1105
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/form&gt;</span></span>
1106
+
1107
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;h2&gt;</span></span>Tasks done<span style="font-weight: bold"><span style="color: #0000FF">&lt;/h2&gt;</span></span>
1108
+
1109
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
1110
+ &lt;?r Task.filter(:done =&gt; true).each do |task| ?&gt;
1111
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>
1112
+ #{ h(task.title) }: #{ task.done },
1113
+ (#{ anchor('open', 'open', task.title) })
1114
+ (#{ anchor('delete', 'delete', task.title) })
1115
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
1116
+ &lt;?r end ?&gt;
1117
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span>
1118
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/body&gt;</span></span>
1119
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/html&gt;</span></span></tt></pre></div></div>
1120
+ <div class="paragraph"><p>Having a déjà vu?</p></div>
1121
+ <div class="paragraph"><p>Yes, me too, must be an error in the matrix.</p></div>
1122
+ <div class="paragraph"><p>If we want one thing from a web-framework, it&#8217;s to spare us writing repetitive
1123
+ code like this (I hope you did copy&amp;paste).</p></div>
1124
+ <div class="paragraph"><p>What we actually wanted to do is <em>sharing</em> the boilerplate around our listing
1125
+ of tasks, that&#8217;s what we call <em>layout</em>.</p></div>
1126
+ <div class="paragraph"><p>Every action can have a layout associated with it, remember that empty <em>layout</em>
1127
+ directory in your application? That&#8217;s exactly where we will put it.</p></div>
1128
+ <div class="listingblock">
1129
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1130
+ by Lorenzo Bettini
1131
+ http://www.lorenzobettini.it
1132
+ http://www.gnu.org/software/src-highlite -->
1133
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">&lt;!DOCTYPE</span></span> <span style="color: #009900">html</span> <span style="color: #009900">PUBLIC</span> <span style="color: #FF0000">"-//W3C//DTD HTML 4.01//EN"</span><span style="font-weight: bold"><span style="color: #000080">&gt;</span></span>
1134
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;html&gt;</span></span>
1135
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;head&gt;</span></span>
1136
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;title&gt;</span></span>TodoList<span style="font-weight: bold"><span style="color: #0000FF">&lt;/title&gt;</span></span>
1137
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;meta</span></span> <span style="color: #009900">http-equiv</span><span style="color: #990000">=</span><span style="color: #FF0000">"content-type"</span> <span style="color: #009900">content</span><span style="color: #990000">=</span><span style="color: #FF0000">"text/html; charset=UTF-8"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1138
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/head&gt;</span></span>
1139
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;body&gt;</span></span>
1140
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;h1&gt;</span></span>TodoList<span style="font-weight: bold"><span style="color: #0000FF">&lt;/h1&gt;</span></span>
1141
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;form</span></span> <span style="color: #009900">method</span><span style="color: #990000">=</span><span style="color: #FF0000">"post"</span> <span style="color: #009900">action</span><span style="color: #990000">=</span><span style="color: #FF0000">"#{ route('create') }"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>
1142
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;fieldset&gt;</span></span>
1143
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;legend&gt;</span></span>Add a task by entering a title.<span style="font-weight: bold"><span style="color: #0000FF">&lt;/legend&gt;</span></span>
1144
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;label</span></span> <span style="color: #009900">for</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span><span style="font-weight: bold"><span style="color: #0000FF">&gt;</span></span>Task title:<span style="font-weight: bold"><span style="color: #0000FF">&lt;/label&gt;</span></span>
1145
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">id</span><span style="color: #990000">=</span><span style="color: #FF0000">"form-title"</span> <span style="color: #009900">name</span><span style="color: #990000">=</span><span style="color: #FF0000">"title"</span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"text"</span> <span style="color: #009900">value</span><span style="color: #990000">=</span><span style="color: #FF0000">"#{ @title }"</span><span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1146
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;input</span></span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"submit"</span> <span style="color: #009900">value</span><span style="color: #990000">=</span><span style="color: #FF0000">"Create"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1147
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/fieldset&gt;</span></span>
1148
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/form&gt;</span></span>
1149
+ #{ @content }
1150
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/body&gt;</span></span>
1151
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/html&gt;</span></span></tt></pre></div></div>
1152
+ <div class="paragraph"><p>And to tell Ramaze which layout to use for our <tt>Tasks</tt> we&#8217;ll have to add a line
1153
+ to the Controller.</p></div>
1154
+ <div class="listingblock">
1155
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1156
+ by Lorenzo Bettini
1157
+ http://www.lorenzobettini.it
1158
+ http://www.gnu.org/software/src-highlite -->
1159
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">class</span></span> Tasks <span style="color: #990000">&lt;</span> Ramaze<span style="color: #990000">::</span>Controller
1160
+ map <span style="color: #FF0000">'/'</span>
1161
+ layout <span style="color: #FF0000">'default'</span>
1162
+ <span style="font-weight: bold"><span style="color: #0000FF">end</span></span></tt></pre></div></div>
1163
+ <div class="paragraph"><p>And finally, since we are fond of valid HTML and just love to get rid of boring
1164
+ boilerplate we can delete the slack from our templates.</p></div>
1165
+ <div class="paragraph"><p><em>view/index.xhtml</em> becomes:</p></div>
1166
+ <div class="listingblock">
1167
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1168
+ by Lorenzo Bettini
1169
+ http://www.lorenzobettini.it
1170
+ http://www.gnu.org/software/src-highlite -->
1171
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;h2&gt;</span></span>Done Tasks<span style="font-weight: bold"><span style="color: #0000FF">&lt;/h2&gt;</span></span>
1172
+
1173
+ #{ anchor('Pending tasks', 'done') }
1174
+
1175
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
1176
+ &lt;?r Task.filter(:done =&gt; false).each do |task| ?&gt;
1177
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>
1178
+ #{ h(task.title) },
1179
+ (#{ anchor('close', 'close', task.title) })
1180
+ (#{ anchor('delete', 'delete', task.title) })
1181
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
1182
+ &lt;?r end ?&gt;
1183
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span></tt></pre></div></div>
1184
+ <div class="paragraph"><p><em>view/done.xhtml</em> becomes:</p></div>
1185
+ <div class="listingblock">
1186
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1187
+ by Lorenzo Bettini
1188
+ http://www.lorenzobettini.it
1189
+ http://www.gnu.org/software/src-highlite -->
1190
+ <pre><tt><span style="font-weight: bold"><span style="color: #0000FF">&lt;h2&gt;</span></span>Pending Tasks<span style="font-weight: bold"><span style="color: #0000FF">&lt;/h2&gt;</span></span>
1191
+
1192
+ #{ anchor('Done tasks', 'done') }
1193
+
1194
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;ul&gt;</span></span>
1195
+ &lt;?r Task.filter(:done =&gt; true).each do |task| ?&gt;
1196
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;li&gt;</span></span>
1197
+ #{ h(task.title) },
1198
+ (#{ anchor('open', 'open', task.title) })
1199
+ (#{ anchor('delete', 'delete', task.title) })
1200
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/li&gt;</span></span>
1201
+ &lt;?r end ?&gt;
1202
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/ul&gt;</span></span></tt></pre></div></div>
1203
+ <div class="paragraph"><p>Well, that&#8217;s so much better, we even included links between the actions.</p></div>
1204
+ </div>
1205
+ <h2 id="_eleventh_step_not_all_that_is_gold_glitters_8230">Eleventh Step, not all that is gold glitters&#8230;</h2>
1206
+ <div class="sectionbody">
1207
+ <div class="paragraph"><p>You have to admit, it&#8217;s a lot of fun having such a sophisticated application,
1208
+ but what good is it if it&#8217;s too ugly to show it even to your closest friends?
1209
+ They will never become addicted enough to your fancy todo-list to actually do
1210
+ all the work for you.</p></div>
1211
+ <div class="paragraph"><p>Let&#8217;s do things with style, with a style-sheet.</p></div>
1212
+ <div class="paragraph"><p>Now is the time to fire up your editor, point it at <em>public/css/screen.css</em> and
1213
+ churn out something of your liking.</p></div>
1214
+ <div class="paragraph"><p>We will not cover this part in the tutorial, an example style-sheet is located
1215
+ in the example todo-list.</p></div>
1216
+ <div class="paragraph"><p>What we do cover is adding it to your application, or the <tt>&lt;head&gt;</tt> in
1217
+ <em>layout/default.xhtml</em> to be exact:</p></div>
1218
+ <div class="listingblock">
1219
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1220
+ by Lorenzo Bettini
1221
+ http://www.lorenzobettini.it
1222
+ http://www.gnu.org/software/src-highlite -->
1223
+ <pre><tt><span style="font-weight: bold"><span style="color: #000080">&lt;!DOCTYPE</span></span> <span style="color: #009900">html</span> <span style="color: #009900">PUBLIC</span> <span style="color: #FF0000">"-//W3C//DTD HTML 4.01//EN"</span><span style="font-weight: bold"><span style="color: #000080">&gt;</span></span>
1224
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;html&gt;</span></span>
1225
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;head&gt;</span></span>
1226
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;title&gt;</span></span>TodoList<span style="font-weight: bold"><span style="color: #0000FF">&lt;/title&gt;</span></span>
1227
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;meta</span></span> <span style="color: #009900">http-equiv</span><span style="color: #990000">=</span><span style="color: #FF0000">"content-type"</span> <span style="color: #009900">content</span><span style="color: #990000">=</span><span style="color: #FF0000">"text/html; charset=UTF-8"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1228
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;link</span></span> <span style="color: #009900">rel</span><span style="color: #990000">=</span><span style="color: #FF0000">"stylesheet"</span> <span style="color: #009900">type</span><span style="color: #990000">=</span><span style="color: #FF0000">"text/css"</span> <span style="color: #009900">href</span><span style="color: #990000">=</span><span style="color: #FF0000">"/css/screen.css"</span> <span style="font-weight: bold"><span style="color: #0000FF">/&gt;</span></span>
1229
+ <span style="font-weight: bold"><span style="color: #0000FF">&lt;/head&gt;</span></span></tt></pre></div></div>
1230
+ <div class="paragraph"><p>Voilà, you now have acquired the Certificate of Ramazeness and all your friends
1231
+ and enemies envy you.</p></div>
1232
+ </div>
1233
+ <h2 id="_twelfth_step_configuring_configurable_configurability">Twelfth Step, configuring configurable configurability</h2>
1234
+ <div class="sectionbody">
1235
+ <div class="paragraph"><p>To round up this tutorial a bit, let&#8217;s introduce you to configuration in Ramaze.
1236
+ There are a number of ways to configure Ramaze, but here we&#8217;ll just see the
1237
+ most common ones with some options you&#8217;ll most likely want to change.</p></div>
1238
+ <div class="paragraph"><p>First of all, you have been running your ramaze application always on the same
1239
+ port, <tt>7000</tt>, which prevents you from starting more than one instance or other
1240
+ applications.</p></div>
1241
+ <div class="paragraph"><p>To change the port, you can, for example:</p></div>
1242
+ <div class="listingblock">
1243
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1244
+ by Lorenzo Bettini
1245
+ http://www.lorenzobettini.it
1246
+ http://www.gnu.org/software/src-highlite -->
1247
+ <pre><tt>Ramaze<span style="color: #990000">.</span>options<span style="color: #990000">.</span>adapter<span style="color: #990000">.</span>port <span style="color: #990000">=</span> <span style="color: #993399">80</span></tt></pre></div></div>
1248
+ <div class="admonitionblock">
1249
+ <table><tr>
1250
+ <td class="icon">
1251
+ <div class="title">Note</div>
1252
+ </td>
1253
+ <td class="content">Running a server on a port below 1024 will require root privileges and is
1254
+ generally not advised for applications that don&#8217;t drop their privileges
1255
+ after establishing a connection.
1256
+ Please have a look at <a href="http://wiki.ramaze.net/Deployment">http://wiki.ramaze.net/Deployment</a> for better ways
1257
+ to deploy your site using a reverse proxy like apache, lighttpd, or
1258
+ nginx.</td>
1259
+ </tr></table>
1260
+ </div>
1261
+ <div class="paragraph"><p>OK, a different port is fine, but how about some speed-boost? For this we will
1262
+ need a faster server like <a href="http://mongrel.rubyforge.org">Mongrel</a> or
1263
+ <a href="http://thin.rubyforge.org">Thin</a>.</p></div>
1264
+ <div class="paragraph"><p>You can install either one via:</p></div>
1265
+ <div class="listingblock">
1266
+ <div class="content">
1267
+ <pre><tt>gem install thin
1268
+ gem install mongrel</tt></pre>
1269
+ </div></div>
1270
+ <div class="paragraph"><p>Now to the configuration:</p></div>
1271
+ <div class="listingblock">
1272
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1273
+ by Lorenzo Bettini
1274
+ http://www.lorenzobettini.it
1275
+ http://www.gnu.org/software/src-highlite -->
1276
+ <pre><tt><span style="font-style: italic"><span style="color: #9A1900"># The default is WEBrick</span></span>
1277
+ Ramaze<span style="color: #990000">.</span>options<span style="color: #990000">.</span>adapter<span style="color: #990000">.</span>adapter <span style="color: #990000">=</span> <span style="color: #990000">:</span>webrick
1278
+
1279
+ <span style="font-style: italic"><span style="color: #9A1900"># How about using Mongrel instead?</span></span>
1280
+ Ramaze<span style="color: #990000">.</span>options<span style="color: #990000">.</span>adapter<span style="color: #990000">.</span>adapter <span style="color: #990000">=</span> <span style="color: #990000">:</span>mongrel
1281
+
1282
+ <span style="font-style: italic"><span style="color: #9A1900"># Or maybe Thin?</span></span>
1283
+ Ramaze<span style="color: #990000">.</span>options<span style="color: #990000">.</span>adapter<span style="color: #990000">.</span>adapter <span style="color: #990000">=</span> <span style="color: #990000">:</span>thin</tt></pre></div></div>
1284
+ <div class="paragraph"><p>For the full performance, switch Ramaze into <tt>:live</tt> mode:</p></div>
1285
+ <div class="listingblock">
1286
+ <div class="content"><!-- Generator: GNU source-highlight 2.11.1
1287
+ by Lorenzo Bettini
1288
+ http://www.lorenzobettini.it
1289
+ http://www.gnu.org/software/src-highlite -->
1290
+ <pre><tt><span style="font-style: italic"><span style="color: #9A1900"># The default is :dev</span></span>
1291
+ Ramaze<span style="color: #990000">.</span>options<span style="color: #990000">.</span>mode <span style="color: #990000">=</span> <span style="color: #990000">:</span>live
1292
+
1293
+ <span style="font-style: italic"><span style="color: #9A1900"># And here comes :live</span></span>
1294
+ Ramaze<span style="color: #990000">.</span>options<span style="color: #990000">.</span>mode <span style="color: #990000">=</span> <span style="color: #990000">:</span>live</tt></pre></div></div>
1295
+ <div class="paragraph"><p>The major differences between <tt>:dev</tt> and <tt>:live</tt> are that in <tt>:live</tt> mode your
1296
+ code won&#8217;t be automatically reloaded if it has changed and we don&#8217;t run every
1297
+ request through <tt>Rack::Lint</tt>, which helps you to stay within the
1298
+ request/response specifications required by Rack.</p></div>
1299
+ </div>
1300
+ <h2 id="glossary">Glossary</h2>
1301
+ <div class="sectionbody">
1302
+ <div class="dlist glossary"><dl>
1303
+ <dt>
1304
+ RDBMS
1305
+ </dt>
1306
+ <dd>
1307
+ <p>
1308
+ Relational Database Management System
1309
+ </p>
1310
+ </dd>
1311
+ <dt>
1312
+ ORM
1313
+ </dt>
1314
+ <dd>
1315
+ <p>
1316
+ Object Relationship Mapper: Maps data into objects and assists in querying
1317
+ and manipulation
1318
+ </p>
1319
+ </dd>
1320
+ <dt>
1321
+ MVC
1322
+ </dt>
1323
+ <dd>
1324
+ <p>
1325
+ Model, View, Controller: one of the patterns traditionally used for GUIs in Smalltalk.
1326
+ </p>
1327
+ </dd>
1328
+ <dt>
1329
+ Etanni
1330
+ </dt>
1331
+ <dd>
1332
+ <p>
1333
+ Innate spelled backwards.
1334
+ </p>
1335
+ </dd>
1336
+ <dt>
1337
+ Innate
1338
+ </dt>
1339
+ <dd>
1340
+ <p>
1341
+ Core of Ramaze.
1342
+ </p>
1343
+ </dd>
1344
+ <dt>
1345
+ Rack
1346
+ </dt>
1347
+ <dd>
1348
+ <p>
1349
+ HTTP abstraction layer and interface used by the majority of Ruby web-frameworks.
1350
+ </p>
1351
+ </dd>
1352
+ <dt>
1353
+ Templating engine
1354
+ </dt>
1355
+ <dd>
1356
+ <p>
1357
+ Used to process so-called templates with inlined source code or instructions
1358
+ to produce dynamic resulting documents. Examples for traditional templating
1359
+ engines are XSLT, SSI, ERB.
1360
+ </p>
1361
+ </dd>
1362
+ <dt>
1363
+ RSI
1364
+ </dt>
1365
+ <dd>
1366
+ <p>
1367
+ Repetive Strain Injury, prevalent among the members of the church of Emacs.
1368
+ </p>
1369
+ </dd>
1370
+ </dl></div>
1371
+ </div>
1372
+ <div id="footer">
1373
+ <div id="footer-text">
1374
+ Version 2.0<br />
1375
+ Last updated 2009-05-10 10:37:49 JST
1376
+ </div>
1377
+ </div>
1378
+ </body>
1379
+ </html>