ramaze 0.0.7 → 0.0.8
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.
- data/Rakefile +52 -19
- data/bin/ramaze +19 -6
- data/doc/CHANGELOG +33 -0
- data/doc/COPYING +1 -1
- data/doc/FAQ +92 -0
- data/doc/GPL +340 -0
- data/doc/INSTALL +34 -0
- data/doc/ProjectInfo +53 -0
- data/doc/README +187 -110
- data/doc/readme_chunks/appendix.txt +13 -0
- data/doc/readme_chunks/examples.txt +38 -0
- data/doc/readme_chunks/features.txt +82 -0
- data/doc/readme_chunks/getting_help.txt +5 -0
- data/doc/readme_chunks/getting_started.txt +18 -0
- data/doc/readme_chunks/installing.txt +41 -0
- data/doc/readme_chunks/introduction.txt +18 -0
- data/doc/readme_chunks/principles.txt +41 -0
- data/doc/readme_chunks/thanks.txt +59 -0
- data/doc/tutorial/todolist.txt +546 -0
- data/examples/blog/main.rb +1 -1
- data/examples/blog/src/controller.rb +13 -11
- data/examples/blog/src/element.rb +11 -6
- data/examples/blog/src/model.rb +8 -23
- data/examples/blog/template/edit.xhtml +3 -1
- data/examples/blog/template/index.xhtml +4 -4
- data/examples/caching.rb +4 -4
- data/examples/element.rb +10 -7
- data/examples/hello.rb +3 -4
- data/examples/simple.rb +5 -3
- data/examples/templates/template/external.amrita +19 -0
- data/examples/templates/template/{external.rmze → external.zmr} +2 -2
- data/examples/templates/template_amrita2.rb +48 -0
- data/examples/templates/template_erubis.rb +5 -2
- data/examples/templates/{template_ramaze.rb → template_ezamar.rb} +13 -7
- data/examples/templates/template_haml.rb +4 -1
- data/examples/templates/template_liquid.rb +2 -1
- data/examples/templates/template_markaby.rb +2 -1
- data/examples/todolist/conf/benchmark.yaml +35 -0
- data/examples/todolist/conf/debug.yaml +34 -0
- data/examples/todolist/conf/live.yaml +33 -0
- data/examples/todolist/conf/silent.yaml +31 -0
- data/examples/todolist/conf/stage.yaml +33 -0
- data/examples/todolist/main.rb +18 -0
- data/examples/todolist/public/404.jpg +0 -0
- data/examples/todolist/public/css/coderay.css +105 -0
- data/examples/todolist/public/css/ramaze_error.css +42 -0
- data/{lib/proto → examples/todolist}/public/error.xhtml +0 -0
- data/examples/todolist/public/favicon.ico +0 -0
- data/examples/todolist/public/js/jquery.js +1923 -0
- data/examples/todolist/public/ramaze.png +0 -0
- data/examples/todolist/src/controller/main.rb +56 -0
- data/examples/todolist/src/element/page.rb +26 -0
- data/examples/todolist/src/model.rb +14 -0
- data/examples/todolist/template/index.xhtml +17 -0
- data/examples/todolist/template/new.xhtml +7 -0
- data/examples/todolist/todolist.db +9 -0
- data/examples/whywiki/main.rb +3 -8
- data/examples/whywiki/template/show.xhtml +4 -0
- data/lib/proto/public/error.zmr +77 -0
- data/lib/proto/src/controller/main.rb +2 -1
- data/lib/proto/src/element/page.rb +2 -1
- data/lib/proto/src/model.rb +3 -2
- data/lib/ramaze.rb +7 -9
- data/lib/ramaze/adapter.rb +51 -0
- data/lib/ramaze/adapter/cgi.rb +23 -0
- data/lib/ramaze/adapter/fcgi.rb +22 -0
- data/lib/ramaze/adapter/mongrel.rb +7 -86
- data/lib/ramaze/adapter/webrick.rb +14 -133
- data/lib/ramaze/cache/memcached.rb +6 -0
- data/lib/ramaze/cache/yaml_store.rb +3 -1
- data/lib/ramaze/controller.rb +292 -2
- data/lib/ramaze/dispatcher.rb +85 -213
- data/lib/ramaze/error.rb +10 -0
- data/lib/ramaze/global.rb +8 -0
- data/lib/ramaze/helper/aspect.rb +30 -7
- data/lib/ramaze/helper/auth.rb +16 -9
- data/lib/ramaze/helper/cache.rb +40 -35
- data/lib/ramaze/helper/feed.rb +1 -1
- data/lib/ramaze/helper/flash.rb +34 -0
- data/lib/ramaze/helper/link.rb +8 -2
- data/lib/ramaze/helper/openid.rb +63 -0
- data/lib/ramaze/helper/redirect.rb +12 -11
- data/lib/ramaze/helper/stack.rb +5 -7
- data/lib/ramaze/inform.rb +12 -1
- data/lib/ramaze/snippets/kernel/aquire.rb +1 -1
- data/lib/ramaze/snippets/kernel/{self_method.rb → method.rb} +3 -18
- data/lib/ramaze/snippets/kernel/{rescue_require.rb → pretty_inspect.rb} +7 -6
- data/lib/ramaze/snippets/method/name.rb +22 -0
- data/lib/ramaze/snippets/{kernel → ramaze}/autoreload.rb +0 -0
- data/lib/ramaze/snippets/ramaze/caller_info.rb +14 -0
- data/lib/ramaze/snippets/{kernel → ramaze}/caller_lines.rb +3 -10
- data/lib/ramaze/snippets/rdoc/usage_no_exit.rb +49 -23
- data/lib/ramaze/snippets/string/DIVIDE.rb +0 -1
- data/lib/ramaze/store/default.rb +58 -2
- data/lib/ramaze/store/yaml.rb +161 -0
- data/lib/ramaze/template.rb +27 -86
- data/lib/ramaze/template/amrita2.rb +14 -19
- data/lib/ramaze/template/erubis.rb +15 -38
- data/lib/ramaze/template/ezamar.rb +100 -0
- data/lib/ramaze/template/ezamar/element.rb +166 -0
- data/lib/ramaze/template/ezamar/engine.rb +124 -0
- data/lib/ramaze/template/ezamar/morpher.rb +155 -0
- data/lib/ramaze/template/haml.rb +16 -43
- data/lib/ramaze/template/liquid.rb +11 -51
- data/lib/ramaze/template/markaby.rb +44 -42
- data/lib/ramaze/tool/mime.rb +18 -0
- data/lib/ramaze/tool/mime_types.yaml +615 -0
- data/lib/ramaze/trinity/request.rb +20 -196
- data/lib/ramaze/trinity/response.rb +4 -33
- data/lib/ramaze/trinity/session.rb +150 -72
- data/lib/ramaze/version.rb +1 -1
- data/spec/adapter_spec.rb +20 -0
- data/spec/public/favicon.ico +0 -0
- data/spec/public/ramaze.png +0 -0
- data/spec/public/test_download.css +141 -0
- data/spec/{tc_request.rb → request_tc_helper.rb} +45 -21
- data/spec/spec_all.rb +77 -34
- data/spec/spec_helper.rb +8 -157
- data/spec/spec_helper_context.rb +72 -0
- data/spec/spec_helper_requester.rb +52 -0
- data/spec/spec_helper_simple_http.rb +433 -0
- data/spec/tc_adapter_mongrel.rb +3 -15
- data/spec/tc_adapter_webrick.rb +4 -14
- data/spec/tc_cache.rb +3 -5
- data/spec/tc_controller.rb +22 -12
- data/spec/tc_dependencies.rb +13 -0
- data/spec/tc_element.rb +8 -7
- data/spec/tc_error.rb +13 -7
- data/spec/tc_global.rb +16 -18
- data/spec/tc_helper_aspect.rb +2 -4
- data/spec/tc_helper_auth.rb +15 -14
- data/spec/tc_helper_cache.rb +5 -7
- data/spec/tc_helper_feed.rb +0 -2
- data/spec/tc_helper_flash.rb +103 -0
- data/spec/tc_helper_form.rb +4 -6
- data/spec/tc_helper_link.rb +1 -3
- data/spec/tc_helper_redirect.rb +23 -8
- data/spec/tc_helper_stack.rb +31 -15
- data/spec/tc_morpher.rb +1 -3
- data/spec/tc_params.rb +48 -7
- data/spec/tc_request_mongrel.rb +9 -0
- data/spec/tc_request_webrick.rb +5 -0
- data/spec/tc_session.rb +41 -25
- data/spec/tc_store.rb +55 -6
- data/spec/tc_store_yaml.rb +71 -0
- data/spec/tc_template_amrita2.rb +3 -3
- data/spec/tc_template_erubis.rb +2 -3
- data/spec/{tc_template_ramaze.rb → tc_template_ezamar.rb} +15 -5
- data/spec/tc_template_haml.rb +4 -3
- data/spec/tc_template_liquid.rb +3 -4
- data/spec/tc_template_markaby.rb +4 -6
- data/spec/tc_tidy.rb +1 -3
- data/spec/template/amrita2/{data.html → data.amrita} +0 -0
- data/spec/template/amrita2/{index.html → index.amrita} +0 -0
- data/spec/template/amrita2/{sum.html → sum.amrita} +0 -0
- data/spec/template/ezamar/another/long/action.zmr +1 -0
- data/spec/template/ezamar/combined.zmr +1 -0
- data/spec/template/{ramaze/file_only.rmze → ezamar/file_only.zmr} +0 -0
- data/spec/template/{ramaze/index.rmze → ezamar/index.zmr} +0 -0
- data/spec/template/{ramaze/nested.rmze → ezamar/nested.zmr} +0 -0
- data/spec/template/ezamar/some__long__action.zmr +1 -0
- data/spec/template/{ramaze/sum.rmze → ezamar/sum.zmr} +0 -0
- metadata +181 -123
- data/doc/allison/LICENSE +0 -184
- data/doc/allison/README +0 -37
- data/doc/allison/allison.css +0 -300
- data/doc/allison/allison.gif +0 -0
- data/doc/allison/allison.js +0 -307
- data/doc/allison/allison.rb +0 -287
- data/doc/allison/cache/BODY +0 -588
- data/doc/allison/cache/CLASS_INDEX +0 -4
- data/doc/allison/cache/CLASS_PAGE +0 -1
- data/doc/allison/cache/FILE_INDEX +0 -4
- data/doc/allison/cache/FILE_PAGE +0 -1
- data/doc/allison/cache/FONTS +0 -1
- data/doc/allison/cache/FR_INDEX_BODY +0 -1
- data/doc/allison/cache/IMGPATH +0 -1
- data/doc/allison/cache/INDEX +0 -1
- data/doc/allison/cache/JAVASCRIPT +0 -307
- data/doc/allison/cache/METHOD_INDEX +0 -4
- data/doc/allison/cache/METHOD_LIST +0 -1
- data/doc/allison/cache/SRC_PAGE +0 -1
- data/doc/allison/cache/STYLE +0 -322
- data/doc/allison/cache/URL +0 -1
- data/doc/changes.txt +0 -2021
- data/doc/changes.xml +0 -2024
- data/lib/ramaze/snippets/kernel/silently.rb +0 -13
- data/lib/ramaze/snippets/thread/deadQUESTIONMARK.rb +0 -11
- data/lib/ramaze/template/haml/actionview_stub.rb +0 -20
- data/lib/ramaze/template/ramaze.rb +0 -177
- data/lib/ramaze/template/ramaze/element.rb +0 -166
- data/lib/ramaze/template/ramaze/morpher.rb +0 -156
- data/spec/tc_test.rb +0 -17
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
* Nicer Error-pages
|
|
2
|
+
* Install coderay (it's a gem)
|
|
3
|
+
|
|
4
|
+
* Performance
|
|
5
|
+
* Serving
|
|
6
|
+
|
|
7
|
+
For best performance you should consider using Mongrel to host your
|
|
8
|
+
application.
|
|
9
|
+
|
|
10
|
+
* Caching
|
|
11
|
+
|
|
12
|
+
You can easily cache your pages using the CacheHelper.
|
|
13
|
+
Also, using MemCache gives you high-end performance and security.
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
There are some examples for your instant pleasure inside the examples-directory
|
|
2
|
+
in the Ramaze-distribution.
|
|
3
|
+
To start up an example, you can use the Ramaze binary located in bin/ramaze
|
|
4
|
+
for example:
|
|
5
|
+
|
|
6
|
+
$ ramaze examples/hello.rb
|
|
7
|
+
|
|
8
|
+
Or:
|
|
9
|
+
|
|
10
|
+
$ cd examples/blog
|
|
11
|
+
$ ramaze
|
|
12
|
+
|
|
13
|
+
Since ramaze uses the main.rb by default if you don't pass anything else.
|
|
14
|
+
|
|
15
|
+
For more information about the usage of ramaze try:
|
|
16
|
+
|
|
17
|
+
$ ramaze --help
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
Examples include:
|
|
21
|
+
|
|
22
|
+
* examples/hello.rb
|
|
23
|
+
Hello, World!
|
|
24
|
+
|
|
25
|
+
* examples/simple.rb
|
|
26
|
+
A bit more advanced than the hello-example, but still very basic.
|
|
27
|
+
|
|
28
|
+
* examples/blog
|
|
29
|
+
Not yet fully functional, but coming along.
|
|
30
|
+
|
|
31
|
+
* examples/whywiki
|
|
32
|
+
A basic examples of a minimalistic application, based on the Wiki of _why in
|
|
33
|
+
his camping-framework.
|
|
34
|
+
|
|
35
|
+
* examples/templates
|
|
36
|
+
examples of real usage of the templating-engines. Tries to implement the same
|
|
37
|
+
functionality in each template_*.rb file using a different engine.
|
|
38
|
+
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
Ramaze offers following features at the moment:
|
|
2
|
+
|
|
3
|
+
* Adapters
|
|
4
|
+
|
|
5
|
+
Ramaze takes advantage of the rack library to provide a common way of
|
|
6
|
+
handling different ways to serve its content.
|
|
7
|
+
|
|
8
|
+
Rack supports at the moment:
|
|
9
|
+
|
|
10
|
+
* Mongrel
|
|
11
|
+
|
|
12
|
+
http://mongrel.rubyforge.org/
|
|
13
|
+
Mongrel is a fast HTTP library and server for Ruby that is intended for
|
|
14
|
+
hosting Ruby web applications of any kind using plain HTTP rather than
|
|
15
|
+
FastCGI or SCGI.
|
|
16
|
+
|
|
17
|
+
* WEBrick
|
|
18
|
+
|
|
19
|
+
http://www.webrick.org/
|
|
20
|
+
WEBrick is a Ruby library program to build HTTP servers.
|
|
21
|
+
|
|
22
|
+
* CGI
|
|
23
|
+
|
|
24
|
+
CGI is the Common Gateway Interface and is one of the most basic ways
|
|
25
|
+
to integrate into Webservers like Apache, Lighttpd or Nginx.
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
* Templates
|
|
29
|
+
* Amrita2
|
|
30
|
+
|
|
31
|
+
http://amrita2.rubyforge.org/
|
|
32
|
+
Amrita2 is a xml/xhtml template library for Ruby. It makes html documents
|
|
33
|
+
from a template and a model data.
|
|
34
|
+
|
|
35
|
+
* Erubis
|
|
36
|
+
|
|
37
|
+
http://rubyforge.org/projects/erubis
|
|
38
|
+
Erubis is a fast, secure, and very extensible implementation of eRuby.
|
|
39
|
+
|
|
40
|
+
* Haml
|
|
41
|
+
|
|
42
|
+
http://haml.hamptoncatlin.com/
|
|
43
|
+
Haml takes your gross, ugly templates and replaces them with veritable Haiku.
|
|
44
|
+
|
|
45
|
+
* Liquid
|
|
46
|
+
|
|
47
|
+
http://home.leetsoft.com/liquid
|
|
48
|
+
Liquid's syntax and parse model are inspired by Django templates, as well
|
|
49
|
+
as PHP's smarty.
|
|
50
|
+
|
|
51
|
+
* Markaby
|
|
52
|
+
|
|
53
|
+
http://code.whytheluckystiff.net/markaby/
|
|
54
|
+
Markaby means Markup as Ruby.
|
|
55
|
+
|
|
56
|
+
* Ezamar
|
|
57
|
+
|
|
58
|
+
A simple homage to Nitros templating. Please check out http://nitroproject.org
|
|
59
|
+
for more information.
|
|
60
|
+
|
|
61
|
+
* Cache
|
|
62
|
+
* Hash
|
|
63
|
+
* YAML::Store
|
|
64
|
+
* MemCache
|
|
65
|
+
|
|
66
|
+
* Helper
|
|
67
|
+
* Aspect
|
|
68
|
+
* Auth
|
|
69
|
+
* Cache
|
|
70
|
+
* Feed
|
|
71
|
+
* Flash
|
|
72
|
+
* Form
|
|
73
|
+
* Link
|
|
74
|
+
* OpenID
|
|
75
|
+
* Redirect
|
|
76
|
+
* Stack
|
|
77
|
+
|
|
78
|
+
* Various
|
|
79
|
+
* Sessions
|
|
80
|
+
* Global configuration system
|
|
81
|
+
* Simple request/response handling
|
|
82
|
+
* Custom Error-handling
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Now that you have a vague idea of what you're about to get into you might just
|
|
2
|
+
want to get a way to get up and running ASAP.
|
|
3
|
+
Please read below for more information about installation.
|
|
4
|
+
|
|
5
|
+
Depending on what you are planning to do you can either just go and start
|
|
6
|
+
reading the source or directly get some hands-on experience by trying some of
|
|
7
|
+
the examples.
|
|
8
|
+
Most things will require dependencies though. The basic functionality is
|
|
9
|
+
provided by the WEBrick adapter and the Template::Ramaze, which just run out
|
|
10
|
+
of the box. For more features you will have to install some templating-engines
|
|
11
|
+
and mongrel (_very_ recommended). Ramaze will inform you when it needs further
|
|
12
|
+
dependencies, so just go and try some things.
|
|
13
|
+
|
|
14
|
+
Some places to get started are:
|
|
15
|
+
- Read the documentation.
|
|
16
|
+
- Run and read the test cases.
|
|
17
|
+
- Look at the examples and run/modify them.
|
|
18
|
+
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
* via RubyGems
|
|
2
|
+
|
|
3
|
+
The simplest way of installing Ramaze is via
|
|
4
|
+
|
|
5
|
+
$ gem install ramaze
|
|
6
|
+
|
|
7
|
+
in case you have RubyGems installed.
|
|
8
|
+
(this will work as soon as I have registered on RubyForge ;)
|
|
9
|
+
|
|
10
|
+
* via darcs
|
|
11
|
+
|
|
12
|
+
To get the latest and sweetest, you can just pull from the repository and run
|
|
13
|
+
Ramaze that way.
|
|
14
|
+
|
|
15
|
+
$ darcs get http://manveru.mine.nu/ramaze
|
|
16
|
+
|
|
17
|
+
Please read the man page or `darcs help` for more information about updating
|
|
18
|
+
and creating your own patches.
|
|
19
|
+
This is at the moment the premier way to use Ramaze, since it is the way I use
|
|
20
|
+
it.
|
|
21
|
+
|
|
22
|
+
Some hints for the usage of Darcs.
|
|
23
|
+
|
|
24
|
+
* use require 'ramaze' from everywhere
|
|
25
|
+
|
|
26
|
+
add a file to your site_ruby named 'ramaze.rb'
|
|
27
|
+
the content should be: "require '/path/to/darcs/repo/ramaze/lib/ramaze'"
|
|
28
|
+
|
|
29
|
+
* get the latest version (from inside the ramaze-directory)
|
|
30
|
+
|
|
31
|
+
$ darcs pull
|
|
32
|
+
|
|
33
|
+
* record a patch
|
|
34
|
+
|
|
35
|
+
$ darcs record
|
|
36
|
+
|
|
37
|
+
* output your patches into a bundle ready to be mailed (compress it before
|
|
38
|
+
sending to make sure it arrives in the way you sent it)
|
|
39
|
+
|
|
40
|
+
$ darcs send -o ramaze_bundle
|
|
41
|
+
$ gzip -c ramaze_bundle > ramaze_bundle.gz
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Ramaze is a very simple and straight-forward web-framework.
|
|
2
|
+
The philosophy of it could be expressed in a mix of KISS and POLS, trying to
|
|
3
|
+
make simple things simple and complex things possible.
|
|
4
|
+
|
|
5
|
+
This of course is nothing new to anyone who knows some ruby, but is often
|
|
6
|
+
forgotten in a chase for new functionality and features. Ramaze only tries to
|
|
7
|
+
give you the ultimate tools, but you have to use them yourself to achieve
|
|
8
|
+
perfect custom-tailored results.
|
|
9
|
+
|
|
10
|
+
Another one of the goals during development of Ramaze was to make every part as
|
|
11
|
+
modular and therefor reuasable as possible, not only to provide a basic
|
|
12
|
+
understanding after the first glance, but also to make it as simple as possible
|
|
13
|
+
to reuse parts of the code.
|
|
14
|
+
|
|
15
|
+
The original purpose of Ramaze was to act as a kind of framework to build
|
|
16
|
+
web-frameworks, this was made obsolete by the introduction of rack, which
|
|
17
|
+
provides this feature at a better level without trying to enforce any structural
|
|
18
|
+
layout of the resulting framework.
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
There are some basic principles that Ramaze tries to follow:
|
|
2
|
+
|
|
3
|
+
* Test everything
|
|
4
|
+
|
|
5
|
+
What use is a wonderful application if it doesn't work?
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
* Document everything
|
|
9
|
+
|
|
10
|
+
Documentation is the glue between the code and the programmers brain
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
* Keep It Super Simple (KISS)
|
|
14
|
+
|
|
15
|
+
Most things should be understandable after reading them once
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
* Principle Of Least Surprise (POLS)
|
|
19
|
+
|
|
20
|
+
Going the way of ruby
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
* Modular design
|
|
24
|
+
|
|
25
|
+
Making it as simple as possible to extract parts
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
* Minimal dependencies
|
|
29
|
+
|
|
30
|
+
In case a dependency is not met use a simple fall-back instead
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
* Provide as many examples as possible
|
|
34
|
+
|
|
35
|
+
Examples are a superior way of getting a quick start into everything
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
* Open development
|
|
39
|
+
|
|
40
|
+
I happily accept all patches or feature-requests that you may have,
|
|
41
|
+
as long as they comply with these principles
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
There is a large number of people who made Ramaze possibe by their ongoing
|
|
2
|
+
efforts in the world of open source and by encouraging and helping me.
|
|
3
|
+
|
|
4
|
+
This list is by no means a full listing of all these people, but I try to
|
|
5
|
+
get a good coverage despite that.
|
|
6
|
+
|
|
7
|
+
I would like to thank:
|
|
8
|
+
|
|
9
|
+
* Yukihiro Matsumoto a.k.a matz
|
|
10
|
+
|
|
11
|
+
For giving the world Ruby and bringing fun back into programming.
|
|
12
|
+
|
|
13
|
+
* Zed Shawn a.k.a. zedas
|
|
14
|
+
|
|
15
|
+
For developing Mongrel, Ramaze started out as a simple Hello World based
|
|
16
|
+
on that awesome server.
|
|
17
|
+
|
|
18
|
+
* Christian Neukirchen a.k.a chris2
|
|
19
|
+
|
|
20
|
+
For building rack, which is just what the numerous web-developers had
|
|
21
|
+
anticipated and which will, with no doubt, change the world.
|
|
22
|
+
|
|
23
|
+
* Pistos
|
|
24
|
+
|
|
25
|
+
For continious encouragment and building the first real webpage on Ramaze.
|
|
26
|
+
His bugreports were invaluable.
|
|
27
|
+
|
|
28
|
+
* Jim Weirich
|
|
29
|
+
|
|
30
|
+
For Rake, which lifts off a lot of tasks from the shoulders of every
|
|
31
|
+
developer who uses it.
|
|
32
|
+
|
|
33
|
+
* Thomas Sawyer a.k.a Trans
|
|
34
|
+
|
|
35
|
+
Dragging me deep into the rabbit-hole and showing me how awesome Ruby
|
|
36
|
+
truely is through his work on facets, ratchets and tons of other projects.
|
|
37
|
+
|
|
38
|
+
* George Moschovitis a.k.a gmosx
|
|
39
|
+
|
|
40
|
+
For his tremendous efforts in the Nitro/Og framework, which is a source of
|
|
41
|
+
steady inspiration for Ramaze and brought me to Ruby in the first place.
|
|
42
|
+
|
|
43
|
+
* Rob Levin a.k.a. lilo
|
|
44
|
+
|
|
45
|
+
He founded the most excellent Freenode IRC-network, where the most important
|
|
46
|
+
channels for rubyists are located (as is #ramaze).
|
|
47
|
+
May he rest in peace.
|
|
48
|
+
|
|
49
|
+
* The guys (and gals) in the various channels on Freenode
|
|
50
|
+
|
|
51
|
+
As the people are way too many to be listed, here the channels that i call
|
|
52
|
+
my online home.
|
|
53
|
+
All the people in there deserve special thanks for getting me hooked to Ruby
|
|
54
|
+
and providing their help in a friendly and patient manner.
|
|
55
|
+
|
|
56
|
+
* #nitro
|
|
57
|
+
* #ruby-de
|
|
58
|
+
* #ruby-lang
|
|
59
|
+
* #rubyforce
|
|
@@ -0,0 +1,546 @@
|
|
|
1
|
+
= To-do List Tutorial
|
|
2
|
+
|
|
3
|
+
Welcome to our official tutorial, the mandatory to-do list.
|
|
4
|
+
I'm writing this while doing the steps to assure it will work for you.
|
|
5
|
+
|
|
6
|
+
The tutorial assumes that you have Ramaze installed already. The easiest way to
|
|
7
|
+
do that is `gem install ramaze`, for other ways of installation please see the
|
|
8
|
+
documentation at http://ramaze.rubyforge.org
|
|
9
|
+
|
|
10
|
+
Should you encounter any problems while doing this tutorial, this might either
|
|
11
|
+
be because Ramaze changed (which happens very often while it is still young)
|
|
12
|
+
or I actually made some mistake while writing it.
|
|
13
|
+
|
|
14
|
+
In either case it would make me (and all other poor fellows who happen to try
|
|
15
|
+
this tutorial) very happy if you could spare some time and report the issue
|
|
16
|
+
either on the Bug tracker at http://rubyforge.org/projects/ramaze or just
|
|
17
|
+
drop by on IRC ( irc.freenode.org channel: #ramaze ).
|
|
18
|
+
|
|
19
|
+
There is also a Mailing list available where you can keep yourself updated on
|
|
20
|
+
what is going on with little effort, it is also located on the project-page at
|
|
21
|
+
RubyForge.
|
|
22
|
+
|
|
23
|
+
Thanks in advance.
|
|
24
|
+
The author of the tutorial, Michael 'manveru' Fellinger
|
|
25
|
+
|
|
26
|
+
== First Step, Create
|
|
27
|
+
|
|
28
|
+
We are using `ramaze --create todolist` to create a new application.
|
|
29
|
+
Ramaze will then create the directory and fill it with a skeleton of a quite
|
|
30
|
+
sophisticated hello-world example out of which we will create the actual
|
|
31
|
+
to-do list.
|
|
32
|
+
|
|
33
|
+
So run:
|
|
34
|
+
|
|
35
|
+
$ ramaze --create todolist
|
|
36
|
+
|
|
37
|
+
done.
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
== Second Step, M, like Model
|
|
41
|
+
|
|
42
|
+
Ramaze comes at the moment only with a simple wrapper of the YAML::Store.
|
|
43
|
+
So we are going to base this on the tools available, you can just do the same
|
|
44
|
+
with your ORM or database of choice.
|
|
45
|
+
|
|
46
|
+
So first, edit the `src/model.rb`, it is filled with the definition of a simple
|
|
47
|
+
YAML::Store already, so we are just gonna modify it a bit to use our wrapper.
|
|
48
|
+
|
|
49
|
+
Instead of 'yaml/store' use:
|
|
50
|
+
|
|
51
|
+
require 'ramaze/store/default'
|
|
52
|
+
|
|
53
|
+
And further:
|
|
54
|
+
|
|
55
|
+
TodoList = Store::Default.new 'todolist.yaml'
|
|
56
|
+
|
|
57
|
+
To have a base to start off of, let's add some items as well.
|
|
58
|
+
|
|
59
|
+
{
|
|
60
|
+
'Laundry' => {:done => false},
|
|
61
|
+
'Wash dishes' => {:done => false},
|
|
62
|
+
|
|
63
|
+
}.each do |title, parameters|
|
|
64
|
+
TodoList[title] = parameters
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
== Third Step, V, like View
|
|
69
|
+
|
|
70
|
+
Now let's get our hands dirty and just edit the templates for our to-do list.
|
|
71
|
+
|
|
72
|
+
Start with editing `template/index.xhtml`, it is using the default templating
|
|
73
|
+
of Ramaze, called Ezamar.
|
|
74
|
+
|
|
75
|
+
Let's put some things in there, I'll explain the syntax as we go, it's quite
|
|
76
|
+
simple.
|
|
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>
|
|
94
|
+
|
|
95
|
+
I will assume that you are familiar with basic Ruby already, so let's
|
|
96
|
+
concentrate on the things new here.
|
|
97
|
+
|
|
98
|
+
<?r ?> defines an area of ruby-code. Late when the template is transformed into
|
|
99
|
+
pure Ruby it will be evaluated. We iterate over the TodoList model and pass the
|
|
100
|
+
title and parameters into a block. In that block we can just get the values
|
|
101
|
+
of title and status (which we define based on the parameters) displayed on the
|
|
102
|
+
page.
|
|
103
|
+
|
|
104
|
+
The whole Template would expand to something like this (only showing the
|
|
105
|
+
interesting part)
|
|
106
|
+
|
|
107
|
+
<ul>
|
|
108
|
+
<li>Laundry: not done</li>
|
|
109
|
+
<li>Wash dishes: not done</li>
|
|
110
|
+
</ul>
|
|
111
|
+
|
|
112
|
+
That wasn't too bad, huh?
|
|
113
|
+
|
|
114
|
+
Now, so we can get our instant pleasure of seeing the result of our (hard) work,
|
|
115
|
+
let's see how to start ramaze.
|
|
116
|
+
|
|
117
|
+
In the `todolist` directory run `ramaze`.
|
|
118
|
+
|
|
119
|
+
This will start an instance of Ramaze and run your application on it. You can
|
|
120
|
+
now access it by browsing to http://localhost:7000/
|
|
121
|
+
|
|
122
|
+
7000 is the default-port Ramaze will run on, to change it you can just run
|
|
123
|
+
`ramaze -p 7070` or similar. Also be sure to look at the output of
|
|
124
|
+
`ramaze --help` to see some other options.
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
== Fourth Step, C, like Controller
|
|
128
|
+
|
|
129
|
+
The last part of the MVC-paradigm is the Controller.
|
|
130
|
+
|
|
131
|
+
Wouldn't it be nice to have a way to add and remove items on our to-do list?
|
|
132
|
+
Editing the model every time would be quite tiresome and limited.
|
|
133
|
+
|
|
134
|
+
Well, come along, I'll introduce you to Controller.
|
|
135
|
+
|
|
136
|
+
In the way MVC is structured, the Controller provides the data in a nice way
|
|
137
|
+
for the View, removing all of the data-preparation and most of the logic from
|
|
138
|
+
the templates. This makes it firstly simple to change the fronted of your
|
|
139
|
+
application and secondly provides excellent ways of changing the complete
|
|
140
|
+
Structure of the Model or View independent from each other.
|
|
141
|
+
|
|
142
|
+
OK, enough of the theory, you will see the benefits in an instant. Go on and
|
|
143
|
+
edit the file `src/controller/main.rb`.
|
|
144
|
+
|
|
145
|
+
The contents of it are like following:
|
|
146
|
+
|
|
147
|
+
class MainController < Controller
|
|
148
|
+
def index
|
|
149
|
+
"Hello, World"
|
|
150
|
+
end
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
The only method right now is #index, with a simple and for the moment quite
|
|
154
|
+
useless "Hello, World". The relationship between the methods on the controller
|
|
155
|
+
and the templates is 1:1, so the method #index is combined with the template
|
|
156
|
+
`index.xhtml`. This combination is called an `action`.
|
|
157
|
+
|
|
158
|
+
Let's get back to editing and change the index-method to this:
|
|
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
|
|
165
|
+
end
|
|
166
|
+
end
|
|
167
|
+
|
|
168
|
+
This will take care of the logic inside the template, which now should be
|
|
169
|
+
changed to do following:
|
|
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>
|
|
189
|
+
|
|
190
|
+
The rest of the template can stay the same.
|
|
191
|
+
|
|
192
|
+
Now, if you browse to http://localhost:7000/ again you will not notice any
|
|
193
|
+
change, which is how it should be. The only change is that if there are no
|
|
194
|
+
Tasks it will say so.
|
|
195
|
+
|
|
196
|
+
Some things you should know:
|
|
197
|
+
|
|
198
|
+
* Instance-variables defined in the Controller are available in the View.
|
|
199
|
+
* The return-value of the Controller does not matter (in this case).
|
|
200
|
+
|
|
201
|
+
== Fifth Step, getting dynamic
|
|
202
|
+
|
|
203
|
+
We set out to build the ultimate to-do list, but there are still some things
|
|
204
|
+
missing. First off, we want to add new tasks, so let's get that done.
|
|
205
|
+
|
|
206
|
+
Add a link on the `template/index.xhtml` like this:
|
|
207
|
+
|
|
208
|
+
<h1>TodoList</h1>
|
|
209
|
+
<a href="/new">New Task</a>
|
|
210
|
+
|
|
211
|
+
Open a new file `template/new.xhtml` with a form to add a new task.
|
|
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>
|
|
226
|
+
|
|
227
|
+
We will not need a method for this on our controller, in fact, actions can
|
|
228
|
+
consist of either method and template or only one of them. The Controller
|
|
229
|
+
can act as a View and the View as Controller (if it returns a String and there
|
|
230
|
+
is no template).
|
|
231
|
+
|
|
232
|
+
If you try to use this form you will notice that we have not yet defined a way
|
|
233
|
+
to actually create the task.
|
|
234
|
+
|
|
235
|
+
You will get the default Ramaze error-page instead. Please take your time to
|
|
236
|
+
explore it and see how Ramaze reacted on the error.
|
|
237
|
+
|
|
238
|
+
It will show you the back trace and what state the application is in at the
|
|
239
|
+
moment, the request and response and the contents of the session. This is very
|
|
240
|
+
useful for debugging and development, you can provide your own set of
|
|
241
|
+
error-pages before going into production (or deactivate them fully) though.
|
|
242
|
+
|
|
243
|
+
OK, let's implement the action for #create, all we want to do is take the
|
|
244
|
+
requests parameters and create a new task for it, this looks like following on
|
|
245
|
+
your MainController.
|
|
246
|
+
|
|
247
|
+
def create
|
|
248
|
+
title = request['title']
|
|
249
|
+
TodoList[title] = {:done => false}
|
|
250
|
+
redirect R(self)
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
That's all folks!
|
|
254
|
+
|
|
255
|
+
we get the title from the request-object, put it into our TodoList as undone
|
|
256
|
+
and redirect back to the mapping of the current Controller ('/' in this case).
|
|
257
|
+
|
|
258
|
+
Now you can create as many tasks as you want, please don't get overworked ;)
|
|
259
|
+
|
|
260
|
+
|
|
261
|
+
== Sixth Step, open and close tasks
|
|
262
|
+
|
|
263
|
+
Since the nature of tasks is to be done eventually
|
|
264
|
+
we will need some way to mark it as done or open tasks again.
|
|
265
|
+
|
|
266
|
+
Jump into `template/index.xhtml` and do the following:
|
|
267
|
+
|
|
268
|
+
|
|
269
|
+
<?r @tasks.each do |title, status, toggle| ?>
|
|
270
|
+
<li>
|
|
271
|
+
#{title}: #{status} - #{toggle}
|
|
272
|
+
</li>
|
|
273
|
+
<?r end ?>
|
|
274
|
+
|
|
275
|
+
We added a new element here, `toggle`, the Controller should give us
|
|
276
|
+
a link to change the status corresponding to the status of the task, so off
|
|
277
|
+
we go and change the index method on the controller once again:
|
|
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' )
|
|
288
|
+
end
|
|
289
|
+
@tasks << [title, status, toggle]
|
|
290
|
+
end
|
|
291
|
+
@tasks.sort!
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
Wow, quite some new stuff here. Let me explain that in detail.
|
|
295
|
+
|
|
296
|
+
We first decide whether a task is done or not, then go on and provide a link to
|
|
297
|
+
toggle the status, link and R are both methods that help you do that.
|
|
298
|
+
the result will be something like:
|
|
299
|
+
|
|
300
|
+
<a href="/open/Wash+dishes">Close Task</a>
|
|
301
|
+
|
|
302
|
+
R actually is responsible to build the links href, for more information please
|
|
303
|
+
take a look at the RDoc for LinkHelper.
|
|
304
|
+
|
|
305
|
+
Also, you might have noticed that the tasks were changing order on every reload,
|
|
306
|
+
which is because we were using an Hash, which are per definition unsorted, so
|
|
307
|
+
now we use an array to hold our tasks and sort it.
|
|
308
|
+
|
|
309
|
+
Now back again to `template/index.xhtml` and change it as follows:
|
|
310
|
+
|
|
311
|
+
<?r @tasks.each do |title, status, toggle| ?>
|
|
312
|
+
<li>
|
|
313
|
+
#{title}: #{status} [ #{toggle} ]
|
|
314
|
+
</li>
|
|
315
|
+
<?r end ?>
|
|
316
|
+
|
|
317
|
+
As usual, the things not changed are omitted for terseness.
|
|
318
|
+
|
|
319
|
+
And as usual since the links for open and close don't lead anywhere, add the
|
|
320
|
+
corresponding methods to the Controller:
|
|
321
|
+
|
|
322
|
+
def open title
|
|
323
|
+
task_status title, false
|
|
324
|
+
redirect R(self)
|
|
325
|
+
end
|
|
326
|
+
|
|
327
|
+
def close title
|
|
328
|
+
task_status title, true
|
|
329
|
+
redirect R(self)
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
private
|
|
333
|
+
|
|
334
|
+
def task_status title, status
|
|
335
|
+
task = TodoList[title]
|
|
336
|
+
task[:done] = status
|
|
337
|
+
TodoList[title] = task
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
Oh, now what have we got here?
|
|
341
|
+
private declares that methods from here on are only to be used within the
|
|
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.
|
|
345
|
+
|
|
346
|
+
Another thing we have not encountered so far is that you can define your public
|
|
347
|
+
methods to take parameters on their own, they will be calculated from requests.
|
|
348
|
+
|
|
349
|
+
'/open/Wash+dishes'
|
|
350
|
+
|
|
351
|
+
will translate into:
|
|
352
|
+
|
|
353
|
+
open('Wash dishes')
|
|
354
|
+
|
|
355
|
+
Which in turn will call task_status('Wash dishes', false)
|
|
356
|
+
|
|
357
|
+
That's it, go on and try it :)
|
|
358
|
+
|
|
359
|
+
== Seventh Step, delete tasks
|
|
360
|
+
|
|
361
|
+
Well, creating, opening and closing work now, one of the things you will
|
|
362
|
+
consider is to delete a task permanently.
|
|
363
|
+
|
|
364
|
+
This is just two little changes away, so let's add the link for deletion in our
|
|
365
|
+
Controller:
|
|
366
|
+
|
|
367
|
+
delete = link( R( self, :delete, CGI.escape(title) ), :title => 'Delete' )
|
|
368
|
+
@tasks << [title, status, toggle, delete]
|
|
369
|
+
|
|
370
|
+
and an corresponding method while we're at it:
|
|
371
|
+
|
|
372
|
+
def delete title
|
|
373
|
+
TodoList.delete title
|
|
374
|
+
redirect R(self)
|
|
375
|
+
end
|
|
376
|
+
|
|
377
|
+
Now jumping to `template/index.xhtml` again, change it so it shows the link:
|
|
378
|
+
|
|
379
|
+
<?r @tasks.each do |title, status, toggle, delete| ?>
|
|
380
|
+
<li>
|
|
381
|
+
#{title}: #{status} [ #{toggle} | #{delete} ]
|
|
382
|
+
</li>
|
|
383
|
+
<?r end ?>
|
|
384
|
+
|
|
385
|
+
Voilà, you now have acquired the Certificate of Ramazeness, our accounting-
|
|
386
|
+
section will contact you within the next few days.
|
|
387
|
+
|
|
388
|
+
Just kidding, but that really are the basics, in the next few steps I will
|
|
389
|
+
explain some more advanced concepts of Ramaze and the templating.
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
== Eight Step, Elements
|
|
393
|
+
|
|
394
|
+
<Page></Page>
|
|
395
|
+
|
|
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
|
|
398
|
+
between to that Element.
|
|
399
|
+
|
|
400
|
+
Sounds weird?
|
|
401
|
+
|
|
402
|
+
Let us have a look at our templates, they all got some repetitive stuff, like:
|
|
403
|
+
|
|
404
|
+
<html>
|
|
405
|
+
<head>
|
|
406
|
+
<title>TodoList</title>
|
|
407
|
+
</head>
|
|
408
|
+
<body>
|
|
409
|
+
<h1>some title</h1>
|
|
410
|
+
</body>
|
|
411
|
+
</html>
|
|
412
|
+
|
|
413
|
+
How about replacing that with something short and nice:
|
|
414
|
+
|
|
415
|
+
<Page title="TodoList">
|
|
416
|
+
your other content
|
|
417
|
+
</Page>
|
|
418
|
+
|
|
419
|
+
Would be nice of course, and when you start having more templates it makes an
|
|
420
|
+
awful lot of sense to change the enclosing stuff in one place.
|
|
421
|
+
|
|
422
|
+
So let's apply DRY here as well.
|
|
423
|
+
|
|
424
|
+
Take a look at the `src/element/page.rb`
|
|
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
|
+
}
|
|
438
|
+
end
|
|
439
|
+
end
|
|
440
|
+
|
|
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.
|
|
444
|
+
|
|
445
|
+
Just adopt it to your liking, I'll just use the things we had in our templates
|
|
446
|
+
so far:
|
|
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
|
+
}
|
|
461
|
+
end
|
|
462
|
+
end
|
|
463
|
+
|
|
464
|
+
Please note that the @hash is filled with the things you pass as parameters
|
|
465
|
+
to tye Page-tag.
|
|
466
|
+
|
|
467
|
+
And let's change our templates as well.
|
|
468
|
+
|
|
469
|
+
First the `template/index.xhtml`
|
|
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>
|
|
485
|
+
|
|
486
|
+
and the `template/new.xhtml`
|
|
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>
|
|
495
|
+
|
|
496
|
+
Alright, now just go and look at the result in the browser, try changing
|
|
497
|
+
the things inside the Element and look at how it behaves.
|
|
498
|
+
|
|
499
|
+
|
|
500
|
+
== Ninth Step, Prettify
|
|
501
|
+
|
|
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
|
+
|
|
504
|
+
So, from what we have right now:
|
|
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>
|
|
513
|
+
|
|
514
|
+
To something like this:
|
|
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>
|
|
526
|
+
|
|
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
|
+
|
|
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
|
+
|
|
541
|
+
That looks quite a bit nicer, right?
|
|
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.
|
|
543
|
+
|
|
544
|
+
I will leave this as an exercise to the reader.
|
|
545
|
+
|
|
546
|
+
To be continued...
|