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.
Files changed (193) hide show
  1. data/Rakefile +52 -19
  2. data/bin/ramaze +19 -6
  3. data/doc/CHANGELOG +33 -0
  4. data/doc/COPYING +1 -1
  5. data/doc/FAQ +92 -0
  6. data/doc/GPL +340 -0
  7. data/doc/INSTALL +34 -0
  8. data/doc/ProjectInfo +53 -0
  9. data/doc/README +187 -110
  10. data/doc/readme_chunks/appendix.txt +13 -0
  11. data/doc/readme_chunks/examples.txt +38 -0
  12. data/doc/readme_chunks/features.txt +82 -0
  13. data/doc/readme_chunks/getting_help.txt +5 -0
  14. data/doc/readme_chunks/getting_started.txt +18 -0
  15. data/doc/readme_chunks/installing.txt +41 -0
  16. data/doc/readme_chunks/introduction.txt +18 -0
  17. data/doc/readme_chunks/principles.txt +41 -0
  18. data/doc/readme_chunks/thanks.txt +59 -0
  19. data/doc/tutorial/todolist.txt +546 -0
  20. data/examples/blog/main.rb +1 -1
  21. data/examples/blog/src/controller.rb +13 -11
  22. data/examples/blog/src/element.rb +11 -6
  23. data/examples/blog/src/model.rb +8 -23
  24. data/examples/blog/template/edit.xhtml +3 -1
  25. data/examples/blog/template/index.xhtml +4 -4
  26. data/examples/caching.rb +4 -4
  27. data/examples/element.rb +10 -7
  28. data/examples/hello.rb +3 -4
  29. data/examples/simple.rb +5 -3
  30. data/examples/templates/template/external.amrita +19 -0
  31. data/examples/templates/template/{external.rmze → external.zmr} +2 -2
  32. data/examples/templates/template_amrita2.rb +48 -0
  33. data/examples/templates/template_erubis.rb +5 -2
  34. data/examples/templates/{template_ramaze.rb → template_ezamar.rb} +13 -7
  35. data/examples/templates/template_haml.rb +4 -1
  36. data/examples/templates/template_liquid.rb +2 -1
  37. data/examples/templates/template_markaby.rb +2 -1
  38. data/examples/todolist/conf/benchmark.yaml +35 -0
  39. data/examples/todolist/conf/debug.yaml +34 -0
  40. data/examples/todolist/conf/live.yaml +33 -0
  41. data/examples/todolist/conf/silent.yaml +31 -0
  42. data/examples/todolist/conf/stage.yaml +33 -0
  43. data/examples/todolist/main.rb +18 -0
  44. data/examples/todolist/public/404.jpg +0 -0
  45. data/examples/todolist/public/css/coderay.css +105 -0
  46. data/examples/todolist/public/css/ramaze_error.css +42 -0
  47. data/{lib/proto → examples/todolist}/public/error.xhtml +0 -0
  48. data/examples/todolist/public/favicon.ico +0 -0
  49. data/examples/todolist/public/js/jquery.js +1923 -0
  50. data/examples/todolist/public/ramaze.png +0 -0
  51. data/examples/todolist/src/controller/main.rb +56 -0
  52. data/examples/todolist/src/element/page.rb +26 -0
  53. data/examples/todolist/src/model.rb +14 -0
  54. data/examples/todolist/template/index.xhtml +17 -0
  55. data/examples/todolist/template/new.xhtml +7 -0
  56. data/examples/todolist/todolist.db +9 -0
  57. data/examples/whywiki/main.rb +3 -8
  58. data/examples/whywiki/template/show.xhtml +4 -0
  59. data/lib/proto/public/error.zmr +77 -0
  60. data/lib/proto/src/controller/main.rb +2 -1
  61. data/lib/proto/src/element/page.rb +2 -1
  62. data/lib/proto/src/model.rb +3 -2
  63. data/lib/ramaze.rb +7 -9
  64. data/lib/ramaze/adapter.rb +51 -0
  65. data/lib/ramaze/adapter/cgi.rb +23 -0
  66. data/lib/ramaze/adapter/fcgi.rb +22 -0
  67. data/lib/ramaze/adapter/mongrel.rb +7 -86
  68. data/lib/ramaze/adapter/webrick.rb +14 -133
  69. data/lib/ramaze/cache/memcached.rb +6 -0
  70. data/lib/ramaze/cache/yaml_store.rb +3 -1
  71. data/lib/ramaze/controller.rb +292 -2
  72. data/lib/ramaze/dispatcher.rb +85 -213
  73. data/lib/ramaze/error.rb +10 -0
  74. data/lib/ramaze/global.rb +8 -0
  75. data/lib/ramaze/helper/aspect.rb +30 -7
  76. data/lib/ramaze/helper/auth.rb +16 -9
  77. data/lib/ramaze/helper/cache.rb +40 -35
  78. data/lib/ramaze/helper/feed.rb +1 -1
  79. data/lib/ramaze/helper/flash.rb +34 -0
  80. data/lib/ramaze/helper/link.rb +8 -2
  81. data/lib/ramaze/helper/openid.rb +63 -0
  82. data/lib/ramaze/helper/redirect.rb +12 -11
  83. data/lib/ramaze/helper/stack.rb +5 -7
  84. data/lib/ramaze/inform.rb +12 -1
  85. data/lib/ramaze/snippets/kernel/aquire.rb +1 -1
  86. data/lib/ramaze/snippets/kernel/{self_method.rb → method.rb} +3 -18
  87. data/lib/ramaze/snippets/kernel/{rescue_require.rb → pretty_inspect.rb} +7 -6
  88. data/lib/ramaze/snippets/method/name.rb +22 -0
  89. data/lib/ramaze/snippets/{kernel → ramaze}/autoreload.rb +0 -0
  90. data/lib/ramaze/snippets/ramaze/caller_info.rb +14 -0
  91. data/lib/ramaze/snippets/{kernel → ramaze}/caller_lines.rb +3 -10
  92. data/lib/ramaze/snippets/rdoc/usage_no_exit.rb +49 -23
  93. data/lib/ramaze/snippets/string/DIVIDE.rb +0 -1
  94. data/lib/ramaze/store/default.rb +58 -2
  95. data/lib/ramaze/store/yaml.rb +161 -0
  96. data/lib/ramaze/template.rb +27 -86
  97. data/lib/ramaze/template/amrita2.rb +14 -19
  98. data/lib/ramaze/template/erubis.rb +15 -38
  99. data/lib/ramaze/template/ezamar.rb +100 -0
  100. data/lib/ramaze/template/ezamar/element.rb +166 -0
  101. data/lib/ramaze/template/ezamar/engine.rb +124 -0
  102. data/lib/ramaze/template/ezamar/morpher.rb +155 -0
  103. data/lib/ramaze/template/haml.rb +16 -43
  104. data/lib/ramaze/template/liquid.rb +11 -51
  105. data/lib/ramaze/template/markaby.rb +44 -42
  106. data/lib/ramaze/tool/mime.rb +18 -0
  107. data/lib/ramaze/tool/mime_types.yaml +615 -0
  108. data/lib/ramaze/trinity/request.rb +20 -196
  109. data/lib/ramaze/trinity/response.rb +4 -33
  110. data/lib/ramaze/trinity/session.rb +150 -72
  111. data/lib/ramaze/version.rb +1 -1
  112. data/spec/adapter_spec.rb +20 -0
  113. data/spec/public/favicon.ico +0 -0
  114. data/spec/public/ramaze.png +0 -0
  115. data/spec/public/test_download.css +141 -0
  116. data/spec/{tc_request.rb → request_tc_helper.rb} +45 -21
  117. data/spec/spec_all.rb +77 -34
  118. data/spec/spec_helper.rb +8 -157
  119. data/spec/spec_helper_context.rb +72 -0
  120. data/spec/spec_helper_requester.rb +52 -0
  121. data/spec/spec_helper_simple_http.rb +433 -0
  122. data/spec/tc_adapter_mongrel.rb +3 -15
  123. data/spec/tc_adapter_webrick.rb +4 -14
  124. data/spec/tc_cache.rb +3 -5
  125. data/spec/tc_controller.rb +22 -12
  126. data/spec/tc_dependencies.rb +13 -0
  127. data/spec/tc_element.rb +8 -7
  128. data/spec/tc_error.rb +13 -7
  129. data/spec/tc_global.rb +16 -18
  130. data/spec/tc_helper_aspect.rb +2 -4
  131. data/spec/tc_helper_auth.rb +15 -14
  132. data/spec/tc_helper_cache.rb +5 -7
  133. data/spec/tc_helper_feed.rb +0 -2
  134. data/spec/tc_helper_flash.rb +103 -0
  135. data/spec/tc_helper_form.rb +4 -6
  136. data/spec/tc_helper_link.rb +1 -3
  137. data/spec/tc_helper_redirect.rb +23 -8
  138. data/spec/tc_helper_stack.rb +31 -15
  139. data/spec/tc_morpher.rb +1 -3
  140. data/spec/tc_params.rb +48 -7
  141. data/spec/tc_request_mongrel.rb +9 -0
  142. data/spec/tc_request_webrick.rb +5 -0
  143. data/spec/tc_session.rb +41 -25
  144. data/spec/tc_store.rb +55 -6
  145. data/spec/tc_store_yaml.rb +71 -0
  146. data/spec/tc_template_amrita2.rb +3 -3
  147. data/spec/tc_template_erubis.rb +2 -3
  148. data/spec/{tc_template_ramaze.rb → tc_template_ezamar.rb} +15 -5
  149. data/spec/tc_template_haml.rb +4 -3
  150. data/spec/tc_template_liquid.rb +3 -4
  151. data/spec/tc_template_markaby.rb +4 -6
  152. data/spec/tc_tidy.rb +1 -3
  153. data/spec/template/amrita2/{data.html → data.amrita} +0 -0
  154. data/spec/template/amrita2/{index.html → index.amrita} +0 -0
  155. data/spec/template/amrita2/{sum.html → sum.amrita} +0 -0
  156. data/spec/template/ezamar/another/long/action.zmr +1 -0
  157. data/spec/template/ezamar/combined.zmr +1 -0
  158. data/spec/template/{ramaze/file_only.rmze → ezamar/file_only.zmr} +0 -0
  159. data/spec/template/{ramaze/index.rmze → ezamar/index.zmr} +0 -0
  160. data/spec/template/{ramaze/nested.rmze → ezamar/nested.zmr} +0 -0
  161. data/spec/template/ezamar/some__long__action.zmr +1 -0
  162. data/spec/template/{ramaze/sum.rmze → ezamar/sum.zmr} +0 -0
  163. metadata +181 -123
  164. data/doc/allison/LICENSE +0 -184
  165. data/doc/allison/README +0 -37
  166. data/doc/allison/allison.css +0 -300
  167. data/doc/allison/allison.gif +0 -0
  168. data/doc/allison/allison.js +0 -307
  169. data/doc/allison/allison.rb +0 -287
  170. data/doc/allison/cache/BODY +0 -588
  171. data/doc/allison/cache/CLASS_INDEX +0 -4
  172. data/doc/allison/cache/CLASS_PAGE +0 -1
  173. data/doc/allison/cache/FILE_INDEX +0 -4
  174. data/doc/allison/cache/FILE_PAGE +0 -1
  175. data/doc/allison/cache/FONTS +0 -1
  176. data/doc/allison/cache/FR_INDEX_BODY +0 -1
  177. data/doc/allison/cache/IMGPATH +0 -1
  178. data/doc/allison/cache/INDEX +0 -1
  179. data/doc/allison/cache/JAVASCRIPT +0 -307
  180. data/doc/allison/cache/METHOD_INDEX +0 -4
  181. data/doc/allison/cache/METHOD_LIST +0 -1
  182. data/doc/allison/cache/SRC_PAGE +0 -1
  183. data/doc/allison/cache/STYLE +0 -322
  184. data/doc/allison/cache/URL +0 -1
  185. data/doc/changes.txt +0 -2021
  186. data/doc/changes.xml +0 -2024
  187. data/lib/ramaze/snippets/kernel/silently.rb +0 -13
  188. data/lib/ramaze/snippets/thread/deadQUESTIONMARK.rb +0 -11
  189. data/lib/ramaze/template/haml/actionview_stub.rb +0 -20
  190. data/lib/ramaze/template/ramaze.rb +0 -177
  191. data/lib/ramaze/template/ramaze/element.rb +0 -166
  192. data/lib/ramaze/template/ramaze/morpher.rb +0 -156
  193. 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,5 @@
1
+ For help you can:
2
+
3
+ - Visit us in the channel #ramaze on irc.freenode.net
4
+
5
+ - Join the Mailinglist at http://ramaze.rubyforge.org
@@ -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...