sws 0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (158) hide show
  1. data/doc/DOC.otl +34 -0
  2. data/doc/Makefile +13 -0
  3. data/doc/architecture.dia +0 -0
  4. data/doc/docbook/architecture.png +0 -0
  5. data/doc/docbook/concepts.docbook +474 -0
  6. data/doc/docbook/installation.docbook +57 -0
  7. data/doc/docbook/introduction.docbook +130 -0
  8. data/doc/docbook/sws_manual.docbook +35 -0
  9. data/doc/docbook/todo.docbook +38 -0
  10. data/doc/docbook/tutorial.docbook +594 -0
  11. data/examples/README +1 -0
  12. data/examples/addressbook/CardBrowse/CardBrowse.html +43 -0
  13. data/examples/addressbook/CardBrowse/CardBrowse.rb +65 -0
  14. data/examples/addressbook/CardBrowse/CardBrowse.sws +92 -0
  15. data/examples/addressbook/Login/LoginPage.html +12 -0
  16. data/examples/addressbook/Login/LoginPage.rb +19 -0
  17. data/examples/addressbook/Login/LoginPage.sws +15 -0
  18. data/examples/addressbook/README +1 -0
  19. data/examples/addressbook/addressbook.rb +70 -0
  20. data/examples/addressbook/application.yaml +8 -0
  21. data/examples/addressbook/db.yaml +7 -0
  22. data/examples/component_demo/CheckBoxDemo/CheckBoxDemo.html +11 -0
  23. data/examples/component_demo/CheckBoxDemo/CheckBoxDemo.rb +21 -0
  24. data/examples/component_demo/CheckBoxDemo/CheckBoxDemo.sws +25 -0
  25. data/examples/component_demo/ComponentDemo.rb +21 -0
  26. data/examples/component_demo/ConditionalDemo/ConditionalDemo.html +18 -0
  27. data/examples/component_demo/ConditionalDemo/ConditionalDemo.rb +2 -0
  28. data/examples/component_demo/ConditionalDemo/ConditionalDemo.sws +22 -0
  29. data/examples/component_demo/FileUploadDemo/FileUploadDemo.html +10 -0
  30. data/examples/component_demo/FileUploadDemo/FileUploadDemo.rb +9 -0
  31. data/examples/component_demo/FileUploadDemo/FileUploadDemo.sws +33 -0
  32. data/examples/component_demo/FormFieldsDemo/FormFieldsDemo.html +12 -0
  33. data/examples/component_demo/FormFieldsDemo/FormFieldsDemo.rb +21 -0
  34. data/examples/component_demo/FormFieldsDemo/FormFieldsDemo.sws +40 -0
  35. data/examples/component_demo/FormListsDemo/FormListsDemo.html +11 -0
  36. data/examples/component_demo/FormListsDemo/FormListsDemo.rb +37 -0
  37. data/examples/component_demo/FormListsDemo/FormListsDemo.sws +47 -0
  38. data/examples/component_demo/GenericDemo/GenericDemo.html +4 -0
  39. data/examples/component_demo/GenericDemo/GenericDemo.rb +2 -0
  40. data/examples/component_demo/GenericDemo/GenericDemo.sws +10 -0
  41. data/examples/component_demo/HyperlinkDemo/HyperlinkDemo.html +8 -0
  42. data/examples/component_demo/HyperlinkDemo/HyperlinkDemo.rb +20 -0
  43. data/examples/component_demo/HyperlinkDemo/HyperlinkDemo.sws +19 -0
  44. data/examples/component_demo/ImageLinkDemo/ImageLinkDemo.html +11 -0
  45. data/examples/component_demo/ImageLinkDemo/ImageLinkDemo.rb +2 -0
  46. data/examples/component_demo/ImageLinkDemo/ImageLinkDemo.sws +14 -0
  47. data/examples/component_demo/PageWrapper/PageWrapper.html +23 -0
  48. data/examples/component_demo/PageWrapper/PageWrapper.rb +2 -0
  49. data/examples/component_demo/PageWrapper/PageWrapper.sws +42 -0
  50. data/examples/component_demo/README +1 -0
  51. data/examples/component_demo/RepetitionDemo/RepetitionDemo.html +13 -0
  52. data/examples/component_demo/RepetitionDemo/RepetitionDemo.rb +19 -0
  53. data/examples/component_demo/RepetitionDemo/RepetitionDemo.sws +20 -0
  54. data/examples/component_demo/StringDemo/StringDemo.html +5 -0
  55. data/examples/component_demo/StringDemo/StringDemo.rb +16 -0
  56. data/examples/component_demo/StringDemo/StringDemo.sws +14 -0
  57. data/examples/component_demo/application.yaml +28 -0
  58. data/examples/component_demo/poweredby.jpg +0 -0
  59. data/examples/component_demo/style.css +1 -0
  60. data/examples/movies/Menu/Menu.html +3 -0
  61. data/examples/movies/Menu/Menu.rb +7 -0
  62. data/examples/movies/Menu/Menu.sws +7 -0
  63. data/examples/movies/MovieBrowse/MovieBrowse.html +68 -0
  64. data/examples/movies/MovieBrowse/MovieBrowse.rb +178 -0
  65. data/examples/movies/MovieBrowse/MovieBrowse.sws +127 -0
  66. data/examples/movies/README +1 -0
  67. data/examples/movies/UserBrowse/UserBrowse.html +50 -0
  68. data/examples/movies/UserBrowse/UserBrowse.rb +69 -0
  69. data/examples/movies/UserBrowse/UserBrowse.sws +49 -0
  70. data/examples/movies/application.yaml +11 -0
  71. data/examples/movies/da.rb +36 -0
  72. data/examples/movies/dbmovies.rb +44 -0
  73. data/examples/movies/frameworks/TestFramework/framework.yaml +4 -0
  74. data/examples/movies/frameworks/TestFramework/resources/im1.jpg +0 -0
  75. data/examples/movies/images/pbr1b.jpg +0 -0
  76. data/examples/movies/movies.rb +28 -0
  77. data/examples/movies/movies.sds +119 -0
  78. data/examples/movies/movies.sqlite +0 -0
  79. data/examples/movies/movies_mysql.sql +28 -0
  80. data/examples/movies/movies_postgres.sql +27 -0
  81. data/examples/movies/movies_sqlite.sql +28 -0
  82. data/lib/sws.rb +89 -0
  83. data/lib/sws/Core/components/CheckBox/CheckBox.api +5 -0
  84. data/lib/sws/Core/components/CheckBox/CheckBox.rb +45 -0
  85. data/lib/sws/Core/components/CheckBoxList/CheckBoxList.api +13 -0
  86. data/lib/sws/Core/components/CheckBoxList/CheckBoxList.rb +54 -0
  87. data/lib/sws/Core/components/Conditional/Conditional.api +3 -0
  88. data/lib/sws/Core/components/Conditional/Conditional.html +1 -0
  89. data/lib/sws/Core/components/Conditional/Conditional.rb +39 -0
  90. data/lib/sws/Core/components/Conditional/Conditional.sws +2 -0
  91. data/lib/sws/Core/components/Content/Content.rb +18 -0
  92. data/lib/sws/Core/components/ExceptionPage/ExceptionPage.html +13 -0
  93. data/lib/sws/Core/components/ExceptionPage/ExceptionPage.rb +18 -0
  94. data/lib/sws/Core/components/ExceptionPage/ExceptionPage.sws +16 -0
  95. data/lib/sws/Core/components/FileUpload/FileUpload.api +16 -0
  96. data/lib/sws/Core/components/FileUpload/FileUpload.rb +62 -0
  97. data/lib/sws/Core/components/Form/Form.api +9 -0
  98. data/lib/sws/Core/components/Form/Form.html +3 -0
  99. data/lib/sws/Core/components/Form/Form.rb +55 -0
  100. data/lib/sws/Core/components/Form/Form.sws +12 -0
  101. data/lib/sws/Core/components/GenericContainer/GenericContainer.api +10 -0
  102. data/lib/sws/Core/components/GenericContainer/GenericContainer.html +1 -0
  103. data/lib/sws/Core/components/GenericContainer/GenericContainer.rb +39 -0
  104. data/lib/sws/Core/components/GenericContainer/GenericContainer.sws +12 -0
  105. data/lib/sws/Core/components/GenericElement/GenericElement.api +10 -0
  106. data/lib/sws/Core/components/GenericElement/GenericElement.rb +34 -0
  107. data/lib/sws/Core/components/HiddenField/HiddenField.api +7 -0
  108. data/lib/sws/Core/components/HiddenField/HiddenField.rb +37 -0
  109. data/lib/sws/Core/components/Hyperlink/Hyperlink.api +13 -0
  110. data/lib/sws/Core/components/Hyperlink/Hyperlink.html +1 -0
  111. data/lib/sws/Core/components/Hyperlink/Hyperlink.rb +102 -0
  112. data/lib/sws/Core/components/Hyperlink/Hyperlink.sws +12 -0
  113. data/lib/sws/Core/components/Image/Image.api +11 -0
  114. data/lib/sws/Core/components/Image/Image.rb +49 -0
  115. data/lib/sws/Core/components/ImageButton/ImageButton.api +16 -0
  116. data/lib/sws/Core/components/ImageButton/ImageButton.rb +76 -0
  117. data/lib/sws/Core/components/Link/Link.api +11 -0
  118. data/lib/sws/Core/components/Link/Link.rb +39 -0
  119. data/lib/sws/Core/components/PasswordField/PasswordField.api +7 -0
  120. data/lib/sws/Core/components/PasswordField/PasswordField.rb +41 -0
  121. data/lib/sws/Core/components/RadioButton/RadioButton.api +7 -0
  122. data/lib/sws/Core/components/RadioButton/RadioButton.rb +44 -0
  123. data/lib/sws/Core/components/RadioButtonList/RadioButtonList.api +20 -0
  124. data/lib/sws/Core/components/RadioButtonList/RadioButtonList.rb +76 -0
  125. data/lib/sws/Core/components/Repetition/Repetition.api +10 -0
  126. data/lib/sws/Core/components/Repetition/Repetition.html +1 -0
  127. data/lib/sws/Core/components/Repetition/Repetition.rb +137 -0
  128. data/lib/sws/Core/components/Repetition/Repetition.sws +2 -0
  129. data/lib/sws/Core/components/ResetButton/ResetButton.api +5 -0
  130. data/lib/sws/Core/components/ResetButton/ResetButton.rb +28 -0
  131. data/lib/sws/Core/components/Select/Select.api +24 -0
  132. data/lib/sws/Core/components/Select/Select.rb +57 -0
  133. data/lib/sws/Core/components/String/String.api +5 -0
  134. data/lib/sws/Core/components/String/String.rb +28 -0
  135. data/lib/sws/Core/components/SubmitButton/SubmitButton.api +6 -0
  136. data/lib/sws/Core/components/SubmitButton/SubmitButton.rb +53 -0
  137. data/lib/sws/Core/components/TextArea/TextArea.api +9 -0
  138. data/lib/sws/Core/components/TextArea/TextArea.rb +28 -0
  139. data/lib/sws/Core/components/TextField/TextField.api +9 -0
  140. data/lib/sws/Core/components/TextField/TextField.rb +46 -0
  141. data/lib/sws/Core/framework.yaml +25 -0
  142. data/lib/sws/JSComponents/components/JSMenu/JSMenu.api +5 -0
  143. data/lib/sws/JSComponents/components/JSMenu/JSMenu.html +58 -0
  144. data/lib/sws/JSComponents/components/JSMenu/JSMenu.rb +34 -0
  145. data/lib/sws/JSComponents/components/JSMenu/JSMenu.sws +37 -0
  146. data/lib/sws/JSComponents/framework.yaml +3 -0
  147. data/lib/sws/adaptor.rb +334 -0
  148. data/lib/sws/application.rb +604 -0
  149. data/lib/sws/component.rb +656 -0
  150. data/lib/sws/cookie.rb +27 -0
  151. data/lib/sws/direct_action.rb +38 -0
  152. data/lib/sws/extensions.rb +49 -0
  153. data/lib/sws/parsers.rb +374 -0
  154. data/lib/sws/request.rb +308 -0
  155. data/lib/sws/response.rb +70 -0
  156. data/lib/sws/session.rb +195 -0
  157. data/lib/sws/slot.rb +198 -0
  158. metadata +263 -0
@@ -0,0 +1,34 @@
1
+ Introduction
2
+ What is SWS
3
+ Short desciption
4
+ General concepts & advantages
5
+ License
6
+ Installation
7
+ Where to get
8
+ Installation instructions
9
+ Upgrading from earlier versions
10
+ What's new
11
+ Concepts
12
+ Architecture
13
+ Picture?
14
+ Application
15
+ Configuration file
16
+ Adaptors
17
+ Request handlers
18
+ Session
19
+ Resources
20
+ Frameworks
21
+ Configuration file
22
+ Components
23
+ Basics
24
+ Files
25
+ Slots
26
+ Content
27
+ Functionality
28
+ Tutorial
29
+ : Need a simple example application (without db)
30
+ Creating application
31
+ Creating first component
32
+ Navigation
33
+ Bugs & limitations
34
+ Future versions
@@ -0,0 +1,13 @@
1
+ all: rdoc docbook-html docbook-txt docbook-pdf
2
+
3
+ rdoc: ../lib/sws/*rb
4
+ rdoc18 -o rdoc -T kilmer ../lib/sws.rb ../lib/sws/*rb ../lib/sws/Core/components/*/*rb
5
+
6
+ docbook-html: docbook/*docbook
7
+ docbook2html -o html docbook/sws_manual.docbook
8
+
9
+ docbook-txt: docbook/*docbook
10
+ docbook2txt -o txt docbook/sws_manual.docbook
11
+
12
+ docbook-pdf: docbook/*docbook
13
+ docbook2pdf -o pdf docbook/sws_manual.docbook
Binary file
@@ -0,0 +1,474 @@
1
+ <chapter id="concepts">
2
+ <title>Concepts</title>
3
+
4
+ <sect1 id="concepts-architecture">
5
+ <title>SWS Application architecture</title>
6
+
7
+ <para>SWS Application architecture is presented on the figure 3-1.
8
+ Application receives HTTP request from client (usually a WWW browser).
9
+ The part of the program responsible for reading the HTTP request and transforming it into <ulink url="../rdoc/classes/SWS/Request.html">SWS::Request</ulink> objects is called the <link linkend="concepts-adaptor">adaptor</link>.
10
+ The request is then passed by application to proper <link linkend="concepts-handlers">request handler</link>, which either creates a <link linkend="concepts-component">Component</link> instance used to generate <ulink url="../rdoc/classes/SWS/Response.html">SWS::Response</ulink> object or generates the Response object itself.
11
+ Component collaborates with <ulink url="../rdoc/classes/SWS/TemplateParser.html">TemplateParser</ulink> and <ulink url="../rdoc/classes/SWS/DefinitionParser.html">DefinitionParser</ulink> objects, which retrieve component information from .html, .sws and .api files.
12
+ Generated SWS::Response object is returned back to adaptor, which in turn sends HTTP response to the client.
13
+
14
+ <figure><title>SWS Application architecture</title>
15
+ <graphic fileref="architecture.png" format="PNG">
16
+ </figure>
17
+
18
+ </para>
19
+ </sect1>
20
+
21
+ <sect1 id="concepts-application">
22
+ <title>Application object</title>
23
+
24
+ <sect2 id="concepts-application-overview">
25
+ <title>Application overview</title>
26
+ <para>Each SWS application is build around an <ulink url="../rdoc/classes/SWS/Application.html">Application</ulink> object, which can be retrieved using <ulink url="../rdoc/classes/SWS/Application.html#M000083.html">SWS::Application.instance()</ulink> method. The Application object provides a WWW server and fundamental <link linkend="concepts-handlers">request handling</link> functionality. It can also contain some global (independent of particular request) variables. You should create your subclass of SWS::Application, create an instance of it and use <ulink url="../rdoc/classes/SWS/Application.html#M000084.html">run</ulink> method to start the application.</para>
27
+ </sect2>
28
+
29
+ <sect2 id="concepts-application-config">
30
+ <title>Application config file</title>
31
+
32
+ <para>Each SWS application must contain a config file named <replaceable>application.yaml</replaceable>. The file is a regular <ulink url="http://yaml4r.sourceforge.net/">YAML</ulink> file containing a single Hash with following elements:
33
+ </para>
34
+
35
+ <variablelist>
36
+ <title>Application config file elements</title>
37
+
38
+ <varlistentry><term>components</term>
39
+ <listitem><para>
40
+ A Hash of <wordasword>component name</wordasword> => <wordasword>component directory</wordasword> (relative to application directory) pairs.
41
+ </para></listitem>
42
+ </varlistentry>
43
+
44
+ <varlistentry><term>frameworks</term>
45
+ <listitem><para>
46
+ A Hash of <wordasword>framework name</wordasword> => <wordasword>framework directory</wordasword> (relative to application directory) pairs. Note the <wordasword>SYSTEM</wordasword> word is replaced with default (system) locations - currently the same as the <wordasword>$LOAD_PATH</wordasword> value.
47
+ </para></listitem>
48
+ </varlistentry>
49
+
50
+ <varlistentry><term>resources</term>
51
+ <listitem><para>
52
+ A Hash of <wordasword>resources name</wordasword> => Hash containing resource parameters (currently containing resource filename - relative to framework directory - and mime type) pairs.
53
+ </para></listitem>
54
+ </varlistentry>
55
+
56
+ <varlistentry><term>adaptor_class</term>
57
+ <listitem><para>
58
+ The name of <link linkend="concepts-adaptor">adaptor</link> class to use. Defaults to <ulink url="../rdoc/classes/SWS/Adaptor/Standalone.html">SWS::Adaptor::Standalone</ulink>.
59
+ </para></listitem>
60
+ </varlistentry>
61
+
62
+ <varlistentry><term>session_class</term>
63
+ <listitem><para>
64
+ The name of <link linkend="concepts-session">session</link> class to use. Defaults to <ulink url="../rdoc/classes/SWS/Session.html">SWS::Session</ulink>.
65
+ </para></listitem>
66
+ </varlistentry>
67
+
68
+ <varlistentry><term>default_direct_action_class</term>
69
+ <listitem><para>
70
+ The name of default DirectAction class. Defaults to <ulink url="../rdoc/classes/SWS/DirectAction.html">SWS::DirectAction</ulink>.
71
+ </para></listitem>
72
+ </varlistentry>
73
+
74
+ <varlistentry><term>default_component_class</term>
75
+ <listitem><para>
76
+ The name of the component class used for new sessions (and invalid request URLs). Defaults to <replaceable>Main</replaceable>.
77
+ </para></listitem>
78
+ </varlistentry>
79
+
80
+ <varlistentry><term>default_encoding</term>
81
+ <listitem><para>
82
+ Default encoding for components. Defaults to <replaceable>"iso-8859-1"</replaceable>.
83
+ </para></listitem>
84
+ </varlistentry>
85
+
86
+ <varlistentry><term>exception_component_class</term>
87
+ <listitem><para>
88
+ Component class to be used to create exception pages. Defaults to <ulink url="../rdoc/classes/SWS/ExceptionPage.html">SWS::ExceptionPage</ulink>.
89
+ </para></listitem>
90
+ </varlistentry>
91
+
92
+ <varlistentry><term>max_sessions</term>
93
+ <listitem><para>
94
+ Maximum number of sessions to be tracked. When this number is exceeded, the following sessions will be refused or the Last Recently Used session will be deleted (depending on the <wordasword>refuse_sessions</wordasword> parameter). Defaults to 100.
95
+ </para></listitem>
96
+ </varlistentry>
97
+
98
+ <varlistentry><term>refuse_sessions</term>
99
+ <listitem><para>
100
+ Policy for handling incoming sessions when the limit has been reached. If <token>true</token>, new session will be refused; if <token>false</token>, Last Recently Used session will be deleted and new session will be handled regularly. Defaults to <token>false</token>.
101
+ </para></listitem>
102
+ </varlistentry>
103
+
104
+ </variablelist>
105
+
106
+ <para>
107
+ All elements of the config file are optional (as they all have default values), but the config file must exist and be a valid YAML file. Besides, there is not much sense in creating an application with empty config file - usually you may at least want to define components and load Core frameowork.
108
+ </para>
109
+
110
+ <example>
111
+ <title>Application config file example</title>
112
+ <programlisting>
113
+ <![CDATA[components:
114
+ UserBrowse: UserBrowse
115
+ MovieBrowse: MovieBrowse
116
+ Menu: Menu
117
+ frameworks:
118
+ Core: SYSTEM/sws/Core
119
+ TestFramework: frameworks/TestFramework
120
+ resources:
121
+ first_image:
122
+ filename: images/image1.jpg
123
+ mime-type: image/jpg
124
+ css_file:
125
+ filename: style.css
126
+ mime-type: text/css
127
+ adaptor_class: SWS::Adaptor::Standalone
128
+ session_class: Session
129
+ default_direct_action_class: MyDirectAction
130
+ default_component_class: MovieBrowse
131
+ default_encoding: iso-8859-2
132
+ exception_component_class: MyExceptionPage
133
+ max_sessions: 50
134
+ refuse_sessions: true
135
+ ]]>
136
+ </programlisting>
137
+ </example>
138
+ </sect2>
139
+
140
+ </sect1>
141
+
142
+ <sect1 id="concepts-adaptor">
143
+ <title>Adaptor</title>
144
+
145
+ <para>The <ulink url="../rdoc/classes/SWS/Adaptor.html">adaptor</ulink> is a part of the application collaborating directly with the client. Currently there are 3 adaptor classes, allowing application to run in 3 different modes: <ulink url="../rdoc/classes/SWS/Adaptor/FastCGI.html">as FastCGI script</ulink>, <ulink url="../rdoc/classes/SWS/Adaptor/CGI.html">as CGI script</ulink> and <ulink url="../rdoc/classes/SWS/Adaptor/Standalone.html">standalone</ulink>. More adaptors are likely to be implemented, but the whole adaptor logic may be the subject to change in future releases.</para>
146
+
147
+ <para>The purpose of the adaptor is to abstract a concept of request and response.
148
+ Adaptor object reads the HTTP response from the source (eg. directly from the socket - Standalone adaptor, from FastCGI request - FastCGI adaptor) and creates <ulink url="../rdoc/classes/SWS/Request.html">SWS::Request</ulink> object, which is than processes by proper <link linkend="concepts-handlers">request handler</link>.
149
+ At the end of the request-response loop, a <ulink url="../rdoc/classes/SWS/Response.html">SWS::Response</ulink> object is transformed by the adaptor into a HTTP response, which is sent to the client.
150
+ This way the rest of the application does not even know how the application was accessed - in fact you can for example change the adaptor (in <replaceable>application.yaml</replaceable> file) from Standalone to FastCGI and the application will still run without any problems (provided you set the WWW server up correctly, of course :)).
151
+ </para>
152
+
153
+ <para>To change the port of Standalone adaptor, use <wordasword>application.adaptor.port = new_port</wordasword> just before <wordasword>application.run()</wordasword>.
154
+ </para>
155
+ </sect1>
156
+
157
+ <sect1 id="concepts-loop">
158
+ <title>Request-response loop</title>
159
+
160
+ <para>SWS application is a standalone WWW server. When a HTTP request is received, it is parsed and a <ulink url="../rdoc/classes/SWS/Request.html">SWS::Request</ulink> object is created. Also the <ulink url="../rdoc/classes/SWS/Session.html">Session</ulink> object is retrieved (using session id - currently stored in cookie) - if cannot be retrieved, new Session object will be created.</para>
161
+
162
+ <para>Then the URL is parsed - it should consist of application base path, request handler key and some parameter(s) for the handler. The request handler is then called - it should return response object and <link linkend="concepts-component">component</link> that will handle next request in this session.</para>
163
+
164
+ </sect1>
165
+
166
+
167
+ <sect1 id="concepts-handlers">
168
+ <title>Request handlers</title>
169
+
170
+ <para>When the application receives a request, proper request handler is chosen according to the key present in request URL (first element after application base path). Each request handler key has a handler method associated in @request_handlers Hash within the application object. Such an architecture allows developer to define his own request handlers and their keys. Following request handlers has been predefined:</para>
171
+
172
+ <itemizedlist>
173
+ <listitem><para>Component request handler - handler key is "cp", example URL: <replaceable>http://domain.com/application/cp/24324343/2423433</replaceable>. Represents request for a particular component (first numeric part of an URL is a hash value for requested component object). This component will call selected method (last part of an URL represents the hash value of the Method object) and create response for request.</para></listitem>
174
+ <listitem><para>PageName request handler - handler key is "pn", example URL: <replaceable>http://domain.com/application/pn/343243433/pageName</replaceable>. Represents request for a particular component class. The middle part of an URL (a numeric one) represents the hash value of the component that served last request - it is necessary to avoid crafting an URL to retrieve page by name from outside the application. New instance of the requested component class will be created and this instance will create a response for the request.</para></listitem>
175
+ <listitem><para>DirectAction request handler - handler key is "da", example URL: <replaceable>http://domain.com/application/da/login</replaceable>. This kind of request handler is used to call arbitrary methods from special DirectAction class - the example above would call <replaceable>login_action</replaceable> method from defined DirectAction class. Can be used to define additional access points to the application.</para></listitem>
176
+ <listitem><para>Resource request handler - handler key "res", example URL: <replaceable>http://domain.com/application/res/app/image.jpg</replaceable> (the "app" element defines a <link linkend="concepts-framework">framework</link> to find the given resource in). This request handler is used to retrieve a <wordasword>resource</wordasword>, such as an image or css file.</para></listitem>
177
+ </itemizedlist>
178
+
179
+ <para>Note that you don't have to create any request handler keys or URLs or anything like this by hand - it is all handled by SWS. This section was only meant to give overall view of the request handlers concepts.</para>
180
+ </sect1>
181
+
182
+
183
+ <sect1 id="concepts-session">
184
+ <title>Session support</title>
185
+
186
+ <para>Session handling in SWS is much more powerful than in most web development libraries. Instead of a key, which has to be retrieved from cookie and can be used to get a hash of session attributes a regular object is created - its class can be set in <replaceable>application.yaml</replaceable> file (it defaults to <ulink url="../rdoc/classes/SWS/Session.html">SWS::Session</ulink>). This mechanism allows you to easily add custom methods and attributes (such as authetication information) to the Session object.</para>
187
+
188
+ <para>Currently session is passed in a cookie, but there are plans to allow keeping it in the URL.</para>
189
+
190
+ </sect1>
191
+
192
+ <sect1 id="concepts-resources">
193
+ <title>Resources</title>
194
+
195
+ <para>Besides the components and other "dynamic content generators" the application can contain also static content, like image files, CSS stylesheets, HTML files etc. These files are defined in config file and can be served to the client by <wordasword>resource request handler</wordasword>.</para>
196
+ </sect1>
197
+
198
+ <sect1 id="concepts-framework">
199
+ <title>Frameworks</title>
200
+
201
+ <sect2 id="concepts-framework-overview">
202
+ <title>Framework overview</title>
203
+ <para>Framework is a kind of library, but besides .rb files it may contain components and resources. Thus frameworks are reusable parts used in multiple applications. Default SWS components are also kept in a <token>Core</token> framework, which you should include in all applications.</para>
204
+ </sect2>
205
+
206
+ <sect2 id="concepts-framework-config">
207
+ <title>Framework config file</title>
208
+
209
+ <para>As an application, a framework must contain a config file (this time named <replaceable>framework.yaml</replaceable>. The file is of course in <ulink url="http://yaml4r.sourceforge.net/">YAML</ulink>format and contains a Hash with following keys:</para>
210
+
211
+ <variablelist>
212
+ <title>Framework config file elements</title>
213
+
214
+ <varlistentry><term>components</term>
215
+ <listitem><para>
216
+ A Hash of <wordasword>component name</wordasword> => <wordasword>component directory</wordasword> (relative to framework directory) pairs.
217
+ </para></listitem>
218
+ </varlistentry>
219
+
220
+ <varlistentry><term>resources</term>
221
+ <listitem><para>
222
+ A Hash of <wordasword>resources name</wordasword> => Hash containing resource parameters (currently containing resource filename - relative to framework directory - and mime type) pairs.
223
+ </para></listitem>
224
+ </varlistentry>
225
+
226
+ <varlistentry><term>load_paths</term>
227
+ <listitem><para>
228
+ An Array of paths to be added to the application <symbol>$LOAD_PATH</symbol>. Note the files in these additional paths are not loaded automatically.
229
+ </para></listitem>
230
+ </varlistentry>
231
+
232
+ </variablelist>
233
+
234
+ <para>
235
+ All elements of the framework config file are optional, but the file must exist (and be a valid YAML file!). However, there is no point in creating such an empty framework.
236
+ </para>
237
+
238
+ <example>
239
+ <title>Framework config file example</title>
240
+ <programlisting>
241
+ <![CDATA[components:
242
+ UserBrowse: UserBrowse
243
+ MovieBrowse: MovieBrowse
244
+ Menu: Menu
245
+ resources:
246
+ first_image:
247
+ filename: images/image1.jpg
248
+ mime-type: image/jpg
249
+ css_file:
250
+ filename: style.css
251
+ mime-type: text/css
252
+ load_paths:
253
+ some/relative/path
254
+ /another/absolute/path
255
+ ]]>
256
+ </programlisting>
257
+ </example>
258
+ </sect2>
259
+
260
+ </sect1>
261
+
262
+ <sect1 id="concepts-component">
263
+ <title>Components</title>
264
+
265
+ <sect2 id="concepts-component-basics">
266
+ <title>Component basics</title>
267
+
268
+ <para>A Component is a building block of each SWS application. The simplest definition of component would be "the element of the page responsible for rendering a part of its content". Each page as a whole is a component too. The components are reusable, so if you create one you can use it in other applications. Reusable components are usually bundled in <link linkend="concepts-framework">frameworks</link>.</para>
269
+
270
+ <para>
271
+ A component is basically a Ruby class (derived from <ulink url="../rdoc/classes/SWS/Component.html">SWS::Component</ulink>), containing initialization and logic for the component. It may also contain additional files, like HTML template or slot definitions (explained in later sections).
272
+ </para>
273
+
274
+ </sect2>
275
+
276
+
277
+ <sect2 id="concepts-component-slots">
278
+ <title>Slots</title>
279
+
280
+ <para>Each component can be made configurable by defining a number of <wordasword>slots</wordasword>. A slot is simply a component parameter, that can have the value assigned by its parent component (that is, the component that contains the component in question) by binding an attribute of parent components' Ruby class to it. The type of the value bound to slot depends on the slot itself - eg. to a <replaceable>value</replaceable> slot of <ulink url="../rdoc/classes/SWS/TextField.html">SWS::TextField</ulink> component you should bind a String, but to a <replaceable>action</replaceable> slot of <ulink url="../rdoc/classes/SWS/SubmitButton.html">SubmitButton</ulink> component you should bind a Method (which will be called when the page is submitted).
281
+ </para>
282
+
283
+ <para>As of SWS 0.3, also class (and module) methods can be used for slot bindings.</para>
284
+
285
+ <para>As of SWS 0.4, you can bind parent bindings to a slot by preceding parent binding name with <replaceable>^</replaceable>. This construction causes the value of the parent slot of given name to be bound to the slot in current component.</para>
286
+
287
+ <para>
288
+ A slot definition (defined in .api file of the component) may contain following attributes:
289
+ </para>
290
+
291
+ <variablelist>
292
+ <title>Slot definition parameters</title>
293
+
294
+ <varlistentry><term>required</term>
295
+ <listitem><para>
296
+ If set to <token>true</token>, the application will raise an exception if the instance of the component is created with empty value for this slot.
297
+ </para></listitem>
298
+ </varlistentry>
299
+
300
+ <varlistentry><term>settable</term>
301
+ <listitem><para>
302
+ If set to <token>true</token>, the value from the slot will be propagated to the parent when the page is submitted. For example - if you bind <replaceable>username</replaceable> instance variable of the page Ruby class to a <ulink url="../rdoc/classes/SWS/TextField.html">textfield component</ulink>, the instance variable will be set to the text the user entered into the textfield. Yes, I mean that - you do not need to parse ANY HTML parameters - they will automatically be assigned to Ruby variables of your choice!.
303
+ </para></listitem>
304
+ </varlistentry>
305
+
306
+ <varlistentry><term>default</term>
307
+ <listitem><para>
308
+ If set and the slot is not bound, the slot value will be set to this default value.
309
+ </para></listitem>
310
+ </varlistentry>
311
+
312
+ </variablelist>
313
+ </sect2>
314
+
315
+ <sect2 id="concepts-component-content">
316
+ <title>Containers and content</title>
317
+
318
+ <para>
319
+ As you can see at the example HTML template file, a component may enclose some HTML (some of which may be components themselves) - in the example the <replaceable>some_form</replaceable> component encloses <replaceable>text_field</replaceable> and <replaceable>submit_button</replaceable> components.
320
+ For the content to be included in response, the component class must be declared as container (the <ulink url="../rdoc/classes/SWS/Component.html#M000133">container?</ulink> method must return <token>true</token>, which is the default).
321
+ The content will be inserted in place where its container HTML template has a <ulink url="../rdoc/classes/SWS/Content.html">SWS::Content</ulink> component.
322
+ This is a special component class meant only for to mark a place where the content should be inserted. In fact, you can mark the place with any component with <ulink url="../rdoc/classes/SWS/Component.html#M000134">content?</ulink> method returning <token>true</token>, but SWS::Content is the only standard component fulfilling this condition.
323
+ </para>
324
+
325
+ <para>
326
+ For non-container components (such as <ulink url="../rdoc/classes/SWS/String.html">SWS::String</ulink>) the content will be completely ignored. Also note the content can be only inserted once - if you use multiple SWS::Content components in a HTML template, this may lead to unexpected behavior!
327
+ </para>
328
+ </sect2>
329
+
330
+ <sect2 id="concepts-component-files">
331
+ <title>Component files</title>
332
+ <para>Each component may consist of up to 4 files, out of which only the Ruby code file is required:</para>
333
+
334
+ <itemizedlist>
335
+ <listitem>
336
+ <para>
337
+ A .html file contains a HTML template of the component. It may contains embedded components, represented by a HTML tag with "sws" attribute (the value of the attribute being a name of the embedded component used in .sws file). You may use virtually any HTML tag for any embedded component, as the component ignores the tag name completely. However, a common practice is to represent "visual" components (eg. <ulink url="../rdoc/classes/SWS/TextField.html">SWS::TextField</ulink>) by the same tag the component renders and "nonvisual" or complex components by a <token>span</token> or <token>div</token> tag.
338
+ </para>
339
+ <para>
340
+ As of version 0.2 of SWS you no longer need to close standalone tags with ugly <![CDATA[/>]]>. However, the file should be a valid HTML markup, otherwise the <ulink url="../rdoc/classes/SWS/TemplateParser.html">template parser</ulink> may not be able to parse it.
341
+ </para>
342
+ <para>
343
+ Example below represents a page with 4 embedded components.
344
+ </para>
345
+ <example>
346
+ <title>Sample HTML template</title>
347
+ <programlisting>
348
+ <![CDATA[<html>
349
+ <body>
350
+ <span sws="some_string"></span>
351
+ <form sws="some_form">
352
+ <input type="text" sws="text_field"><br>
353
+ <input type="submit" sws="submit_button">
354
+ </form>
355
+ </body>
356
+ </html>]]>
357
+ </programlisting>
358
+ </example>
359
+
360
+ <para>As of SWS 0.3, all custom HTML tag attributes will be added (of course only for components representing HTML tags).
361
+ </para>
362
+
363
+ </listitem>
364
+
365
+ <listitem>
366
+ <para>
367
+ A .rb file is a most obvious one from all component files. It contains a Ruby class defining the component - the class derives from <ulink url="../rdoc/classes/SWS/Component.html">SWS::Component</ulink> and may contain methods and attributes to be bound in .sws file.
368
+ </para>
369
+
370
+ <example>
371
+ <title>Ruby class file for an example component</title>
372
+ <programlisting>
373
+ <![CDATA[class SampleComponent < SWS::Component
374
+
375
+ attr_accessor :some_attribute
376
+ attr_reader :string_to_display
377
+
378
+ def form_submitted
379
+ puts "Value in the textfield: #{@some_attribute}"
380
+ @some_attribute = "Enter something"
381
+ @string_to_display = "Form submitted!"
382
+ return self
383
+ end
384
+
385
+ end]]>
386
+ </programlisting>
387
+ </example>
388
+ </listitem>
389
+
390
+ <listitem>
391
+ <para>
392
+ A .api file contains slot definitions for the component. The file uses YAML format and defines component slots as described <link linkend="concepts-component-slots">above</link>.
393
+ </para>
394
+
395
+ <para>
396
+ Please note that defining slots does not make sense for top-level (page) components. So the example slots below are only... examples :)
397
+ </para>
398
+
399
+ <example>
400
+ <title>Sample slot definition file for the component</title>
401
+
402
+ <programlisting>
403
+ <![CDATA[
404
+ slot1:
405
+ required: true
406
+ settable: true
407
+
408
+ slot2:
409
+ default: "'Some value'"
410
+
411
+ slot3:
412
+ ]]>
413
+ </programlisting>
414
+ </example>
415
+ </listitem>
416
+
417
+ <listitem>
418
+ <para>
419
+ A .sws file contains bindings for the children components - the components placed on the HTML template of the component in question. It uses YAML format and contains children components names and their slots with values bound to them (if any). The values bound to the slots must be accessible from within component instance, so they are usually instance_variables or methods of this instance.
420
+ Note the special <symbol>_class</symbol> "slot" - this is not a slot, but a special internal key defining the class of the child component.
421
+ Also note that while the <replaceable>text_field</replaceable> and <replaceable>some_string</replaceable> components have String variables bound to their slots, <replaceable>submit_button</replaceable> component has a Method bound to its <token>action</token> slot - this method will be called when the page is submitted. The method returns <token>self</token>, so the same component will handle next request in this session - it could return another component, which would take over the next request.
422
+ </para>
423
+
424
+ <example>
425
+ <title>Sample slot binding file for the component</title>
426
+
427
+ <programlisting>
428
+ <![CDATA[
429
+ some_form:
430
+ _class: SWS::Form
431
+
432
+ some_string:
433
+ _class: SWS::String
434
+ value: string_to_display
435
+
436
+ text_field:
437
+ _class: SWS::TextField
438
+ value: some_attribute
439
+
440
+ submit_button:
441
+ _class: SWS::SubmitButton
442
+ value: "'Click here'"
443
+ action: form_submitted
444
+ ]]>
445
+ </programlisting>
446
+ </example>
447
+
448
+ </listitem>
449
+
450
+ </itemizedlist>
451
+
452
+ </sect2>
453
+
454
+ <sect2 id="concepts-component-works">
455
+ <title>How does it work?</title>
456
+
457
+ <para>
458
+ The common question that appears at this point is: "How do all these files work together?". Here's a simple explanation: When this component will be used as a page, it creates a simple HTML document - <replaceable>some_form</replaceable> will be rendered as HTML form, <replaceable>some_string</replaceable> will be replaced with value of <replaceable>string_to_display</replaceable> instace variabl, <replaceable>text_button</replaceable> will be rendered as HTML form textfield (with value set to the value of <replaceable>some_attribute</replaceable>) and <replaceable>submit_button</replaceable> will become HTML submit button - if it will be clicked, the <function>form_submitted</function> method of the component will be called.
459
+ But before calling the method the value of the <replaceable>some_attribute</replaceable> will be set to the value of the HTML field. So basically all the work developer usually had to do himself is now done by the library. You don't have to parse submitted HTML form values - instead just bind them to some attributes of the component and they'll be set! You don't have to check which button was clicked either - just bind some method to each button and SWS will call proper one.
460
+ </para>
461
+ </sect2>
462
+
463
+ <sect2 id="concepts-component-final">
464
+ <title>Final word</title>
465
+
466
+ <para>
467
+ Although the whole component concept may seem unnecessary complicated at a first glance, it proves to be very useful and powerful. It breaks the traditional "HTML rendering" thinking of WWW apps, separates business logic from the presentation and allows for construction of WWW applications in object-oriented manner.
468
+ </para>
469
+ </sect2>
470
+
471
+ </sect1>
472
+
473
+ </chapter>
474
+