ramaze 0.1.0 → 0.1.1

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 (195) hide show
  1. data/Rakefile +4 -12
  2. data/bin/ramaze +95 -171
  3. data/doc/CHANGELOG +387 -4
  4. data/doc/README +81 -13
  5. data/doc/meta/announcement.txt +51 -8
  6. data/doc/meta/configuration.txt +17 -34
  7. data/doc/meta/internals.txt +34 -4
  8. data/doc/migrate/1110_to_1111.txt +131 -0
  9. data/doc/readme_chunks/features.txt +81 -12
  10. data/doc/readme_chunks/installing.txt +0 -1
  11. data/doc/tutorial/todolist.html +293 -65
  12. data/doc/tutorial/{todolist.txt → todolist.mkd} +251 -51
  13. data/examples/blog/main.rb +1 -1
  14. data/examples/blog/src/model.rb +0 -1
  15. data/examples/hello.rb +2 -5
  16. data/examples/templates/template/external.haml +5 -5
  17. data/examples/templates/template/external.liquid +1 -1
  18. data/examples/templates/template/external.mab +8 -8
  19. data/examples/templates/template/external.rem +30 -0
  20. data/examples/templates/template/external.rhtml +6 -7
  21. data/examples/templates/template/external.zmr +13 -9
  22. data/examples/templates/template_amrita2.rb +8 -8
  23. data/examples/templates/template_erubis.rb +11 -11
  24. data/examples/templates/template_ezamar.rb +9 -11
  25. data/examples/templates/template_haml.rb +13 -13
  26. data/examples/templates/template_liquid.rb +10 -10
  27. data/examples/templates/template_markaby.rb +13 -10
  28. data/examples/templates/template_remarkably.rb +59 -0
  29. data/examples/todolist/main.rb +1 -7
  30. data/examples/todolist/src/controller/main.rb +26 -13
  31. data/examples/todolist/src/element/page.rb +5 -0
  32. data/examples/whywiki/main.rb +1 -1
  33. data/lib/proto/main.rb +0 -8
  34. data/lib/proto/public/css/ramaze_error.css +12 -4
  35. data/lib/proto/public/error.zmr +6 -25
  36. data/lib/ramaze.rb +35 -245
  37. data/lib/ramaze/action.rb +21 -0
  38. data/lib/ramaze/adapter.rb +94 -29
  39. data/lib/ramaze/adapter/base.rb +57 -0
  40. data/lib/ramaze/adapter/mongrel.rb +12 -19
  41. data/lib/ramaze/adapter/webrick.rb +21 -20
  42. data/lib/ramaze/cache.rb +47 -3
  43. data/lib/ramaze/cache/memcached.rb +22 -0
  44. data/lib/ramaze/cache/yaml_store.rb +19 -0
  45. data/lib/ramaze/controller.rb +47 -271
  46. data/lib/ramaze/controller/error.rb +43 -0
  47. data/lib/ramaze/controller/render.rb +90 -0
  48. data/lib/ramaze/controller/resolve.rb +147 -0
  49. data/lib/ramaze/dispatcher.rb +41 -9
  50. data/lib/ramaze/dispatcher/file.rb +1 -1
  51. data/lib/ramaze/global.rb +73 -158
  52. data/lib/ramaze/global/dsl.rb +29 -0
  53. data/lib/ramaze/global/globalstruct.rb +90 -0
  54. data/lib/ramaze/helper.rb +1 -1
  55. data/lib/ramaze/helper/aspect.rb +39 -179
  56. data/lib/ramaze/helper/cache.rb +8 -9
  57. data/lib/ramaze/helper/cgi.rb +23 -0
  58. data/lib/ramaze/helper/file.rb +3 -0
  59. data/lib/ramaze/helper/inform.rb +3 -0
  60. data/lib/ramaze/helper/link.rb +56 -63
  61. data/lib/ramaze/helper/nitroform.rb +4 -0
  62. data/lib/ramaze/helper/redirect.rb +1 -1
  63. data/lib/ramaze/inform.rb +6 -2
  64. data/lib/ramaze/inform/analogger.rb +5 -1
  65. data/lib/ramaze/inform/hub.rb +1 -1
  66. data/lib/ramaze/inform/informing.rb +7 -0
  67. data/lib/ramaze/snippets/kernel/aquire.rb +2 -0
  68. data/lib/ramaze/snippets/kernel/constant.rb +2 -0
  69. data/lib/ramaze/snippets/kernel/pretty_inspect.rb +2 -0
  70. data/lib/ramaze/snippets/object/traits.rb +4 -0
  71. data/lib/ramaze/snippets/openstruct/temp.rb +3 -0
  72. data/lib/ramaze/snippets/string/DIVIDE.rb +2 -0
  73. data/lib/ramaze/snippets/string/camel_case.rb +2 -0
  74. data/lib/ramaze/snippets/string/color.rb +2 -0
  75. data/lib/ramaze/snippets/string/each.rb +2 -0
  76. data/lib/ramaze/snippets/string/snake_case.rb +3 -0
  77. data/lib/ramaze/snippets/struct/fill.rb +8 -2
  78. data/lib/ramaze/snippets/struct/values_at.rb +16 -0
  79. data/lib/ramaze/snippets/symbol/to_proc.rb +3 -0
  80. data/lib/ramaze/sourcereload.rb +89 -0
  81. data/lib/ramaze/template.rb +21 -12
  82. data/lib/ramaze/template/amrita2.rb +6 -6
  83. data/lib/ramaze/template/erubis.rb +4 -9
  84. data/lib/ramaze/template/ezamar.rb +13 -57
  85. data/lib/ramaze/template/ezamar/element.rb +10 -12
  86. data/lib/ramaze/template/ezamar/engine.rb +40 -101
  87. data/lib/ramaze/template/ezamar/morpher.rb +3 -3
  88. data/lib/ramaze/template/haml.rb +3 -6
  89. data/lib/ramaze/template/liquid.rb +4 -9
  90. data/lib/ramaze/template/markaby.rb +16 -22
  91. data/lib/ramaze/template/remarkably.rb +28 -0
  92. data/lib/ramaze/tool/mime.rb +2 -0
  93. data/lib/ramaze/tool/record.rb +6 -0
  94. data/lib/ramaze/trinity/request.rb +44 -54
  95. data/lib/ramaze/trinity/response.rb +1 -1
  96. data/lib/ramaze/trinity/session.rb +15 -37
  97. data/lib/ramaze/version.rb +1 -1
  98. data/rake_tasks/gem.rake +2 -2
  99. data/rake_tasks/maintaince.rake +42 -1
  100. data/rake_tasks/spec.rake +45 -0
  101. data/spec/examples/caching.rb +1 -1
  102. data/spec/examples/simple.rb +1 -1
  103. data/spec/examples/templates/template_amrita2.rb +1 -0
  104. data/spec/examples/templates/template_erubis.rb +2 -1
  105. data/spec/examples/templates/template_ezamar.rb +1 -1
  106. data/spec/examples/templates/template_haml.rb +2 -1
  107. data/spec/examples/templates/template_liquid.rb +2 -1
  108. data/spec/examples/templates/template_markaby.rb +2 -1
  109. data/spec/examples/templates/template_remarkably.rb +22 -0
  110. data/spec/examples/todolist.rb +125 -0
  111. data/spec/helper.rb +2 -23
  112. data/spec/helper/minimal.rb +20 -0
  113. data/spec/helper/mock_http.rb +24 -30
  114. data/spec/helper/simple_http.rb +2 -2
  115. data/spec/helper/wrap.rb +6 -9
  116. data/spec/ramaze/adapter.rb +1 -1
  117. data/spec/ramaze/adapter/record.rb +31 -0
  118. data/spec/ramaze/cache.rb +41 -54
  119. data/spec/ramaze/controller.rb +121 -137
  120. data/spec/ramaze/controller/template/list.xhtml +1 -0
  121. data/spec/ramaze/controller/template/other/greet/other.xhtml +1 -0
  122. data/spec/ramaze/controller/template_resolving.rb +27 -3
  123. data/spec/ramaze/element.rb +11 -7
  124. data/spec/ramaze/error.rb +1 -1
  125. data/spec/ramaze/gestalt.rb +2 -0
  126. data/spec/ramaze/helper/aspect.rb +30 -21
  127. data/spec/ramaze/helper/auth.rb +1 -1
  128. data/spec/ramaze/helper/cache.rb +2 -1
  129. data/spec/ramaze/helper/form.rb +14 -11
  130. data/spec/ramaze/helper/link.rb +18 -41
  131. data/spec/ramaze/localize.rb +29 -2
  132. data/spec/ramaze/morpher.rb +23 -12
  133. data/spec/ramaze/params.rb +46 -24
  134. data/spec/ramaze/request.rb +6 -2
  135. data/spec/ramaze/store/yaml.rb +5 -0
  136. data/spec/ramaze/template.rb +22 -27
  137. data/spec/ramaze/template/amrita2.rb +1 -2
  138. data/spec/ramaze/template/erubis.rb +1 -1
  139. data/spec/ramaze/template/ezamar.rb +1 -2
  140. data/spec/ramaze/template/haml.rb +2 -2
  141. data/spec/ramaze/template/haml/with_vars.haml +1 -1
  142. data/spec/ramaze/template/liquid.rb +1 -1
  143. data/spec/ramaze/template/markaby.rb +1 -1
  144. data/spec/ramaze/template/remarkably.rb +56 -0
  145. data/spec/ramaze/template/remarkably/external.rem +8 -0
  146. data/spec/ramaze/template/remarkably/sum.rem +1 -0
  147. metadata +38 -63
  148. data/doc/README.html +0 -637
  149. data/doc/allison/LICENSE +0 -184
  150. data/doc/allison/README +0 -37
  151. data/doc/allison/allison.css +0 -299
  152. data/doc/allison/allison.gif +0 -0
  153. data/doc/allison/allison.js +0 -307
  154. data/doc/allison/allison.rb +0 -287
  155. data/doc/allison/cache/BODY +0 -588
  156. data/doc/allison/cache/CLASS_INDEX +0 -4
  157. data/doc/allison/cache/CLASS_PAGE +0 -1
  158. data/doc/allison/cache/FILE_INDEX +0 -4
  159. data/doc/allison/cache/FILE_PAGE +0 -1
  160. data/doc/allison/cache/FONTS +0 -1
  161. data/doc/allison/cache/FR_INDEX_BODY +0 -1
  162. data/doc/allison/cache/IMGPATH +0 -1
  163. data/doc/allison/cache/INDEX +0 -1
  164. data/doc/allison/cache/JAVASCRIPT +0 -307
  165. data/doc/allison/cache/METHOD_INDEX +0 -4
  166. data/doc/allison/cache/METHOD_LIST +0 -1
  167. data/doc/allison/cache/SRC_PAGE +0 -1
  168. data/doc/allison/cache/STYLE +0 -321
  169. data/doc/allison/cache/URL +0 -1
  170. data/doc/changes.txt +0 -3375
  171. data/doc/changes.xml +0 -3378
  172. data/examples/todolist/conf/benchmark.yaml +0 -35
  173. data/examples/todolist/conf/debug.yaml +0 -34
  174. data/examples/todolist/conf/live.yaml +0 -33
  175. data/examples/todolist/conf/silent.yaml +0 -31
  176. data/examples/todolist/conf/stage.yaml +0 -33
  177. data/examples/todolist/public/css/coderay.css +0 -105
  178. data/examples/todolist/public/css/ramaze_error.css +0 -42
  179. data/lib/proto/conf/benchmark.yaml +0 -21
  180. data/lib/proto/conf/debug.yaml +0 -21
  181. data/lib/proto/conf/live.yaml +0 -21
  182. data/lib/proto/conf/silent.yaml +0 -21
  183. data/lib/proto/conf/stage.yaml +0 -21
  184. data/lib/proto/public/css/coderay.css +0 -105
  185. data/lib/ramaze/http_status.rb +0 -66
  186. data/lib/ramaze/snippets/hash/keys_to_sym.rb +0 -19
  187. data/lib/ramaze/snippets/kernel/method.rb +0 -26
  188. data/lib/ramaze/snippets/method/name.rb +0 -22
  189. data/lib/ramaze/snippets/ramaze/autoreload.rb +0 -135
  190. data/lib/ramaze/snippets/rdoc/usage_no_exit.rb +0 -65
  191. data/spec/all.rb +0 -32
  192. data/spec/ramaze/conf/locale_de.yaml +0 -6
  193. data/spec/ramaze/conf/locale_en.yaml +0 -6
  194. data/spec/ramaze/dependencies.rb +0 -16
  195. data/spec/ramaze/global.rb +0 -44
@@ -22,6 +22,11 @@ Ramaze offers following features at the moment:
22
22
  CGI is the Common Gateway Interface and is one of the most basic ways
23
23
  to integrate into Webservers like Apache, Lighttpd or Nginx.
24
24
 
25
+ * FCGI
26
+
27
+ Improvment of CGI as it doesn't start up a new connection to Ramaze on
28
+ every request.
29
+
25
30
 
26
31
  * Templates
27
32
  * [Amrita2](http://amrita2.rubyforge.org/)
@@ -42,13 +47,18 @@ Ramaze offers following features at the moment:
42
47
  Liquid's syntax and parse model are inspired by Django templates, as well
43
48
  as PHP's smarty.
44
49
 
50
+ * [Remarkably](http://rubyforge.org/projects/remarkably)
51
+
52
+ Remarkably is a very tiny Markaby-like XML builder
53
+
45
54
  * [Markaby](http://code.whytheluckystiff.net/markaby/)
46
55
 
47
56
  Markaby means Markup as Ruby.
48
57
 
49
58
  * Ezamar
50
59
 
51
- A simple homage to [Nitro](http://nitroproject.org)s templating.
60
+ A simple homage to [Nitro](http://nitroproject.org)s templating, is shipped
61
+ together with Ramaze.
52
62
 
53
63
  * Cache
54
64
  * Hash
@@ -56,19 +66,78 @@ Ramaze offers following features at the moment:
56
66
  * MemCache
57
67
 
58
68
  * Helper
59
- * Aspect
60
- * Auth
61
- * Cache
62
- * Feed
63
- * Flash
64
- * Form
65
- * Link
66
- * OpenID
67
- * Redirect
68
- * Stack
69
+ * Active by default
70
+ * CGI
71
+
72
+ Shortcuts for escape/unescape of the CGI module.
73
+
74
+ * File
75
+
76
+ Helps you serving files from your Controller.
77
+
78
+ * Flash
79
+
80
+ Store a couple of values for one request associated with a session.
81
+
82
+ * Link
83
+
84
+ Easier linking to the various parts of your applications Controllers and
85
+ Actions.
86
+
87
+ * Redirect
88
+
89
+ Easy redirection.
90
+
91
+ * Optional
92
+ * Aspect
93
+
94
+ Allows you to wrap different Actions on your Controller with code.
95
+
96
+ * Auth
97
+
98
+ Simple way to add basic authentication.
99
+
100
+ * Cache
101
+
102
+ Easy caching Actions and values.
103
+
104
+ * Feed
105
+
106
+ Programmatically generate feeds from any Class.
107
+
108
+ * Form
109
+
110
+ In development, help appreciated.
111
+
112
+ * Identity
113
+
114
+ For ease of use of the OpenID authentication mechanism.
115
+
116
+ * Inform
117
+
118
+ Wrapping the functionality of Ramazes logging facilities.
119
+
120
+ * Markaby
121
+
122
+ Allows you to use Markaby in your Controller without having it as the
123
+ default templating engine.
124
+
125
+ * Nitroform
126
+
127
+ Hooks up on nitros form builder to help you creating forms from Og
128
+ objects.
129
+
130
+ * OpenID
131
+
132
+ Authentication via OpenID made easy.
133
+
134
+ * Stack
135
+
136
+ Allows you to use a call/answer mechanism for things like redirection to the
137
+ site a user entered login-forms from.
69
138
 
70
139
  * Various
71
140
  * Sessions
72
141
  * Global configuration system
73
142
  * Simple request/response handling
74
- * Custom Error-handling
143
+ * Custom sophisticated Error-handling
@@ -5,7 +5,6 @@
5
5
  $ gem install ramaze
6
6
 
7
7
  in case you have RubyGems installed.
8
- (this will work as soon as I have registered on RubyForge ;)
9
8
 
10
9
 
11
10
  * via darcs
@@ -22,7 +22,30 @@
22
22
  <meta content="text/html; charset=UTF-8" http-equiv="content-type" />
23
23
  </head>
24
24
  <body>
25
- <h1>To-do List Tutorial</h1>
25
+
26
+ <h1>To-do List Tutorial</h1>
27
+
28
+ <div class="menu">
29
+ <h3>Table of Contents</h3>
30
+ <li>
31
+ <ol><a href="#Step_Zero,_Introduction">Step Zero, Introduction</a></ol>
32
+ <ol><a href="#First_Step,_Create">First Step, Create</a></ol>
33
+ <ol><a href="#Second_Step,_M,_like_Model">Second Step, M, like Model</a></ol>
34
+ <ol><a href="#Third_Step,_V,_like_View">Third Step, V, like View</a></ol>
35
+ <ol><a href="#Fourth_Step,_C,_like_Controller">Fourth Step, C, like Controller</a></ol>
36
+ <ol><a href="#Fifth_Step,_getting_dynamic">Fifth Step, getting dynamic</a></ol>
37
+ <ol><a href="#Sixth_Step,_open_and_close_tasks">Sixth Step, open and close tasks</a></ol>
38
+ <ol><a href="#Seventh_Step,_delete_tasks">Seventh Step, delete tasks</a></ol>
39
+ <ol><a href="#Eighth_Step,_Elements">Eighth Step, Elements</a></ol>
40
+ <ol><a href="#Ninth_Step,_Prettify">Ninth Step, Prettify</a></ol>
41
+ <ol><a href="#Tenth_Step,_Configuration">Tenth Step, Configuration</a></ol>
42
+ <ol><a href="#Eleventh_Step,_Refactor_with_AspectHelper">Eleventh Step, Refactor with AspectHelper</a></ol>
43
+ <ol><a href="#Twelfth_Step,_Validation_and_Errors">Twelfth Step, Validation and Errors</a></ol>
44
+ </li>
45
+ </div>
46
+
47
+
48
+ <a name="Step_Zero,_Introduction"><h2>Step Zero, Introduction</h2></a>
26
49
 
27
50
  <p>Welcome to our official tutorial, the mandatory to-do list.
28
51
  I'm writing this while doing the steps to assure it will work for you.</p>
@@ -44,10 +67,15 @@ drop by on IRC ( irc.freenode.org channel: #ramaze ).</p>
44
67
  what is going on with little effort, it is also located on the project-page at
45
68
  RubyForge.</p>
46
69
 
70
+ <p>Additionally, we now have added tests for the resulting application that you
71
+ can find in spec/examples/todolist.rb</p>
72
+
73
+ <p>Date of last update: Thu May 24 20:53:49 JST 2007</p>
74
+
47
75
  <p>Thanks in advance.
48
76
  The author of the tutorial, Michael 'manveru' Fellinger</p>
49
77
 
50
- <h2>First Step, Create</h2>
78
+ <a name="First_Step,_Create"><h2>First Step, Create</h2></a>
51
79
 
52
80
  <p>We are using <code>ramaze --create todolist</code> to create a new application.
53
81
  Ramaze will then create the directory and fill it with a skeleton of a quite
@@ -61,21 +89,13 @@ to-do list.</p>
61
89
 
62
90
  <p>done.</p>
63
91
 
64
- <h2>Second Step, M, like Model</h2>
92
+ <a name="Second_Step,_M,_like_Model"><h2>Second Step, M, like Model</h2></a>
65
93
 
66
94
  <p>Ramaze comes at the moment only with a simple wrapper of the YAML::Store.
67
95
  So we are going to base this on the tools available, you can just do the same
68
- with your ORM or database of choice.</p>
69
-
70
- <p>So first, edit the <code>src/model.rb</code>, it is filled with the definition of a simple
71
- YAML::Store already, so we are just gonna modify it a bit to use our wrapper.</p>
72
-
73
- <p>Instead of 'yaml/store' use:</p>
96
+ with your ORM or database-library of choice.</p>
74
97
 
75
- <pre><code>require 'ramaze/store/default'
76
- </code></pre>
77
-
78
- <p>And further:</p>
98
+ <p>So first, edit the <code>src/model.rb</code> to fit better into our application:</p>
79
99
 
80
100
  <pre><code>TodoList = Store::Default.new 'todolist.yaml'
81
101
  </code></pre>
@@ -86,12 +106,12 @@ YAML::Store already, so we are just gonna modify it a bit to use our wrapper.</p
86
106
  'Laundry' =&gt; {:done =&gt; false},
87
107
  'Wash dishes' =&gt; {:done =&gt; false},
88
108
 
89
- }.each do |title, parameters|
90
- TodoList[title] = parameters
109
+ }.each do |title, value|
110
+ TodoList[title] = value
91
111
  end
92
112
  </code></pre>
93
113
 
94
- <h2>Third Step, V, like View</h2>
114
+ <a name="Third_Step,_V,_like_View"><h2>Third Step, V, like View</h2></a>
95
115
 
96
116
  <p>Now let's get our hands dirty and just edit the templates for our to-do list.</p>
97
117
 
@@ -109,8 +129,8 @@ simple.</p>
109
129
  &lt;h1&gt;TodoList&lt;/h1&gt;
110
130
  &lt;ul&gt;
111
131
  &lt;?r
112
- TodoList.each do |title, parameters|
113
- status = parameters[:done] ? 'done' : 'not done'
132
+ TodoList.each do |title, value|
133
+ status = value[:done] ? 'done' : 'not done'
114
134
  ?&gt;
115
135
  &lt;li&gt;#{title}: #{status}&lt;/li&gt;
116
136
  &lt;?r end ?&gt;
@@ -122,10 +142,10 @@ simple.</p>
122
142
  <p>I will assume that you are familiar with basic Ruby already, so let's
123
143
  concentrate on the things new here.</p>
124
144
 
125
- <p><?r ?> defines an area of ruby-code. Late when the template is transformed into
145
+ <p><code>&lt;?r ?&gt;</code> defines an area of ruby-code. Late when the template is transformed into
126
146
  pure Ruby it will be evaluated. We iterate over the TodoList model and pass the
127
- title and parameters into a block. In that block we can just get the values
128
- of title and status (which we define based on the parameters) displayed on the
147
+ title and value into a block. In that block we can just get the values
148
+ of title and status (which we define based on the value) displayed on the
129
149
  page.</p>
130
150
 
131
151
  <p>The whole Template would expand to something like this (only showing the
@@ -151,7 +171,7 @@ now access it by browsing to http://localhost:7000/</p>
151
171
  <code>ramaze -p 7070</code> or similar. Also be sure to look at the output of
152
172
  <code>ramaze --help</code> to see some other options.</p>
153
173
 
154
- <h2>Fourth Step, C, like Controller</h2>
174
+ <a name="Fourth_Step,_C,_like_Controller"><h2>Fourth Step, C, like Controller</h2></a>
155
175
 
156
176
  <p>The last part of the MVC-paradigm is the Controller.</p>
157
177
 
@@ -162,7 +182,7 @@ Editing the model every time would be quite tiresome and limited.</p>
162
182
 
163
183
  <p>In the way MVC is structured, the Controller provides the data in a nice way
164
184
  for the View, removing all of the data-preparation and most of the logic from
165
- the templates. This makes it firstly simple to change the fronted of your
185
+ the templates. This makes it firstly simple to change the front end of your
166
186
  application and secondly provides excellent ways of changing the complete
167
187
  Structure of the Model or View independent from each other.</p>
168
188
 
@@ -178,17 +198,17 @@ edit the file <code>src/controller/main.rb</code>.</p>
178
198
  end
179
199
  </code></pre>
180
200
 
181
- <p>The only method right now is #index, with a simple and for the moment quite
201
+ <p>The only method right now is <code>#index</code>, with a simple and for the moment quite
182
202
  useless "Hello, World". The relationship between the methods on the controller
183
- and the templates is 1:1, so the method #index is combined with the template
203
+ and the templates is 1:1, so the method <code>#index</code> is combined with the template
184
204
  <code>index.xhtml</code>. This combination is called an <code>action</code>.</p>
185
205
 
186
206
  <p>Let's get back to editing and change the index-method to this:</p>
187
207
 
188
208
  <pre><code>def index
189
209
  @tasks = TodoList.content
190
- @tasks.each do |title, parameters|
191
- status = parameters[:done] ? 'done' : 'not done'
210
+ @tasks.each do |title, value|
211
+ status = value[:done] ? 'done' : 'not done'
192
212
  @tasks[title] = status
193
213
  end
194
214
  end
@@ -203,7 +223,6 @@ changed to do following:</p>
203
223
  &lt;/head&gt;
204
224
  &lt;body&gt;
205
225
  &lt;h1&gt;TodoList&lt;/h1&gt;
206
- &lt;a href="/new"&gt;New Task&lt;/a&gt;
207
226
  &lt;?r if @tasks.empty? ?&gt;
208
227
  No Tasks
209
228
  &lt;?r else ?&gt;
@@ -230,7 +249,7 @@ Tasks it will say so.</p>
230
249
  <li>The return-value of the Controller does not matter (in this case).</li>
231
250
  </ul>
232
251
 
233
- <h2>Fifth Step, getting dynamic</h2>
252
+ <a name="Fifth_Step,_getting_dynamic"><h2>Fifth Step, getting dynamic</h2></a>
234
253
 
235
254
  <p>We set out to build the ultimate to-do list, but there are still some things
236
255
  missing. First off, we want to add new tasks, so let's get that done.</p>
@@ -252,7 +271,7 @@ missing. First off, we want to add new tasks, so let's get that done.</p>
252
271
  &lt;a href="/"&gt;Back to TodoList&lt;/a&gt;
253
272
  &lt;form method="POST" action="create"&gt;
254
273
  Task: &lt;input type="text" name="title" /&gt;&lt;br /&gt;
255
- &lt;inpyt type="submit" /&gt;
274
+ &lt;input type="submit" /&gt;
256
275
  &lt;/form&gt;
257
276
  &lt;/body&gt;
258
277
  &lt;/html&gt;
@@ -274,25 +293,25 @@ moment, the request and response and the contents of the session. This is very
274
293
  useful for debugging and development, you can provide your own set of
275
294
  error-pages before going into production (or deactivate them fully) though.</p>
276
295
 
277
- <p>OK, let's implement the action for #create, all we want to do is take the
296
+ <p>OK, let's implement the action for <code>#create</code>, all we want to do is take the
278
297
  requests parameters and create a new task for it, this looks like following on
279
298
  your MainController.</p>
280
299
 
281
300
  <pre><code>def create
282
301
  title = request['title']
283
302
  TodoList[title] = {:done =&gt; false}
284
- redirect R(self)
303
+ redirect Rs()
285
304
  end
286
305
  </code></pre>
287
306
 
288
307
  <p>That's all folks!</p>
289
308
 
290
- <p>we get the title from the request-object, put it into our TodoList as undone
309
+ <p>We get the title from the request-object, put it into our TodoList as undone
291
310
  and redirect back to the mapping of the current Controller ('/' in this case).</p>
292
311
 
293
312
  <p>Now you can create as many tasks as you want, please don't get overworked ;)</p>
294
313
 
295
- <h2>Sixth Step, open and close tasks</h2>
314
+ <a name="Sixth_Step,_open_and_close_tasks"><h2>Sixth Step, open and close tasks</h2></a>
296
315
 
297
316
  <p>Since the nature of tasks is to be done eventually
298
317
  we will need some way to mark it as done or open tasks again.</p>
@@ -301,7 +320,7 @@ we will need some way to mark it as done or open tasks again.</p>
301
320
 
302
321
  <pre><code>&lt;?r @tasks.each do |title, status, toggle| ?&gt;
303
322
  &lt;li&gt;
304
- #{title}: #{status} - #{toggle}
323
+ #{title}: #{status} - [ #{toggle} ]
305
324
  &lt;/li&gt;
306
325
  &lt;?r end ?&gt;
307
326
  </code></pre>
@@ -312,13 +331,13 @@ we go and change the index method on the controller once again:</p>
312
331
 
313
332
  <pre><code>def index
314
333
  @tasks = []
315
- TodoList.original.each do |title, parameters|
316
- if parameters[:done]
334
+ TodoList.original.each do |title, value|
335
+ if value[:done]
317
336
  status = 'done'
318
- toggle = link( R( self, :open, CGI.escape(title) ), :title =&gt; 'Open Task' )
337
+ toggle = A('Open Task', :href =&gt; Rs(:open, title))
319
338
  else
320
339
  status = 'not done'
321
- toggle = link( R( self, :close, CGI.escape(title) ), :title =&gt; 'Close Task' )
340
+ toggle = A('Close Task', :href =&gt; Rs(:close, title))
322
341
  end
323
342
  @tasks &lt;&lt; [title, status, toggle]
324
343
  end
@@ -329,13 +348,13 @@ end
329
348
  <p>Wow, quite some new stuff here. Let me explain that in detail.</p>
330
349
 
331
350
  <p>We first decide whether a task is done or not, then go on and provide a link to
332
- toggle the status, link and R are both methods that help you do that.
333
- the result will be something like:</p>
351
+ toggle the status, A and Rs are both methods that help you do that.
352
+ The result will be something like:</p>
334
353
 
335
354
  <pre><code>&lt;a href="/open/Wash+dishes"&gt;Close Task&lt;/a&gt;
336
355
  </code></pre>
337
356
 
338
- <p>R actually is responsible to build the links href, for more information please
357
+ <p>Rs actually is responsible to build the links href, for more information please
339
358
  take a look at the RDoc for LinkHelper.</p>
340
359
 
341
360
  <p>Also, you might have noticed that the tasks were changing order on every reload,
@@ -358,12 +377,12 @@ corresponding methods to the Controller:</p>
358
377
 
359
378
  <pre><code>def open title
360
379
  task_status title, false
361
- redirect R(self)
380
+ redirect Rs()
362
381
  end
363
382
 
364
383
  def close title
365
384
  task_status title, true
366
- redirect R(self)
385
+ redirect Rs()
367
386
  end
368
387
 
369
388
  private
@@ -376,9 +395,9 @@ end
376
395
  </code></pre>
377
396
 
378
397
  <p>Oh, now what have we got here?
379
- private declares that methods from here on are only to be used within the
380
- Controller itself, we define an #task_status method that takes the title and
381
- status to be set so we don't have to repeat that code in <em>#open</em> and <em>#close</em>
398
+ <code>private</code> declares that methods from here on are only to be used within the
399
+ Controller itself, we define an <code>#task_status</code> method that takes the title and
400
+ status to be set so we don't have to repeat that code in <code>#open</code> and <code>#close</code>
382
401
  and follow the DRY (Don't repeat yourself) paradigm.</p>
383
402
 
384
403
  <p>Another thing we have not encountered so far is that you can define your public
@@ -392,11 +411,11 @@ methods to take parameters on their own, they will be calculated from requests.<
392
411
  <pre><code>open('Wash dishes')
393
412
  </code></pre>
394
413
 
395
- <p>Which in turn will call task_status('Wash dishes', false)</p>
414
+ <p>Which in turn will call <code>task_status('Wash dishes', false)</code></p>
396
415
 
397
416
  <p>That's it, go on and try it :)</p>
398
417
 
399
- <h2>Seventh Step, delete tasks</h2>
418
+ <a name="Seventh_Step,_delete_tasks"><h2>Seventh Step, delete tasks</h2></a>
400
419
 
401
420
  <p>Well, creating, opening and closing work now, one of the things you will
402
421
  consider is to delete a task permanently.</p>
@@ -404,7 +423,7 @@ consider is to delete a task permanently.</p>
404
423
  <p>This is just two little changes away, so let's add the link for deletion in our
405
424
  Controller:</p>
406
425
 
407
- <pre><code>delete = link( R( self, :delete, CGI.escape(title) ), :title =&gt; 'Delete' )
426
+ <pre><code>delete = A('Delete', :href =&gt; Rs(:delete, title))
408
427
  @tasks &lt;&lt; [title, status, toggle, delete]
409
428
  </code></pre>
410
429
 
@@ -412,7 +431,7 @@ Controller:</p>
412
431
 
413
432
  <pre><code>def delete title
414
433
  TodoList.delete title
415
- redirect R(self)
434
+ redirect Rs()
416
435
  end
417
436
  </code></pre>
418
437
 
@@ -431,13 +450,13 @@ section will contact you within the next few days.</p>
431
450
  <p>Just kidding, but that really are the basics, in the next few steps I will
432
451
  explain some more advanced concepts of Ramaze and the templating.</p>
433
452
 
434
- <h2>Eighth Step, Elements</h2>
453
+ <a name="Eighth_Step,_Elements"><h2>Eighth Step, Elements</h2></a>
435
454
 
436
455
  <pre><code>&lt;Page&gt;&lt;/Page&gt;
437
456
  </code></pre>
438
457
 
439
458
  <p>This is called an Element, Ramaze will go and search for a class that matches
440
- the name Page and responds to <em>#render</em>. Then it will go and hand the content in
459
+ the name Page and responds to <code>#render</code>. Then it will go and hand the content in
441
460
  between to that Element.</p>
442
461
 
443
462
  <p>Sounds weird?</p>
@@ -468,7 +487,7 @@ awful lot of sense to change the enclosing stuff in one place.</p>
468
487
 
469
488
  <p>Take a look at the <code>src/element/page.rb</code></p>
470
489
 
471
- <pre><code>class Page &lt; Element
490
+ <pre><code>class Page &lt; Ezamar::Element
472
491
  def render
473
492
  %{
474
493
  &lt;html&gt;
@@ -485,13 +504,13 @@ end
485
504
  </code></pre>
486
505
 
487
506
  <p>Alright, most things we need are in place already, the most important thing
488
- is the <em>#content</em> method that we call with <em>#{content}</em> inside the string in
489
- <em>#render</em>.</p>
507
+ is the <code>#content</code> method that we call with <code>#{content}</code> inside the string in
508
+ <code>#render</code>.</p>
490
509
 
491
510
  <p>Just adopt it to your liking, I'll just use the things we had in our templates
492
511
  so far:</p>
493
512
 
494
- <pre><code>class Page &lt; Element
513
+ <pre><code>class Page &lt; Ezamar::Element
495
514
  def render
496
515
  %{
497
516
  &lt;html&gt;
@@ -499,7 +518,7 @@ so far:</p>
499
518
  &lt;title&gt;TodoList&lt;/title&gt;
500
519
  &lt;/head&gt;
501
520
  &lt;body&gt;
502
- &lt;h1&gt;#{@hash['title']}&lt;/h1&gt;
521
+ &lt;h1&gt;#{@title}&lt;/h1&gt;
503
522
  #{content}
504
523
  &lt;/body&gt;
505
524
  &lt;/html&gt;
@@ -508,8 +527,7 @@ so far:</p>
508
527
  end
509
528
  </code></pre>
510
529
 
511
- <p>Please note that the @hash is filled with the things you pass as parameters
512
- to tye Page-tag.</p>
530
+ <p>Please note that instance variables reflecting the parameters are set.</p>
513
531
 
514
532
  <p>And let's change our templates as well.</p>
515
533
 
@@ -545,9 +563,10 @@ to tye Page-tag.</p>
545
563
  <p>Alright, now just go and look at the result in the browser, try changing
546
564
  the things inside the Element and look at how it behaves.</p>
547
565
 
548
- <h2>Ninth Step, Prettify</h2>
566
+ <a name="Ninth_Step,_Prettify"><h2>Ninth Step, Prettify</h2></a>
549
567
 
550
- <p>Let's structure the data inside the list a little bit, in this case into a table to get it line up properly and look actually structured.</p>
568
+ <p>Let's structure the data inside the list a little bit, in this case into a table
569
+ to get it line up properly and look actually structured.</p>
551
570
 
552
571
  <p>So, from what we have right now:</p>
553
572
 
@@ -574,7 +593,8 @@ the things inside the Element and look at how it behaves.</p>
574
593
  &lt;/table&gt;
575
594
  </code></pre>
576
595
 
577
- <p>And, since we have proper classes to address some style sheets, jump into the Page element and add some style sheet like that:</p>
596
+ <p>And, since we have proper classes to address some style sheets, jump into the
597
+ Page element and add some style sheet like that:</p>
578
598
 
579
599
  <pre><code>&lt;head&gt;
580
600
  &lt;title&gt;TodoList&lt;/title&gt;
@@ -589,11 +609,219 @@ the things inside the Element and look at how it behaves.</p>
589
609
  &lt;/head&gt;
590
610
  </code></pre>
591
611
 
592
- <p>That looks quite a bit nicer, right?
593
- And yes, if you don't like tables (though this is an entirely legit use in my opinion, you can just do it like you want, using nested lists or divs/spans, replacing the open/close and delete links with nice images and changing the style according to the status.</p>
612
+ <p>That looks quite a bit nicer, right? And yes, if you don't like tables (though
613
+ this is an entirely legit use in my opinion, you can just do it like you want,
614
+ using nested lists or divs/spans, replacing the open/close and delete links with
615
+ nice images and changing the style according to the status.</p>
594
616
 
595
617
  <p>I will leave this as an exercise to the reader.</p>
596
618
 
619
+ <a name="Tenth_Step,_Configuration"><h2>Tenth Step, Configuration</h2></a>
620
+
621
+ <p>To round up this tutorial a bit, let's introduce you to configuration in Ramaze.
622
+ This will not go into full depth of possibilities or a total coverage of the
623
+ options, since they are bound to change over time.</p>
624
+
625
+ <p>First of all, the default port Ramaze runs on is 7000, but to make it a usual
626
+ webserver it has to run on port 80. So, let's add following line in your
627
+ main.rb right after the lines of require you added before:</p>
628
+
629
+ <pre><code>Ramaze::Global.port = 80
630
+ </code></pre>
631
+
632
+ <p>Alright, that wasn't that hard.
633
+ Let's say now you also want to run Mongrel instead of WEBrick, to get nice a bit
634
+ of performance:</p>
635
+
636
+ <pre><code>Ramaze::Global.adapter = :mongrel
637
+ </code></pre>
638
+
639
+ <p>To do this in a DRY way you could also do following:</p>
640
+
641
+ <pre><code>Ramaze::Global.setup do |g|
642
+ g.port = 80
643
+ g.adapter = :mongrel
644
+ end
645
+ </code></pre>
646
+
647
+ <p>It seems to be quite common to put this configuration into separate files so you
648
+ can just require it on demand. There are other, slightly stronger way to set
649
+ options, which is either using flags on the ramaze executable, or like this:</p>
650
+
651
+ <pre><code>Ramaze.start :port =&gt; 80, :adapter =&gt; :mongrel
652
+ </code></pre>
653
+
654
+ <p>We haven't started Ramaze directly as of yet, but this allows you to ignore the
655
+ ramaze executable and just run your application.</p>
656
+
657
+ <a name="Eleventh_Step,_Refactor_with_AspectHelper"><h2>Eleventh Step, Refactor with AspectHelper</h2></a>
658
+
659
+ <p>Now, if you take a closer look at the Controller you will see:</p>
660
+
661
+ <pre><code>def create
662
+ title = request['title']
663
+ TodoList[title] = {:done =&gt; false}
664
+ redirect R(self)
665
+ end
666
+
667
+ def open title
668
+ task_status title, false
669
+ redirect R(self)
670
+ end
671
+
672
+ def close title
673
+ task_status title, true
674
+ redirect R(self)
675
+ end
676
+
677
+ def delete title
678
+ TodoList.delete title
679
+ redirect R(self)
680
+ end
681
+ </code></pre>
682
+
683
+ <p>We did some refactoring before, by introducing <code>#task_status</code>, but here we have
684
+ repetition again: <code>redirect Rs()</code> <em>after</em> each method did its job.</p>
685
+
686
+ <p>However, we can take advantage of one of the helpers Ramaze offers, the
687
+ AspectHelper.
688
+ It allows you to easily wrap actions in your controller with other methods</p>
689
+
690
+ <p>In your Controller, replace the previous chunk with following:</p>
691
+
692
+ <pre><code>def create
693
+ title = request['title']
694
+ TodoList[title] = {:done =&gt; false}
695
+ end
696
+
697
+ def open title
698
+ task_status title, false
699
+ end
700
+
701
+ def close title
702
+ task_status title, true
703
+ end
704
+
705
+ def delete title
706
+ TodoList.delete title
707
+ end
708
+
709
+ helper :aspect
710
+ after(:create, :open, :close, :delete){ redirect_index }
711
+
712
+ def redirect_index
713
+ redirect Rs()
714
+ end
715
+ </code></pre>
716
+
717
+ <p>Alright, that looks a lot nicer already and is definitely easier to maintain.
718
+ Please note that the <code>#redirect_index</code> method should not be private, as it is a
719
+ usual action that will just run after the others.</p>
720
+
721
+ <p>There is a symmetrical <code>#before</code> aspect that you could take advantage of as well,
722
+ and in case you want to add required authentication for all actions of a
723
+ Controller you could use <code>#before_all</code> instead of a list of action-names.</p>
724
+
725
+ <a name="Twelfth_Step,_Validation_and_Errors"><h2>Twelfth Step, Validation and Errors</h2></a>
726
+
727
+ <p>Right now, all kinds of things could still go wrong when you do things like
728
+ creating tasks with no title at all or try to open/close a task that does not
729
+ exist. So in this step we will add some little checks for these cases.</p>
730
+
731
+ <p>First we head over to the Controller again and take a look at <code>#create</code>:</p>
732
+
733
+ <pre><code>def create
734
+ title = request['title']
735
+ TodoList[title] = {:done =&gt; false}
736
+ end
737
+ </code></pre>
738
+
739
+ <p>Here we just create a new task, no matter what we get. Every seasoned
740
+ web-developer would advise you to be suspicious about all the input you receive
741
+ from your users, so let's apply this advice.</p>
742
+
743
+ <pre><code>def create
744
+ if title = request['title']
745
+ title.strip!
746
+ if title.empty?
747
+ error("Please enter a title")
748
+ redirect '/new'
749
+ end
750
+ TodoList[title] = {:done =&gt; false}
751
+ end
752
+ end
753
+ </code></pre>
754
+
755
+ <p>First of all we check if we got a request with a value for 'title', if we get
756
+ none we just let the aspect kick in that will redirect the browser to the index.
757
+ Next we strip the title of all spaces around it so we can check if it is empty.
758
+ We will talk about the specifics of our error-handling now.</p>
759
+
760
+ <p>Ramaze has a helper called FlashHelper, that will keep a hash associated with
761
+ the session for one request, afterwards the hash is thrown away. This is
762
+ specifically useful for giving the user feedback while keeping a stateless
763
+ approach.</p>
764
+
765
+ <p>Let me show you our <code>#error</code> method (it goes in the private section to
766
+ <code>#task_status</code>):</p>
767
+
768
+ <pre><code>def error(message)
769
+ flash[:error] = message
770
+ end
771
+ </code></pre>
772
+
773
+ <p>Duh, you may say, wouldn't that fit in the one line instead of the call to
774
+ <code>#error</code>?
775
+ Indeed, it would, but let me remind you, we have no checks for changing the
776
+ status of a task yet. We will need error-handling there as well, so we just keep
777
+ our code DRY and maintainable by collecting shared behaviour in small pieces.</p>
778
+
779
+ <p>Now on to the <code>#task_status</code>:</p>
780
+
781
+ <pre><code>def task_status title, status
782
+ unless task = TodoList[title]
783
+ error "No such Task: `#{title}'"
784
+ redirect_referer
785
+ end
786
+
787
+ task[:done] = status
788
+ TodoList[title] = task
789
+ end
790
+ </code></pre>
791
+
792
+ <p>That used to look like this:</p>
793
+
794
+ <pre><code>def task_status title, status
795
+ task = TodoList[title]
796
+ task[:done] = status
797
+ TodoList[title] = task
798
+ end
799
+ </code></pre>
800
+
801
+ <p>So in fact all we added is a check whether a task already exists, set an
802
+ error-message in case it doesn't and redirect to wherever the browser came from.</p>
803
+
804
+ <p>But what about actually showing the error-messages we so carefully set? Well,
805
+ where do we change the view? Right, in the templates. But both templates we have
806
+ so far (index and new) share this behaviour, so let's head over to the Element
807
+ and add in the right place:</p>
808
+
809
+ <pre><code>&lt;body&gt;
810
+ &lt;h1&gt;#{@title}&lt;/h1&gt;
811
+ &lt;?r if flash[:error] ?&gt;
812
+ &lt;div class="error"&gt;
813
+ \#{flash[:error]}
814
+ &lt;/div&gt;
815
+ &lt;?r end ?&gt;
816
+ #{content}
817
+ &lt;/body&gt;
818
+ </code></pre>
819
+
820
+ <p>The only thing special about it is the <code>\#{flash[:error]}</code>, we have to escape
821
+ the <code>#</code> so it won't evaluate this immediately but wait until it is really
822
+ rendered.
823
+ You can add some nifty style if you like.</p>
824
+
597
825
  <p>To be continued...</p>
598
826
  </body>
599
827
  </html>