wee 0.1.0 → 0.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (193) hide show
  1. data/INSTALL +7 -0
  2. data/README +268 -0
  3. data/Rakefile +26 -0
  4. data/TODO +116 -0
  5. data/benchmark/Centrino1300/result.2000.counter.action +45 -0
  6. data/benchmark/Centrino1300/result.2000.counter.render +43 -0
  7. data/benchmark/Centrino1300/result.2000.filehandler +43 -0
  8. data/benchmark/Centrino600/result.2000.counter.action +47 -0
  9. data/benchmark/Centrino600/result.2000.counter.render +45 -0
  10. data/benchmark/Centrino600/result.2000.filehandler +43 -0
  11. data/benchmark/Makefile +48 -0
  12. data/benchmark/bench.sh +24 -0
  13. data/benchmark/counter.rb +96 -0
  14. data/benchmark/filehandler.rb +6 -0
  15. data/doc/rdoc/classes/Array.html +172 -0
  16. data/doc/rdoc/classes/Cache.html +126 -0
  17. data/doc/rdoc/classes/Cache/StorageCache.html +320 -0
  18. data/doc/rdoc/classes/Cache/Strategy.html +128 -0
  19. data/doc/rdoc/classes/Cache/Strategy/CapacityBounded.html +269 -0
  20. data/doc/rdoc/classes/Cache/Strategy/LFU.html +238 -0
  21. data/doc/rdoc/classes/Cache/Strategy/LFU/Item.html +111 -0
  22. data/doc/rdoc/classes/Cache/Strategy/LRU.html +238 -0
  23. data/doc/rdoc/classes/Cache/Strategy/LRU/Item.html +111 -0
  24. data/doc/rdoc/classes/Cache/Strategy/Unbounded.html +225 -0
  25. data/doc/rdoc/classes/Cache/Strategy/Unbounded/Item.html +111 -0
  26. data/doc/rdoc/classes/Enumerable.html +146 -0
  27. data/doc/rdoc/classes/LiteralMethod.html +196 -0
  28. data/doc/rdoc/classes/Object.html +178 -0
  29. data/doc/rdoc/classes/String.html +172 -0
  30. data/doc/rdoc/classes/Struct.html +174 -0
  31. data/doc/rdoc/classes/Wee.html +160 -0
  32. data/doc/rdoc/classes/Wee/AnswerDecoration.html +182 -0
  33. data/doc/rdoc/classes/Wee/Application.html +337 -0
  34. data/doc/rdoc/classes/Wee/Brush.html +245 -0
  35. data/doc/rdoc/classes/Wee/Brush/ActionCallbackMixin.html +149 -0
  36. data/doc/rdoc/classes/Wee/Brush/ActionMixin.html +146 -0
  37. data/doc/rdoc/classes/Wee/Brush/ActionURLCallbackMixin.html +157 -0
  38. data/doc/rdoc/classes/Wee/Brush/AnchorTag.html +210 -0
  39. data/doc/rdoc/classes/Wee/Brush/AssignMixin.html +141 -0
  40. data/doc/rdoc/classes/Wee/Brush/CallbackMixin.html +141 -0
  41. data/doc/rdoc/classes/Wee/Brush/FormTag.html +225 -0
  42. data/doc/rdoc/classes/Wee/Brush/GenericEncodedTextBrush.html +176 -0
  43. data/doc/rdoc/classes/Wee/Brush/GenericTagBrush.html +283 -0
  44. data/doc/rdoc/classes/Wee/Brush/GenericTextBrush.html +176 -0
  45. data/doc/rdoc/classes/Wee/Brush/ImageButtonTag.html +195 -0
  46. data/doc/rdoc/classes/Wee/Brush/InputCallbackMixin.html +149 -0
  47. data/doc/rdoc/classes/Wee/Brush/InputTag.html +172 -0
  48. data/doc/rdoc/classes/Wee/Brush/Page.html +193 -0
  49. data/doc/rdoc/classes/Wee/Brush/SelectListTag.html +267 -0
  50. data/doc/rdoc/classes/Wee/Brush/SelectOptionTag.html +177 -0
  51. data/doc/rdoc/classes/Wee/Brush/SubmitButtonTag.html +154 -0
  52. data/doc/rdoc/classes/Wee/Brush/TableDataTag.html +173 -0
  53. data/doc/rdoc/classes/Wee/Brush/TableHeaderTag.html +146 -0
  54. data/doc/rdoc/classes/Wee/Brush/TableRowTag.html +277 -0
  55. data/doc/rdoc/classes/Wee/Brush/TableTag.html +146 -0
  56. data/doc/rdoc/classes/Wee/Brush/TextAreaTag.html +229 -0
  57. data/doc/rdoc/classes/Wee/Brush/TextInputTag.html +154 -0
  58. data/doc/rdoc/classes/Wee/Callback.html +231 -0
  59. data/doc/rdoc/classes/Wee/CallbackRegistry.html +308 -0
  60. data/doc/rdoc/classes/Wee/CallbackStream.html +227 -0
  61. data/doc/rdoc/classes/Wee/Canvas.html +235 -0
  62. data/doc/rdoc/classes/Wee/Component.html +933 -0
  63. data/doc/rdoc/classes/Wee/Context.html +111 -0
  64. data/doc/rdoc/classes/Wee/Decoration.html +338 -0
  65. data/doc/rdoc/classes/Wee/Delegate.html +247 -0
  66. data/doc/rdoc/classes/Wee/ErrorPage.html +175 -0
  67. data/doc/rdoc/classes/Wee/ErrorResponse.html +180 -0
  68. data/doc/rdoc/classes/Wee/GenericResponse.html +162 -0
  69. data/doc/rdoc/classes/Wee/HtmlCanvas.html +751 -0
  70. data/doc/rdoc/classes/Wee/HtmlWriter.html +351 -0
  71. data/doc/rdoc/classes/Wee/LiteralMethodCallback.html +180 -0
  72. data/doc/rdoc/classes/Wee/MethodCallback.html +193 -0
  73. data/doc/rdoc/classes/Wee/Page.html +111 -0
  74. data/doc/rdoc/classes/Wee/Presenter.html +521 -0
  75. data/doc/rdoc/classes/Wee/RedirectResponse.html +150 -0
  76. data/doc/rdoc/classes/Wee/RefreshResponse.html +157 -0
  77. data/doc/rdoc/classes/Wee/RenderingContext.html +111 -0
  78. data/doc/rdoc/classes/Wee/Request.html +268 -0
  79. data/doc/rdoc/classes/Wee/RequestHandler.html +336 -0
  80. data/doc/rdoc/classes/Wee/Response.html +260 -0
  81. data/doc/rdoc/classes/Wee/Session.html +469 -0
  82. data/doc/rdoc/classes/Wee/SimpleIdGenerator.html +198 -0
  83. data/doc/rdoc/classes/Wee/Snapshot.html +211 -0
  84. data/doc/rdoc/classes/Wee/StateHolder.html +149 -0
  85. data/doc/rdoc/classes/Wee/StateRegistry.html +434 -0
  86. data/doc/rdoc/classes/Wee/StateRegistry/Snapshot.html +320 -0
  87. data/doc/rdoc/classes/Wee/StateRegistry/WithObject.html +153 -0
  88. data/doc/rdoc/classes/Wee/Utils.html +111 -0
  89. data/doc/rdoc/classes/Wee/Utils/LRUCache.html +148 -0
  90. data/doc/rdoc/classes/Wee/ValueHolder.html +220 -0
  91. data/doc/rdoc/classes/Wee/WEBrickAdaptor.html +330 -0
  92. data/doc/rdoc/created.rid +1 -0
  93. data/doc/rdoc/files/INSTALL.html +118 -0
  94. data/doc/rdoc/files/README.html +466 -0
  95. data/doc/rdoc/files/lib/cache/cache_rb.html +101 -0
  96. data/doc/rdoc/files/lib/wee/adaptors/webrick_rb.html +108 -0
  97. data/doc/rdoc/files/lib/wee/application_rb.html +112 -0
  98. data/doc/rdoc/files/lib/wee/callback_rb.html +107 -0
  99. data/doc/rdoc/files/lib/wee/component_ext_rb.html +101 -0
  100. data/doc/rdoc/files/lib/wee/component_rb.html +109 -0
  101. data/doc/rdoc/files/lib/wee/context_rb.html +101 -0
  102. data/doc/rdoc/files/lib/wee/core/callback_rb.html +115 -0
  103. data/doc/rdoc/files/lib/wee/core/component_rb.html +108 -0
  104. data/doc/rdoc/files/lib/wee/core/decoration_rb.html +133 -0
  105. data/doc/rdoc/files/lib/wee/core/presenter_rb.html +112 -0
  106. data/doc/rdoc/files/lib/wee/core/snapshot_rb.html +113 -0
  107. data/doc/rdoc/files/lib/wee/core/valueholder_rb.html +110 -0
  108. data/doc/rdoc/files/lib/wee/core_rb.html +131 -0
  109. data/doc/rdoc/files/lib/wee/decoration_rb.html +101 -0
  110. data/doc/rdoc/files/lib/wee/holder_rb.html +101 -0
  111. data/doc/rdoc/files/lib/wee/html_canvas_rb.html +108 -0
  112. data/doc/rdoc/files/lib/wee/html_writer_rb.html +108 -0
  113. data/doc/rdoc/files/lib/wee/idgen_rb.html +101 -0
  114. data/doc/rdoc/files/lib/wee/page_rb.html +101 -0
  115. data/doc/rdoc/files/lib/wee/presenter_rb.html +112 -0
  116. data/doc/rdoc/files/lib/wee/renderer/html/brushes_rb.html +101 -0
  117. data/doc/rdoc/files/lib/wee/renderer/html/canvas_rb.html +101 -0
  118. data/doc/rdoc/files/lib/wee/renderer/html/writer_rb.html +108 -0
  119. data/doc/rdoc/files/lib/wee/rendering/html/brushes_rb.html +101 -0
  120. data/doc/rdoc/files/lib/wee/rendering/html/canvas_rb.html +101 -0
  121. data/doc/rdoc/files/lib/wee/rendering/html/writer_rb.html +108 -0
  122. data/doc/rdoc/files/lib/wee/request_rb.html +113 -0
  123. data/doc/rdoc/files/lib/wee/requesthandler_rb.html +101 -0
  124. data/doc/rdoc/files/lib/wee/response_rb.html +108 -0
  125. data/doc/rdoc/files/lib/wee/session_rb.html +109 -0
  126. data/doc/rdoc/files/lib/wee/snapshot_ext_rb.html +101 -0
  127. data/doc/rdoc/files/lib/wee/snapshot_rb.html +107 -0
  128. data/doc/rdoc/files/lib/wee/state_registry_rb.html +110 -0
  129. data/doc/rdoc/files/lib/wee/stuff_rb.html +144 -0
  130. data/doc/rdoc/files/lib/wee/utils/cache_rb.html +108 -0
  131. data/doc/rdoc/files/lib/wee/webrick_rb.html +108 -0
  132. data/doc/rdoc/files/lib/wee_rb.html +132 -0
  133. data/doc/rdoc/fr_class_index.html +93 -0
  134. data/doc/rdoc/fr_file_index.html +51 -0
  135. data/doc/rdoc/fr_method_index.html +242 -0
  136. data/doc/rdoc/index.html +24 -0
  137. data/doc/rdoc/rdoc-style.css +208 -0
  138. data/examples/ObjectSpaceBrowser.rb +199 -0
  139. data/examples/calendar.rb +366 -0
  140. data/examples/cc.rb +94 -0
  141. data/examples/draw.rb +91 -0
  142. data/examples/example.rb +223 -0
  143. data/examples/test.rb +66 -0
  144. data/examples/window.rb +53 -0
  145. data/lib/cache/cache.rb +9 -0
  146. data/lib/wee.rb +18 -8
  147. data/lib/wee/adaptors/webrick.rb +73 -0
  148. data/lib/wee/application.rb +69 -71
  149. data/lib/wee/context.rb +2 -12
  150. data/lib/wee/core.rb +15 -0
  151. data/lib/wee/core/callback.rb +108 -0
  152. data/lib/wee/core/component.rb +314 -0
  153. data/lib/wee/core/decoration.rb +129 -0
  154. data/lib/wee/core/presenter.rb +132 -0
  155. data/lib/wee/core/snapshot.rb +21 -0
  156. data/lib/wee/core/valueholder.rb +19 -0
  157. data/lib/wee/idgen.rb +13 -0
  158. data/lib/wee/page.rb +1 -1
  159. data/lib/wee/renderer/html/brushes.rb +435 -0
  160. data/lib/wee/renderer/html/canvas.rb +148 -0
  161. data/lib/wee/{html_writer.rb → renderer/html/writer.rb} +31 -16
  162. data/lib/wee/request.rb +57 -0
  163. data/lib/wee/requesthandler.rb +77 -0
  164. data/lib/wee/response.rb +77 -0
  165. data/lib/wee/session.rb +70 -64
  166. data/lib/wee/{snapshot.rb → snapshot_ext.rb} +4 -4
  167. data/test/components/calltest.rb +16 -0
  168. data/test/components/counter.rb +17 -0
  169. data/test/components/messagebox.rb +15 -0
  170. data/test/components/page.rb +14 -0
  171. data/test/components/page_decoration.rb +7 -0
  172. data/test/stress.rb +64 -0
  173. data/test/test_component.rb +106 -0
  174. data/test/test_html_canvas.rb +25 -0
  175. data/test/test_html_writer.rb +27 -0
  176. data/test/test_request.rb +13 -0
  177. data/test/utils/cross.rb +65 -0
  178. data/test/utils/generic_plotter.rb +28 -0
  179. data/test/utils/gnuplot.rb +31 -0
  180. data/test/utils/measure_memory.rb +9 -0
  181. data/test/utils/memory_plotter.rb +10 -0
  182. data/test/utils/object_plotter.rb +10 -0
  183. data/test/utils/webrick_background.rb +31 -0
  184. data/wee.gemspec +22 -0
  185. metadata +222 -18
  186. data/lib/wee/component.rb +0 -126
  187. data/lib/wee/delegate_decoration.rb +0 -22
  188. data/lib/wee/handler_registry.rb +0 -89
  189. data/lib/wee/holder.rb +0 -14
  190. data/lib/wee/html_canvas.rb +0 -379
  191. data/lib/wee/state_registry.rb +0 -173
  192. data/lib/wee/stuff.rb +0 -29
  193. data/lib/wee/webrick.rb +0 -15
@@ -0,0 +1,314 @@
1
+ # The base class of all components. You should at least overwrite method
2
+ # #render in your own subclasses.
3
+
4
+ class Wee::Component < Wee::Presenter
5
+
6
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
7
+ # :section: Render
8
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
9
+
10
+ public
11
+
12
+ # Starts rendering the decoration chain by calling method Presenter#do_render
13
+ # for the first decoration of the component, or calling <i>do_render</i> for
14
+ # the component itself if no decorations were specified.
15
+ #
16
+ # [+rendering_context+]
17
+ # An object of class RenderingContext
18
+
19
+ def do_render_chain(rendering_context)
20
+ decoration.do_render(rendering_context)
21
+ end
22
+
23
+ # This method renders the content of this component.
24
+ #
25
+ # *OVERWRITE* this method in your own component class to implement the
26
+ # view. By default this method does nothing!
27
+ #
28
+ # Use the current renderer as returned by #renderer or it's short-cut #r.
29
+
30
+ def render
31
+ end
32
+
33
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
34
+ # :section: Callback
35
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
36
+
37
+ public
38
+
39
+ # Starts processing the callbacks for the decoration chain by invoking method
40
+ # #process_callbacks of the first decoration or the component itself if no
41
+ # decorations were specified.
42
+ #
43
+ # [+callback_stream+]
44
+ # An object of class CallbackStream
45
+
46
+ def process_callbacks_chain(callback_stream)
47
+ decoration.process_callbacks(callback_stream)
48
+ end
49
+
50
+ # Process and invoke all callbacks specified for this component and all of
51
+ # it's child components.
52
+ #
53
+ # All input callbacks of this component and it's child components are
54
+ # processed/invoked before any of the action callbacks are processed/invoked.
55
+ #
56
+ # [+callback_stream+]
57
+ # An object of class CallbackStream
58
+
59
+ def process_callbacks(callback_stream)
60
+ super do
61
+ # process callbacks of all children
62
+ children.each do |child|
63
+ child.process_callbacks_chain(callback_stream)
64
+ end
65
+ end
66
+ end
67
+
68
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
69
+ # :section: Init
70
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71
+
72
+ protected
73
+
74
+ # Initializes a newly created component.
75
+ #
76
+ # Call this method from your own components' <i>initialize</i> method using
77
+ # +super+, before setting up anything else!
78
+
79
+ def initialize() # :notnew:
80
+ @decoration = Wee::ValueHolder.new(self)
81
+ @children = []
82
+ end
83
+
84
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
85
+ # :section: Children
86
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
87
+
88
+ protected
89
+
90
+ # Returns all direct child components collected in an array.
91
+
92
+ def children
93
+ @children
94
+ end
95
+
96
+ # Add a child to the component. Example:
97
+ #
98
+ # class YourComponent < Wee::Component
99
+ # def initialize
100
+ # super()
101
+ # add_child ChildComponent.new
102
+ # end
103
+ # end
104
+ #
105
+ # If you dynamically add child components to a component at run-time (not in
106
+ # initialize), then you should consider to backtrack the children array (of
107
+ # course only if you want backtracking at all):
108
+ #
109
+ # def backtrack_state(snapshot)
110
+ # super
111
+ # snapshot.add(self.children)
112
+ # end
113
+ #
114
+
115
+ def add_child(child)
116
+ self.children << child
117
+ end
118
+
119
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
120
+ # :section: Decoration
121
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
122
+
123
+ public
124
+
125
+ # Returns the first decoration from the component's decoration chain, or
126
+ # +self+ if no decorations were specified for the component.
127
+
128
+ def decoration
129
+ @decoration.value
130
+ end
131
+
132
+ # Set the pointer to the first decoration to +d+.
133
+
134
+ def decoration=(d)
135
+ @decoration.value = d
136
+ end
137
+
138
+ # Iterates over all decorations (note that the component itself is excluded).
139
+
140
+ def each_decoration # :yields: decoration
141
+ d = self.decoration
142
+ loop do
143
+ break if d == self or d.nil?
144
+ yield d
145
+ d = d.owner
146
+ end
147
+ end
148
+
149
+ # Adds decoration +d+ in front of the decoration chain.
150
+
151
+ def add_decoration(d)
152
+ d.owner = self.decoration
153
+ self.decoration = d
154
+ end
155
+
156
+ # Remove decoration +d+ from the decoration chain.
157
+ #
158
+ # Returns the removed decoration or +nil+ if it did not exist in the
159
+ # decoration chain.
160
+
161
+ def remove_decoration(d)
162
+ if d == self.decoration # 'd' is in front
163
+ self.decoration = d.owner
164
+ else
165
+ last_decoration = self.decoration
166
+ next_decoration = nil
167
+ loop do
168
+ return nil if last_decoration == self or last_decoration.nil?
169
+ next_decoration = last_decoration.owner
170
+ break if d == next_decoration
171
+ last_decoration = next_decoration
172
+ end
173
+ last_decoration.owner = d.owner
174
+ end
175
+ d.owner = nil # decoration 'd' no longer is an owner of anything!
176
+ return d
177
+ end
178
+
179
+ # Remove all decorations that match the block condition.
180
+ #
181
+ # Example (removes all decorations of class +HaloDecoration+):
182
+ #
183
+ # remove_decoration_if {|d| d.class == HaloDecoration}
184
+ #
185
+
186
+ def remove_decoration_if # :yields: decoration
187
+ to_remove = []
188
+ each_decoration {|d| to_remove << d if yield d}
189
+ to_remove.each {|d| remove_decoration(d)}
190
+ end
191
+
192
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
193
+ # :section: Backtrack
194
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
195
+
196
+ public
197
+
198
+ # Starts the backtrack-state phase for the decoration chain, by invoking
199
+ # method #backtrack_state of the first decoration or the component itself if
200
+ # no decorations were specified.
201
+ #
202
+ # See #backtrack_state for details.
203
+ #
204
+ # [+snapshot+]
205
+ # An object of class Snapshot
206
+
207
+ def backtrack_state_chain(snapshot)
208
+ decoration.backtrack_state(snapshot)
209
+ end
210
+
211
+ # Take snapshots of objects that should correctly be backtracked.
212
+ #
213
+ # Backtracking means that you can go back in time of the components' state.
214
+ # Therefore it is neccessary to take snapshots of those objects that want to
215
+ # participate in backtracking. Taking snapshots of the whole component tree
216
+ # would be too expensive and unflexible. Note that methods
217
+ # <i>take_snapshot</i> and <i>restore_snapshot</i> are called for those
218
+ # objects to take the snapshot (they behave like <i>marshal_dump</i> and
219
+ # <i>marshal_load</i>). Overwrite them if you want to define special
220
+ # behaviour.
221
+ #
222
+ # By default only <tt>@decoration</tt> is backtracked (which actually is a
223
+ # ValueHolder, as only the pointer changes not the decoration-object
224
+ # itself!).
225
+ #
226
+ # For example if you dynamically add children to your component, you might
227
+ # want to backtrack the children array. Therefore you simply pass it to the
228
+ # Snapshot#add method:
229
+ #
230
+ # def backtrack_state(snapshot)
231
+ # super
232
+ # snapshot.add(self.children)
233
+ # end
234
+ #
235
+ # This will call Array#take_snapshot to take the snapshot for the children
236
+ # array. If at a later point in time a snapshot is restored,
237
+ # Array#restore_snapshot will be called with the return value of
238
+ # Array#take_snapshot as argument.
239
+ #
240
+ # [+snapshot+]
241
+ # An object of class Snapshot
242
+
243
+ def backtrack_state(snapshot)
244
+ snapshot.add(@decoration)
245
+ children.each do |child| child.backtrack_state_chain(snapshot) end
246
+ end
247
+
248
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
249
+ # :section: Call/Answer
250
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
251
+
252
+ protected
253
+
254
+ # Call another component. The calling component is neither rendered nor are
255
+ # it's callbacks processed until the called component answers using method
256
+ # #answer.
257
+ #
258
+ # [+component+]
259
+ # The component to be called.
260
+ #
261
+ # <b>How it works</b>
262
+ #
263
+ # At first a continuation is created. The component to be called is then
264
+ # wrapped with an AnswerDecoration and the continuation is assigned to it's
265
+ # +on_answer+ attribute. Then a Delegate decoration is added to the calling
266
+ # component (self), which delegates to the component to be called
267
+ # (+component+). Then we unwind the calling stack back to the Session by
268
+ # throwing <i>:wee_back_to_session</i>. This means, that there is only ever
269
+ # one action callback invoked per request. When at a later point in time the
270
+ # called component invokes #answer, this will throw a <i>:wee_answer</i>
271
+ # exception which is catched in the AnswerDecoration. The AnswerDecoration
272
+ # then jumps back to the continuation we created at the beginning, and
273
+ # finally method #call returns.
274
+ #
275
+ # Note that #call returns to an "old" stack-frame from a previous request.
276
+ # That is why we throw <i>:wee_back_to_session</i> after invoking an action
277
+ # callback, and that's why only ever one is invoked. We could remove this
278
+ # limitation without problems, but then there would be a difference between
279
+ # those action callbacks that call other components and those that do not.
280
+
281
+ def call(component, return_callback=:use_continuation)
282
+ add_decoration(delegate = Wee::Delegate.new(component))
283
+ component.add_decoration(answer = Wee::AnswerDecoration.new)
284
+
285
+ if return_callback == :use_continuation
286
+ result = callcc {|cc|
287
+ answer.on_answer = cc
288
+ throw :wee_back_to_session
289
+ }
290
+ remove_decoration(delegate)
291
+ component.remove_decoration(answer)
292
+ return result
293
+ else
294
+ # TODO: make this marshallable!
295
+ answer.on_answer = proc {|*args|
296
+ remove_decoration(delegate)
297
+ component.remove_decoration(answer)
298
+ return_callback.call(*args)
299
+ }
300
+ throw :wee_back_to_session
301
+ end
302
+ end
303
+
304
+ # Return from a called component.
305
+ #
306
+ # NOTE that #answer never returns.
307
+ #
308
+ # See #call for a detailed description of the call/answer mechanism.
309
+
310
+ def answer(*args)
311
+ throw :wee_answer, args
312
+ end
313
+
314
+ end
@@ -0,0 +1,129 @@
1
+ # Abstract base class of all decorations. Forwards the methods
2
+ # #process_callbacks, #do_render and #backtrack_state to the next decoration in
3
+ # the chain. Subclasses should provide special behaviour in these methods,
4
+ # otherwise the decoration does not make sense.
5
+ #
6
+ # For example, a HeaderFooterDecoration class could draw a header and footer
7
+ # around the decorations or components below itself:
8
+ #
9
+ # class HeaderFooterDecoration < Wee::Decoration
10
+ # def do_render(rendering_context)
11
+ # with_renderer_for(rendering_context) do
12
+ # render_header
13
+ # super(rendering_context)
14
+ # render_footer
15
+ # end
16
+ # end
17
+ #
18
+ # def render_header
19
+ # r.text "header
20
+ # end
21
+ #
22
+ # def render_footer
23
+ # ...
24
+ # end
25
+ # end
26
+
27
+ class Wee::Decoration < Wee::Presenter
28
+
29
+ # Points to the next decoration in the chain. A decoration is responsible for
30
+ # all decorations or components "below" it (everything that follows this
31
+ # decoration in the chain). In other words, it's the owner of everything
32
+ # "below" itself.
33
+
34
+ attr_accessor :owner
35
+
36
+ # Forwards method call to the next decoration in the chain.
37
+
38
+ def process_callbacks(callback_stream)
39
+ @owner.process_callbacks(callback_stream)
40
+ end
41
+
42
+ # Forwards method call to the next decoration in the chain.
43
+
44
+ def do_render(rendering_context)
45
+ @owner.do_render(rendering_context)
46
+ end
47
+
48
+ # Forwards method call to the next decoration in the chain.
49
+
50
+ def backtrack_state(snapshot)
51
+ @owner.backtrack_state(snapshot)
52
+ snapshot.add(self)
53
+ end
54
+
55
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
56
+ # :section: Snapshot
57
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
58
+
59
+ # We have to save the @owner attribute to be able to correctly backtrack
60
+ # calls, as method Wee::Component#call modifies it in the call to
61
+ # <tt>component.remove_decoration(answer)</tt>. Removing the
62
+ # answer-decoration has the advantage to be able to call a component more
63
+ # than once!
64
+
65
+ def take_snapshot
66
+ @owner
67
+ end
68
+
69
+ def restore_snapshot(snap)
70
+ @owner = snap
71
+ end
72
+
73
+ end
74
+
75
+ # A Wee::Delegate breaks the decoration chain and forwards the methods
76
+ # #process_callbacks, #do_render and #backtrack_state to the corresponding
77
+ # *chain* method of it's _delegate_ component (a Wee::Component).
78
+
79
+ class Wee::Delegate < Wee::Decoration
80
+ def initialize(delegate)
81
+ @delegate = delegate
82
+ end
83
+
84
+ # Forwards method to the corresponding top-level *chain* method of the
85
+ # _delegate_ component.
86
+
87
+ def process_callbacks(callback_stream)
88
+ @delegate.process_callbacks_chain(callback_stream)
89
+ end
90
+
91
+ # Forwards method to the corresponding top-level *chain* method of the
92
+ # _delegate_ component.
93
+
94
+ def do_render(rendering_context)
95
+ @delegate.do_render_chain(rendering_context)
96
+ end
97
+
98
+ # Forwards method to the corresponding top-level *chain* method of the
99
+ # _delegate_ component. We also take snapshots of all non-visible components,
100
+ # thus we follow the @owner (via super).
101
+
102
+ def backtrack_state(snapshot)
103
+ super
104
+ @delegate.backtrack_state_chain(snapshot)
105
+ end
106
+ end
107
+
108
+ # A Wee::AnswerDecoration is wrapped around a component that will call
109
+ # Component#answer. This makes it possible to use such components without the
110
+ # need to call them (Component#call), e.g. as child components of other
111
+ # components.
112
+
113
+ class Wee::AnswerDecoration < Wee::Decoration
114
+
115
+ # When a component answers, <tt>on_answer.call(args)</tt> will be executed
116
+ # (unless nil), where +args+ are the arguments passed to Component#answer.
117
+ # Note that no snapshot of on_answer is taken, so you should avoid modifying
118
+ # it!
119
+
120
+ attr_accessor :on_answer
121
+
122
+ def process_callbacks(callback_stream)
123
+ args = catch(:wee_answer) { super; nil }
124
+ if args != nil
125
+ # return to the calling component
126
+ @on_answer.call(*args) if @on_answer
127
+ end
128
+ end
129
+ end
@@ -0,0 +1,132 @@
1
+ # Wee::Presenter is the superclass of all classes that want to participate in
2
+ # rendering and callback-processing. Wee::Component and Wee::Decoration are
3
+ # it's two most important subclasses.
4
+
5
+ class Wee::Presenter
6
+
7
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
8
+ # :section: Render
9
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
10
+
11
+ public
12
+
13
+ # This method renders the content of the presenter.
14
+ #
15
+ # *OVERWRITE* this method in your own presenter classes to implement the
16
+ # view. By default this method does nothing!
17
+ #
18
+ # Use the current renderer as returned by #renderer or it's short-cut #r.
19
+
20
+ def render
21
+ end
22
+
23
+ # Render the presenter in the given rendering context. <b>DO NOT</b>
24
+ # overwrite this method, unless you know exactly what you're doing!
25
+ #
26
+ # Creates a new renderer object of the class returned by method
27
+ # #renderer_class, makes this the current renderer, then invokes method
28
+ # #render.
29
+ #
30
+ # [+rendering_context+]
31
+ # An object of class RenderingContext
32
+
33
+ def do_render(rendering_context)
34
+ with_renderer_for(rendering_context) do render() end
35
+ end
36
+
37
+ protected
38
+
39
+ # Returns the current renderer object for use by the render methods.
40
+ def renderer() @renderer end
41
+
42
+ # Short cut for #renderer.
43
+ def r() @renderer end
44
+
45
+ # Creates a new renderer object of the class returned by method
46
+ # #renderer_class, then makes this the current renderer for the time the
47
+ # block it yields to executes. Finally, it restores the current renderer to
48
+ # the former one and closes the newly created renderer.
49
+
50
+ def with_renderer_for(rendering_context)
51
+ renderer = renderer_class.new(rendering_context)
52
+ renderer.current_component = self
53
+ old_renderer = @renderer
54
+ begin
55
+ @renderer = renderer
56
+ yield
57
+ ensure
58
+ @renderer = old_renderer
59
+ renderer.close # write outstanding brushes to the document
60
+ end
61
+ end
62
+
63
+ # Returns the class used as renderer for this presenter. Overwrite this
64
+ # method if you want to use a different renderer.
65
+
66
+ def renderer_class
67
+ Wee::DefaultRenderer
68
+ end
69
+
70
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
71
+ # :section: Callback
72
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
73
+
74
+ public
75
+
76
+ # Process all callbacks specified for this presenter.
77
+ #
78
+ # At first, this method invokes all input callbacks of this presenter, then
79
+ # it calls the block if one was given (used by subclasses). Finally, the
80
+ # action callback is invoked (there's only one per request).
81
+ #
82
+ # NOTE: Input callbacks should never call other components!
83
+ #
84
+ # [+callback_stream+]
85
+ # An object of class CallbackStream
86
+
87
+ def process_callbacks(callback_stream) # :yields:
88
+ # invoke input callbacks
89
+ callback_stream.with_callbacks_for(self, :input) { |callback, value|
90
+ callback.call(value)
91
+ }
92
+
93
+ # enable subclasses to add behaviour, e.g. a Component class will invoke
94
+ # process_callbacks_chain for each child in the block.
95
+ yield if block_given?
96
+
97
+ # invoke action callback. only the first action callback is invoked.
98
+ callback_stream.with_callbacks_for(self, :action) { |callback, value|
99
+ callback.call
100
+ throw :wee_back_to_session
101
+ }
102
+ end
103
+
104
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
105
+ # :section: Backtrack
106
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
107
+
108
+ public
109
+
110
+ # Dummy implementation. See Component#backtrack_state for more information.
111
+ #
112
+ # [+snapshot+]
113
+ # An object of class Snapshot
114
+
115
+ def backtrack_state(snapshot)
116
+ end
117
+
118
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
119
+ # :section: Session
120
+ # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
121
+
122
+ public
123
+
124
+ # Returns the current session. A presenter (or component) has always an
125
+ # associated session. The returned object is of class Wee::Session or a
126
+ # subclass thereof.
127
+
128
+ def session
129
+ Wee::Session.current
130
+ end
131
+
132
+ end