ramaze 0.0.8 → 0.0.9

Sign up to get free protection for your applications and to get access to all the features.
Files changed (49) hide show
  1. data/Rakefile +42 -0
  2. data/doc/allison/LICENSE +184 -0
  3. data/doc/allison/README +37 -0
  4. data/doc/allison/allison.css +300 -0
  5. data/doc/allison/allison.gif +0 -0
  6. data/doc/allison/allison.js +307 -0
  7. data/doc/allison/allison.rb +287 -0
  8. data/doc/allison/cache/BODY +588 -0
  9. data/doc/allison/cache/CLASS_INDEX +4 -0
  10. data/doc/allison/cache/CLASS_PAGE +1 -0
  11. data/doc/allison/cache/FILE_INDEX +4 -0
  12. data/doc/allison/cache/FILE_PAGE +1 -0
  13. data/doc/allison/cache/FONTS +1 -0
  14. data/doc/allison/cache/FR_INDEX_BODY +1 -0
  15. data/doc/allison/cache/IMGPATH +1 -0
  16. data/doc/allison/cache/INDEX +1 -0
  17. data/doc/allison/cache/JAVASCRIPT +307 -0
  18. data/doc/allison/cache/METHOD_INDEX +4 -0
  19. data/doc/allison/cache/METHOD_LIST +1 -0
  20. data/doc/allison/cache/SRC_PAGE +1 -0
  21. data/doc/allison/cache/STYLE +322 -0
  22. data/doc/allison/cache/URL +1 -0
  23. data/doc/readme_chunks/principles.txt +33 -18
  24. data/doc/tutorial/todolist.html +599 -0
  25. data/doc/tutorial/todolist.txt +230 -230
  26. data/examples/identity.rb +21 -0
  27. data/examples/nitro_form.rb +22 -0
  28. data/lib/ramaze/controller.rb +1 -1
  29. data/lib/ramaze/dispatcher.rb +10 -4
  30. data/lib/ramaze/helper/{openid.rb → identity.rb} +15 -6
  31. data/lib/ramaze/helper/nitroform.rb +10 -0
  32. data/lib/ramaze/helper/stack.rb +1 -1
  33. data/lib/ramaze/inform.rb +18 -8
  34. data/lib/ramaze/snippets/kernel/aquire.rb +3 -3
  35. data/lib/ramaze/snippets/object/traits.rb +1 -1
  36. data/lib/ramaze/snippets/ramaze/caller_info.rb +17 -1
  37. data/lib/ramaze/snippets/ramaze/caller_lines.rb +1 -1
  38. data/lib/ramaze/store/yaml.rb +10 -1
  39. data/lib/ramaze/template/ezamar.rb +10 -5
  40. data/lib/ramaze/trinity/request.rb +12 -2
  41. data/lib/ramaze/version.rb +1 -1
  42. data/lib/ramaze.rb +5 -3
  43. data/spec/public/error404.xhtml +1 -0
  44. data/spec/spec_all.rb +21 -19
  45. data/spec/spec_helper.rb +1 -1
  46. data/spec/tc_error.rb +18 -4
  47. data/spec/tc_helper_cache.rb +1 -1
  48. data/spec/tc_helper_flash.rb +1 -2
  49. metadata +32 -4
@@ -1,4 +1,4 @@
1
- = To-do List Tutorial
1
+ # To-do List Tutorial
2
2
 
3
3
  Welcome to our official tutorial, the mandatory to-do list.
4
4
  I'm writing this while doing the steps to assure it will work for you.
@@ -23,7 +23,7 @@ RubyForge.
23
23
  Thanks in advance.
24
24
  The author of the tutorial, Michael 'manveru' Fellinger
25
25
 
26
- == First Step, Create
26
+ ## First Step, Create
27
27
 
28
28
  We are using `ramaze --create todolist` to create a new application.
29
29
  Ramaze will then create the directory and fill it with a skeleton of a quite
@@ -32,12 +32,12 @@ to-do list.
32
32
 
33
33
  So run:
34
34
 
35
- $ ramaze --create todolist
35
+ $ ramaze --create todolist
36
36
 
37
37
  done.
38
38
 
39
39
 
40
- == Second Step, M, like Model
40
+ ## Second Step, M, like Model
41
41
 
42
42
  Ramaze comes at the moment only with a simple wrapper of the YAML::Store.
43
43
  So we are going to base this on the tools available, you can just do the same
@@ -48,24 +48,24 @@ YAML::Store already, so we are just gonna modify it a bit to use our wrapper.
48
48
 
49
49
  Instead of 'yaml/store' use:
50
50
 
51
- require 'ramaze/store/default'
51
+ require 'ramaze/store/default'
52
52
 
53
53
  And further:
54
54
 
55
- TodoList = Store::Default.new 'todolist.yaml'
55
+ TodoList = Store::Default.new 'todolist.yaml'
56
56
 
57
57
  To have a base to start off of, let's add some items as well.
58
58
 
59
- {
60
- 'Laundry' => {:done => false},
61
- 'Wash dishes' => {:done => false},
59
+ {
60
+ 'Laundry' => {:done => false},
61
+ 'Wash dishes' => {:done => false},
62
62
 
63
- }.each do |title, parameters|
64
- TodoList[title] = parameters
65
- end
63
+ }.each do |title, parameters|
64
+ TodoList[title] = parameters
65
+ end
66
66
 
67
67
 
68
- == Third Step, V, like View
68
+ ## Third Step, V, like View
69
69
 
70
70
  Now let's get our hands dirty and just edit the templates for our to-do list.
71
71
 
@@ -75,22 +75,22 @@ of Ramaze, called Ezamar.
75
75
  Let's put some things in there, I'll explain the syntax as we go, it's quite
76
76
  simple.
77
77
 
78
- <html>
79
- <head>
80
- <title>TodoList</title>
81
- </head>
82
- <body>
83
- <h1>TodoList</h1>
84
- <ul>
85
- <?r
86
- TodoList.each do |title, parameters|
87
- status = parameters[:done] ? 'done' : 'not done'
88
- ?>
89
- <li>#{title}: #{status}</li>
90
- <?r end ?>
91
- </ul>
92
- </body>
93
- </html>
78
+ <html>
79
+ <head>
80
+ <title>TodoList</title>
81
+ </head>
82
+ <body>
83
+ <h1>TodoList</h1>
84
+ <ul>
85
+ <?r
86
+ TodoList.each do |title, parameters|
87
+ status = parameters[:done] ? 'done' : 'not done'
88
+ ?>
89
+ <li>#{title}: #{status}</li>
90
+ <?r end ?>
91
+ </ul>
92
+ </body>
93
+ </html>
94
94
 
95
95
  I will assume that you are familiar with basic Ruby already, so let's
96
96
  concentrate on the things new here.
@@ -104,10 +104,10 @@ page.
104
104
  The whole Template would expand to something like this (only showing the
105
105
  interesting part)
106
106
 
107
- <ul>
108
- <li>Laundry: not done</li>
109
- <li>Wash dishes: not done</li>
110
- </ul>
107
+ <ul>
108
+ <li>Laundry: not done</li>
109
+ <li>Wash dishes: not done</li>
110
+ </ul>
111
111
 
112
112
  That wasn't too bad, huh?
113
113
 
@@ -124,7 +124,7 @@ now access it by browsing to http://localhost:7000/
124
124
  `ramaze --help` to see some other options.
125
125
 
126
126
 
127
- == Fourth Step, C, like Controller
127
+ ## Fourth Step, C, like Controller
128
128
 
129
129
  The last part of the MVC-paradigm is the Controller.
130
130
 
@@ -144,11 +144,11 @@ edit the file `src/controller/main.rb`.
144
144
 
145
145
  The contents of it are like following:
146
146
 
147
- class MainController < Controller
148
- def index
149
- "Hello, World"
147
+ class MainController < Controller
148
+ def index
149
+ "Hello, World"
150
+ end
150
151
  end
151
- end
152
152
 
153
153
  The only method right now is #index, with a simple and for the moment quite
154
154
  useless "Hello, World". The relationship between the methods on the controller
@@ -157,35 +157,35 @@ and the templates is 1:1, so the method #index is combined with the template
157
157
 
158
158
  Let's get back to editing and change the index-method to this:
159
159
 
160
- def index
161
- @tasks = TodoList.content
162
- @tasks.each do |title, parameters|
163
- status = parameters[:done] ? 'done' : 'not done'
164
- @tasks[title] = status
160
+ def index
161
+ @tasks = TodoList.content
162
+ @tasks.each do |title, parameters|
163
+ status = parameters[:done] ? 'done' : 'not done'
164
+ @tasks[title] = status
165
+ end
165
166
  end
166
- end
167
167
 
168
168
  This will take care of the logic inside the template, which now should be
169
169
  changed to do following:
170
170
 
171
- <html>
172
- <head>
173
- <title>TodoList</title>
174
- </head>
175
- <body>
176
- <h1>TodoList</h1>
177
- <a href="/new">New Task</a>
178
- <?r if @tasks.empty? ?>
179
- No Tasks
180
- <?r else ?>
181
- <ul>
182
- <?r @tasks.each do |title, status| ?>
183
- <li>#{title}: #{status}</li>
184
- <?r end ?>
185
- </ul>
186
- <?r end ?>
187
- </body>
188
- </html>
171
+ <html>
172
+ <head>
173
+ <title>TodoList</title>
174
+ </head>
175
+ <body>
176
+ <h1>TodoList</h1>
177
+ <a href="/new">New Task</a>
178
+ <?r if @tasks.empty? ?>
179
+ No Tasks
180
+ <?r else ?>
181
+ <ul>
182
+ <?r @tasks.each do |title, status| ?>
183
+ <li>#{title}: #{status}</li>
184
+ <?r end ?>
185
+ </ul>
186
+ <?r end ?>
187
+ </body>
188
+ </html>
189
189
 
190
190
  The rest of the template can stay the same.
191
191
 
@@ -198,31 +198,31 @@ Some things you should know:
198
198
  * Instance-variables defined in the Controller are available in the View.
199
199
  * The return-value of the Controller does not matter (in this case).
200
200
 
201
- == Fifth Step, getting dynamic
201
+ ## Fifth Step, getting dynamic
202
202
 
203
203
  We set out to build the ultimate to-do list, but there are still some things
204
204
  missing. First off, we want to add new tasks, so let's get that done.
205
205
 
206
206
  Add a link on the `template/index.xhtml` like this:
207
207
 
208
- <h1>TodoList</h1>
209
- <a href="/new">New Task</a>
208
+ <h1>TodoList</h1>
209
+ <a href="/new">New Task</a>
210
210
 
211
211
  Open a new file `template/new.xhtml` with a form to add a new task.
212
212
 
213
- <html>
214
- <head>
215
- <title>TodoList</title>
216
- </head>
217
- <body>
218
- <h1>New Task</h1>
219
- <a href="/">Back to TodoList</a>
220
- <form method="POST" action="create">
221
- Task: <input type="text" name="title" /><br />
222
- <inpyt type="submit" />
223
- </form>
224
- </body>
225
- </html>
213
+ <html>
214
+ <head>
215
+ <title>TodoList</title>
216
+ </head>
217
+ <body>
218
+ <h1>New Task</h1>
219
+ <a href="/">Back to TodoList</a>
220
+ <form method="POST" action="create">
221
+ Task: <input type="text" name="title" /><br />
222
+ <inpyt type="submit" />
223
+ </form>
224
+ </body>
225
+ </html>
226
226
 
227
227
  We will not need a method for this on our controller, in fact, actions can
228
228
  consist of either method and template or only one of them. The Controller
@@ -244,11 +244,11 @@ OK, let's implement the action for #create, all we want to do is take the
244
244
  requests parameters and create a new task for it, this looks like following on
245
245
  your MainController.
246
246
 
247
- def create
248
- title = request['title']
249
- TodoList[title] = {:done => false}
250
- redirect R(self)
251
- end
247
+ def create
248
+ title = request['title']
249
+ TodoList[title] = {:done => false}
250
+ redirect R(self)
251
+ end
252
252
 
253
253
  That's all folks!
254
254
 
@@ -258,7 +258,7 @@ and redirect back to the mapping of the current Controller ('/' in this case).
258
258
  Now you can create as many tasks as you want, please don't get overworked ;)
259
259
 
260
260
 
261
- == Sixth Step, open and close tasks
261
+ ## Sixth Step, open and close tasks
262
262
 
263
263
  Since the nature of tasks is to be done eventually
264
264
  we will need some way to mark it as done or open tasks again.
@@ -266,30 +266,30 @@ we will need some way to mark it as done or open tasks again.
266
266
  Jump into `template/index.xhtml` and do the following:
267
267
 
268
268
 
269
- <?r @tasks.each do |title, status, toggle| ?>
270
- <li>
271
- #{title}: #{status} - #{toggle}
272
- </li>
273
- <?r end ?>
269
+ <?r @tasks.each do |title, status, toggle| ?>
270
+ <li>
271
+ #{title}: #{status} - #{toggle}
272
+ </li>
273
+ <?r end ?>
274
274
 
275
275
  We added a new element here, `toggle`, the Controller should give us
276
276
  a link to change the status corresponding to the status of the task, so off
277
277
  we go and change the index method on the controller once again:
278
278
 
279
- def index
280
- @tasks = []
281
- TodoList.original.each do |title, parameters|
282
- if parameters[:done]
283
- status = 'done'
284
- toggle = link( R( self, :open, CGI.escape(title) ), :title => 'Open Task' )
285
- else
286
- status = 'not done'
287
- toggle = link( R( self, :close, CGI.escape(title) ), :title => 'Close Task' )
279
+ def index
280
+ @tasks = []
281
+ TodoList.original.each do |title, parameters|
282
+ if parameters[:done]
283
+ status = 'done'
284
+ toggle = link( R( self, :open, CGI.escape(title) ), :title => 'Open Task' )
285
+ else
286
+ status = 'not done'
287
+ toggle = link( R( self, :close, CGI.escape(title) ), :title => 'Close Task' )
288
+ end
289
+ @tasks << [title, status, toggle]
288
290
  end
289
- @tasks << [title, status, toggle]
291
+ @tasks.sort!
290
292
  end
291
- @tasks.sort!
292
- end
293
293
 
294
294
  Wow, quite some new stuff here. Let me explain that in detail.
295
295
 
@@ -297,7 +297,7 @@ We first decide whether a task is done or not, then go on and provide a link to
297
297
  toggle the status, link and R are both methods that help you do that.
298
298
  the result will be something like:
299
299
 
300
- <a href="/open/Wash+dishes">Close Task</a>
300
+ <a href="/open/Wash+dishes">Close Task</a>
301
301
 
302
302
  R actually is responsible to build the links href, for more information please
303
303
  take a look at the RDoc for LinkHelper.
@@ -308,55 +308,55 @@ now we use an array to hold our tasks and sort it.
308
308
 
309
309
  Now back again to `template/index.xhtml` and change it as follows:
310
310
 
311
- <?r @tasks.each do |title, status, toggle| ?>
312
- <li>
313
- #{title}: #{status} [ #{toggle} ]
314
- </li>
315
- <?r end ?>
311
+ <?r @tasks.each do |title, status, toggle| ?>
312
+ <li>
313
+ #{title}: #{status} [ #{toggle} ]
314
+ </li>
315
+ <?r end ?>
316
316
 
317
317
  As usual, the things not changed are omitted for terseness.
318
318
 
319
319
  And as usual since the links for open and close don't lead anywhere, add the
320
320
  corresponding methods to the Controller:
321
321
 
322
- def open title
323
- task_status title, false
324
- redirect R(self)
325
- end
322
+ def open title
323
+ task_status title, false
324
+ redirect R(self)
325
+ end
326
326
 
327
- def close title
328
- task_status title, true
329
- redirect R(self)
330
- end
327
+ def close title
328
+ task_status title, true
329
+ redirect R(self)
330
+ end
331
331
 
332
- private
332
+ private
333
333
 
334
- def task_status title, status
335
- task = TodoList[title]
336
- task[:done] = status
337
- TodoList[title] = task
338
- end
334
+ def task_status title, status
335
+ task = TodoList[title]
336
+ task[:done] = status
337
+ TodoList[title] = task
338
+ end
339
339
 
340
340
  Oh, now what have we got here?
341
341
  private declares that methods from here on are only to be used within the
342
342
  Controller itself, we define an #task_status method that takes the title and
343
- status to be set so we don't have to repeat that code in #open and #close and
344
- follow the DRY (Don't repeat yourself) paradigm.
343
+ status to be set so we don't have to repeat that code in _#open_ and _#close_
344
+ and follow the DRY (Don't repeat yourself) paradigm.
345
345
 
346
346
  Another thing we have not encountered so far is that you can define your public
347
347
  methods to take parameters on their own, they will be calculated from requests.
348
348
 
349
- '/open/Wash+dishes'
349
+ '/open/Wash+dishes'
350
350
 
351
351
  will translate into:
352
352
 
353
- open('Wash dishes')
353
+ open('Wash dishes')
354
354
 
355
355
  Which in turn will call task_status('Wash dishes', false)
356
356
 
357
357
  That's it, go on and try it :)
358
358
 
359
- == Seventh Step, delete tasks
359
+ ## Seventh Step, delete tasks
360
360
 
361
361
  Well, creating, opening and closing work now, one of the things you will
362
362
  consider is to delete a task permanently.
@@ -364,23 +364,23 @@ consider is to delete a task permanently.
364
364
  This is just two little changes away, so let's add the link for deletion in our
365
365
  Controller:
366
366
 
367
- delete = link( R( self, :delete, CGI.escape(title) ), :title => 'Delete' )
368
- @tasks << [title, status, toggle, delete]
367
+ delete = link( R( self, :delete, CGI.escape(title) ), :title => 'Delete' )
368
+ @tasks << [title, status, toggle, delete]
369
369
 
370
370
  and an corresponding method while we're at it:
371
371
 
372
- def delete title
373
- TodoList.delete title
374
- redirect R(self)
375
- end
372
+ def delete title
373
+ TodoList.delete title
374
+ redirect R(self)
375
+ end
376
376
 
377
377
  Now jumping to `template/index.xhtml` again, change it so it shows the link:
378
378
 
379
- <?r @tasks.each do |title, status, toggle, delete| ?>
380
- <li>
381
- #{title}: #{status} [ #{toggle} | #{delete} ]
382
- </li>
383
- <?r end ?>
379
+ <?r @tasks.each do |title, status, toggle, delete| ?>
380
+ <li>
381
+ #{title}: #{status} [ #{toggle} | #{delete} ]
382
+ </li>
383
+ <?r end ?>
384
384
 
385
385
  Voilà, you now have acquired the Certificate of Ramazeness, our accounting-
386
386
  section will contact you within the next few days.
@@ -389,32 +389,32 @@ Just kidding, but that really are the basics, in the next few steps I will
389
389
  explain some more advanced concepts of Ramaze and the templating.
390
390
 
391
391
 
392
- == Eight Step, Elements
392
+ ## Eighth Step, Elements
393
393
 
394
- <Page></Page>
394
+ <Page></Page>
395
395
 
396
396
  This is called an Element, Ramaze will go and search for a class that matches
397
- the name Page and responds to #render. Then it will go and hand the content in
397
+ the name Page and responds to _#render_. Then it will go and hand the content in
398
398
  between to that Element.
399
399
 
400
400
  Sounds weird?
401
401
 
402
402
  Let us have a look at our templates, they all got some repetitive stuff, like:
403
403
 
404
- <html>
405
- <head>
406
- <title>TodoList</title>
407
- </head>
408
- <body>
409
- <h1>some title</h1>
410
- </body>
411
- </html>
404
+ <html>
405
+ <head>
406
+ <title>TodoList</title>
407
+ </head>
408
+ <body>
409
+ <h1>some title</h1>
410
+ </body>
411
+ </html>
412
412
 
413
413
  How about replacing that with something short and nice:
414
414
 
415
- <Page title="TodoList">
416
- your other content
417
- </Page>
415
+ <Page title="TodoList">
416
+ your other content
417
+ </Page>
418
418
 
419
419
  Would be nice of course, and when you start having more templates it makes an
420
420
  awful lot of sense to change the enclosing stuff in one place.
@@ -423,43 +423,43 @@ So let's apply DRY here as well.
423
423
 
424
424
  Take a look at the `src/element/page.rb`
425
425
 
426
- class Page < Element
427
- def render
428
- %{
429
- <html>
430
- <head>
431
- <title>Welcome to Ramaze</title>
432
- </head>
433
- <body>
434
- #{content}
435
- </body>
436
- </html>
437
- }
426
+ class Page < Element
427
+ def render
428
+ %{
429
+ <html>
430
+ <head>
431
+ <title>Welcome to Ramaze</title>
432
+ </head>
433
+ <body>
434
+ #{content}
435
+ </body>
436
+ </html>
437
+ }
438
+ end
438
439
  end
439
- end
440
440
 
441
441
  Alright, most things we need are in place already, the most important thing
442
- is the #content method that we call with #{content} inside the string in
443
- #render.
442
+ is the _#content_ method that we call with _#{content}_ inside the string in
443
+ _#render_.
444
444
 
445
445
  Just adopt it to your liking, I'll just use the things we had in our templates
446
446
  so far:
447
447
 
448
- class Page < Element
449
- def render
450
- %{
451
- <html>
452
- <head>
453
- <title>TodoList</title>
454
- </head>
455
- <body>
456
- <h1>#{@hash['title']}</h1>
457
- #{content}
458
- </body>
459
- </html>
460
- }
448
+ class Page < Element
449
+ def render
450
+ %{
451
+ <html>
452
+ <head>
453
+ <title>TodoList</title>
454
+ </head>
455
+ <body>
456
+ <h1>#{@hash['title']}</h1>
457
+ #{content}
458
+ </body>
459
+ </html>
460
+ }
461
+ end
461
462
  end
462
- end
463
463
 
464
464
  Please note that the @hash is filled with the things you pass as parameters
465
465
  to tye Page-tag.
@@ -468,75 +468,75 @@ And let's change our templates as well.
468
468
 
469
469
  First the `template/index.xhtml`
470
470
 
471
- <Page title="TodoList">
472
- <a href="/new">New Task</a>
473
- <?r if @tasks.empty? ?>
474
- No Tasks
475
- <?r else ?>
476
- <ul>
477
- <?r @tasks.each do |title, status, toggle, delete| ?>
478
- <li>
479
- #{title}: #{status} [ #{toggle} | #{delete} ]
480
- </li>
481
- <?r end ?>
482
- </ul>
483
- <?r end ?>
484
- </Page>
471
+ <Page title="TodoList">
472
+ <a href="/new">New Task</a>
473
+ <?r if @tasks.empty? ?>
474
+ No Tasks
475
+ <?r else ?>
476
+ <ul>
477
+ <?r @tasks.each do |title, status, toggle, delete| ?>
478
+ <li>
479
+ #{title}: #{status} [ #{toggle} | #{delete} ]
480
+ </li>
481
+ <?r end ?>
482
+ </ul>
483
+ <?r end ?>
484
+ </Page>
485
485
 
486
486
  and the `template/new.xhtml`
487
487
 
488
- <Page title="New Task">
489
- <a href="/">Back to TodoList</a>
490
- <form method="POST" action="create">
491
- Task: <input type="text" name="title" /><br />
492
- <input type="submit" />
493
- </form>
494
- </Page>
488
+ <Page title="New Task">
489
+ <a href="/">Back to TodoList</a>
490
+ <form method="POST" action="create">
491
+ Task: <input type="text" name="title" /><br />
492
+ <input type="submit" />
493
+ </form>
494
+ </Page>
495
495
 
496
496
  Alright, now just go and look at the result in the browser, try changing
497
497
  the things inside the Element and look at how it behaves.
498
498
 
499
499
 
500
- == Ninth Step, Prettify
500
+ ## Ninth Step, Prettify
501
501
 
502
502
  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.
503
503
 
504
504
  So, from what we have right now:
505
505
 
506
- <ul>
507
- <?r @tasks.each do |title, status, toggle, delete| ?>
508
- <li>
509
- #{title}: #{status} [ #{toggle} | #{delete} ]
510
- </li>
511
- <?r end ?>
512
- </ul>
506
+ <ul>
507
+ <?r @tasks.each do |title, status, toggle, delete| ?>
508
+ <li>
509
+ #{title}: #{status} [ #{toggle} | #{delete} ]
510
+ </li>
511
+ <?r end ?>
512
+ </ul>
513
513
 
514
514
  To something like this:
515
515
 
516
- <table>
517
- <?r @tasks.each do |title, status, toggle, delete| ?>
518
- <tr>
519
- <td class="title"> #{title} </td>
520
- <td class="status"> #{status} </td>
521
- <td class="toggle"> #{toggle} </td>
522
- <td class="delete"> #{delete} </td>
523
- </tr>
524
- <?r end ?>
525
- </table>
516
+ <table>
517
+ <?r @tasks.each do |title, status, toggle, delete| ?>
518
+ <tr>
519
+ <td class="title"> #{title} </td>
520
+ <td class="status"> #{status} </td>
521
+ <td class="toggle"> #{toggle} </td>
522
+ <td class="delete"> #{delete} </td>
523
+ </tr>
524
+ <?r end ?>
525
+ </table>
526
526
 
527
527
  And, since we have proper classes to address some style sheets, jump into the Page element and add some style sheet like that:
528
528
 
529
- <head>
530
- <title>TodoList</title>
531
- <style>
532
- table { width: 100%; }
533
- tr { background: #efe; width: 100%; }
534
- tr:hover { background: #dfd; }
535
- td.title { font-weight: bold; width: 60%; }
536
- td.status { margin: 1em; }
537
- a { color: #3a3; }
538
- </style>
539
- </head>
529
+ <head>
530
+ <title>TodoList</title>
531
+ <style>
532
+ table { width: 100%; }
533
+ tr { background: #efe; width: 100%; }
534
+ tr:hover { background: #dfd; }
535
+ td.title { font-weight: bold; width: 60%; }
536
+ td.status { margin: 1em; }
537
+ a { color: #3a3; }
538
+ </style>
539
+ </head>
540
540
 
541
541
  That looks quite a bit nicer, right?
542
542
  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.