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.
- data/INSTALL +7 -0
- data/README +268 -0
- data/Rakefile +26 -0
- data/TODO +116 -0
- data/benchmark/Centrino1300/result.2000.counter.action +45 -0
- data/benchmark/Centrino1300/result.2000.counter.render +43 -0
- data/benchmark/Centrino1300/result.2000.filehandler +43 -0
- data/benchmark/Centrino600/result.2000.counter.action +47 -0
- data/benchmark/Centrino600/result.2000.counter.render +45 -0
- data/benchmark/Centrino600/result.2000.filehandler +43 -0
- data/benchmark/Makefile +48 -0
- data/benchmark/bench.sh +24 -0
- data/benchmark/counter.rb +96 -0
- data/benchmark/filehandler.rb +6 -0
- data/doc/rdoc/classes/Array.html +172 -0
- data/doc/rdoc/classes/Cache.html +126 -0
- data/doc/rdoc/classes/Cache/StorageCache.html +320 -0
- data/doc/rdoc/classes/Cache/Strategy.html +128 -0
- data/doc/rdoc/classes/Cache/Strategy/CapacityBounded.html +269 -0
- data/doc/rdoc/classes/Cache/Strategy/LFU.html +238 -0
- data/doc/rdoc/classes/Cache/Strategy/LFU/Item.html +111 -0
- data/doc/rdoc/classes/Cache/Strategy/LRU.html +238 -0
- data/doc/rdoc/classes/Cache/Strategy/LRU/Item.html +111 -0
- data/doc/rdoc/classes/Cache/Strategy/Unbounded.html +225 -0
- data/doc/rdoc/classes/Cache/Strategy/Unbounded/Item.html +111 -0
- data/doc/rdoc/classes/Enumerable.html +146 -0
- data/doc/rdoc/classes/LiteralMethod.html +196 -0
- data/doc/rdoc/classes/Object.html +178 -0
- data/doc/rdoc/classes/String.html +172 -0
- data/doc/rdoc/classes/Struct.html +174 -0
- data/doc/rdoc/classes/Wee.html +160 -0
- data/doc/rdoc/classes/Wee/AnswerDecoration.html +182 -0
- data/doc/rdoc/classes/Wee/Application.html +337 -0
- data/doc/rdoc/classes/Wee/Brush.html +245 -0
- data/doc/rdoc/classes/Wee/Brush/ActionCallbackMixin.html +149 -0
- data/doc/rdoc/classes/Wee/Brush/ActionMixin.html +146 -0
- data/doc/rdoc/classes/Wee/Brush/ActionURLCallbackMixin.html +157 -0
- data/doc/rdoc/classes/Wee/Brush/AnchorTag.html +210 -0
- data/doc/rdoc/classes/Wee/Brush/AssignMixin.html +141 -0
- data/doc/rdoc/classes/Wee/Brush/CallbackMixin.html +141 -0
- data/doc/rdoc/classes/Wee/Brush/FormTag.html +225 -0
- data/doc/rdoc/classes/Wee/Brush/GenericEncodedTextBrush.html +176 -0
- data/doc/rdoc/classes/Wee/Brush/GenericTagBrush.html +283 -0
- data/doc/rdoc/classes/Wee/Brush/GenericTextBrush.html +176 -0
- data/doc/rdoc/classes/Wee/Brush/ImageButtonTag.html +195 -0
- data/doc/rdoc/classes/Wee/Brush/InputCallbackMixin.html +149 -0
- data/doc/rdoc/classes/Wee/Brush/InputTag.html +172 -0
- data/doc/rdoc/classes/Wee/Brush/Page.html +193 -0
- data/doc/rdoc/classes/Wee/Brush/SelectListTag.html +267 -0
- data/doc/rdoc/classes/Wee/Brush/SelectOptionTag.html +177 -0
- data/doc/rdoc/classes/Wee/Brush/SubmitButtonTag.html +154 -0
- data/doc/rdoc/classes/Wee/Brush/TableDataTag.html +173 -0
- data/doc/rdoc/classes/Wee/Brush/TableHeaderTag.html +146 -0
- data/doc/rdoc/classes/Wee/Brush/TableRowTag.html +277 -0
- data/doc/rdoc/classes/Wee/Brush/TableTag.html +146 -0
- data/doc/rdoc/classes/Wee/Brush/TextAreaTag.html +229 -0
- data/doc/rdoc/classes/Wee/Brush/TextInputTag.html +154 -0
- data/doc/rdoc/classes/Wee/Callback.html +231 -0
- data/doc/rdoc/classes/Wee/CallbackRegistry.html +308 -0
- data/doc/rdoc/classes/Wee/CallbackStream.html +227 -0
- data/doc/rdoc/classes/Wee/Canvas.html +235 -0
- data/doc/rdoc/classes/Wee/Component.html +933 -0
- data/doc/rdoc/classes/Wee/Context.html +111 -0
- data/doc/rdoc/classes/Wee/Decoration.html +338 -0
- data/doc/rdoc/classes/Wee/Delegate.html +247 -0
- data/doc/rdoc/classes/Wee/ErrorPage.html +175 -0
- data/doc/rdoc/classes/Wee/ErrorResponse.html +180 -0
- data/doc/rdoc/classes/Wee/GenericResponse.html +162 -0
- data/doc/rdoc/classes/Wee/HtmlCanvas.html +751 -0
- data/doc/rdoc/classes/Wee/HtmlWriter.html +351 -0
- data/doc/rdoc/classes/Wee/LiteralMethodCallback.html +180 -0
- data/doc/rdoc/classes/Wee/MethodCallback.html +193 -0
- data/doc/rdoc/classes/Wee/Page.html +111 -0
- data/doc/rdoc/classes/Wee/Presenter.html +521 -0
- data/doc/rdoc/classes/Wee/RedirectResponse.html +150 -0
- data/doc/rdoc/classes/Wee/RefreshResponse.html +157 -0
- data/doc/rdoc/classes/Wee/RenderingContext.html +111 -0
- data/doc/rdoc/classes/Wee/Request.html +268 -0
- data/doc/rdoc/classes/Wee/RequestHandler.html +336 -0
- data/doc/rdoc/classes/Wee/Response.html +260 -0
- data/doc/rdoc/classes/Wee/Session.html +469 -0
- data/doc/rdoc/classes/Wee/SimpleIdGenerator.html +198 -0
- data/doc/rdoc/classes/Wee/Snapshot.html +211 -0
- data/doc/rdoc/classes/Wee/StateHolder.html +149 -0
- data/doc/rdoc/classes/Wee/StateRegistry.html +434 -0
- data/doc/rdoc/classes/Wee/StateRegistry/Snapshot.html +320 -0
- data/doc/rdoc/classes/Wee/StateRegistry/WithObject.html +153 -0
- data/doc/rdoc/classes/Wee/Utils.html +111 -0
- data/doc/rdoc/classes/Wee/Utils/LRUCache.html +148 -0
- data/doc/rdoc/classes/Wee/ValueHolder.html +220 -0
- data/doc/rdoc/classes/Wee/WEBrickAdaptor.html +330 -0
- data/doc/rdoc/created.rid +1 -0
- data/doc/rdoc/files/INSTALL.html +118 -0
- data/doc/rdoc/files/README.html +466 -0
- data/doc/rdoc/files/lib/cache/cache_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/adaptors/webrick_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/application_rb.html +112 -0
- data/doc/rdoc/files/lib/wee/callback_rb.html +107 -0
- data/doc/rdoc/files/lib/wee/component_ext_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/component_rb.html +109 -0
- data/doc/rdoc/files/lib/wee/context_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/core/callback_rb.html +115 -0
- data/doc/rdoc/files/lib/wee/core/component_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/core/decoration_rb.html +133 -0
- data/doc/rdoc/files/lib/wee/core/presenter_rb.html +112 -0
- data/doc/rdoc/files/lib/wee/core/snapshot_rb.html +113 -0
- data/doc/rdoc/files/lib/wee/core/valueholder_rb.html +110 -0
- data/doc/rdoc/files/lib/wee/core_rb.html +131 -0
- data/doc/rdoc/files/lib/wee/decoration_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/holder_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/html_canvas_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/html_writer_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/idgen_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/page_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/presenter_rb.html +112 -0
- data/doc/rdoc/files/lib/wee/renderer/html/brushes_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/renderer/html/canvas_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/renderer/html/writer_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/rendering/html/brushes_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/rendering/html/canvas_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/rendering/html/writer_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/request_rb.html +113 -0
- data/doc/rdoc/files/lib/wee/requesthandler_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/response_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/session_rb.html +109 -0
- data/doc/rdoc/files/lib/wee/snapshot_ext_rb.html +101 -0
- data/doc/rdoc/files/lib/wee/snapshot_rb.html +107 -0
- data/doc/rdoc/files/lib/wee/state_registry_rb.html +110 -0
- data/doc/rdoc/files/lib/wee/stuff_rb.html +144 -0
- data/doc/rdoc/files/lib/wee/utils/cache_rb.html +108 -0
- data/doc/rdoc/files/lib/wee/webrick_rb.html +108 -0
- data/doc/rdoc/files/lib/wee_rb.html +132 -0
- data/doc/rdoc/fr_class_index.html +93 -0
- data/doc/rdoc/fr_file_index.html +51 -0
- data/doc/rdoc/fr_method_index.html +242 -0
- data/doc/rdoc/index.html +24 -0
- data/doc/rdoc/rdoc-style.css +208 -0
- data/examples/ObjectSpaceBrowser.rb +199 -0
- data/examples/calendar.rb +366 -0
- data/examples/cc.rb +94 -0
- data/examples/draw.rb +91 -0
- data/examples/example.rb +223 -0
- data/examples/test.rb +66 -0
- data/examples/window.rb +53 -0
- data/lib/cache/cache.rb +9 -0
- data/lib/wee.rb +18 -8
- data/lib/wee/adaptors/webrick.rb +73 -0
- data/lib/wee/application.rb +69 -71
- data/lib/wee/context.rb +2 -12
- data/lib/wee/core.rb +15 -0
- data/lib/wee/core/callback.rb +108 -0
- data/lib/wee/core/component.rb +314 -0
- data/lib/wee/core/decoration.rb +129 -0
- data/lib/wee/core/presenter.rb +132 -0
- data/lib/wee/core/snapshot.rb +21 -0
- data/lib/wee/core/valueholder.rb +19 -0
- data/lib/wee/idgen.rb +13 -0
- data/lib/wee/page.rb +1 -1
- data/lib/wee/renderer/html/brushes.rb +435 -0
- data/lib/wee/renderer/html/canvas.rb +148 -0
- data/lib/wee/{html_writer.rb → renderer/html/writer.rb} +31 -16
- data/lib/wee/request.rb +57 -0
- data/lib/wee/requesthandler.rb +77 -0
- data/lib/wee/response.rb +77 -0
- data/lib/wee/session.rb +70 -64
- data/lib/wee/{snapshot.rb → snapshot_ext.rb} +4 -4
- data/test/components/calltest.rb +16 -0
- data/test/components/counter.rb +17 -0
- data/test/components/messagebox.rb +15 -0
- data/test/components/page.rb +14 -0
- data/test/components/page_decoration.rb +7 -0
- data/test/stress.rb +64 -0
- data/test/test_component.rb +106 -0
- data/test/test_html_canvas.rb +25 -0
- data/test/test_html_writer.rb +27 -0
- data/test/test_request.rb +13 -0
- data/test/utils/cross.rb +65 -0
- data/test/utils/generic_plotter.rb +28 -0
- data/test/utils/gnuplot.rb +31 -0
- data/test/utils/measure_memory.rb +9 -0
- data/test/utils/memory_plotter.rb +10 -0
- data/test/utils/object_plotter.rb +10 -0
- data/test/utils/webrick_background.rb +31 -0
- data/wee.gemspec +22 -0
- metadata +222 -18
- data/lib/wee/component.rb +0 -126
- data/lib/wee/delegate_decoration.rb +0 -22
- data/lib/wee/handler_registry.rb +0 -89
- data/lib/wee/holder.rb +0 -14
- data/lib/wee/html_canvas.rb +0 -379
- data/lib/wee/state_registry.rb +0 -173
- data/lib/wee/stuff.rb +0 -29
- 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
|