wee 0.1.0
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/lib/cache/cache.rb +158 -0
- data/lib/wee.rb +11 -0
- data/lib/wee/application.rb +91 -0
- data/lib/wee/component.rb +126 -0
- data/lib/wee/context.rb +12 -0
- data/lib/wee/delegate_decoration.rb +22 -0
- data/lib/wee/handler_registry.rb +89 -0
- data/lib/wee/holder.rb +14 -0
- data/lib/wee/html_canvas.rb +379 -0
- data/lib/wee/html_writer.rb +63 -0
- data/lib/wee/page.rb +1 -0
- data/lib/wee/session.rb +144 -0
- data/lib/wee/snapshot.rb +47 -0
- data/lib/wee/state_registry.rb +173 -0
- data/lib/wee/stuff.rb +29 -0
- data/lib/wee/utils/cache.rb +9 -0
- data/lib/wee/webrick.rb +15 -0
- metadata +55 -0
data/lib/wee/holder.rb
ADDED
@@ -0,0 +1,379 @@
|
|
1
|
+
module Wee
|
2
|
+
|
3
|
+
class Canvas
|
4
|
+
def initialize
|
5
|
+
@parent_brush = nil
|
6
|
+
@current_brush = nil
|
7
|
+
end
|
8
|
+
|
9
|
+
def set_brush(brush)
|
10
|
+
# tell previous brush to finish
|
11
|
+
@current_brush.close if @current_brush
|
12
|
+
|
13
|
+
brush.parent = @parent_brush
|
14
|
+
brush.canvas = self
|
15
|
+
@current_brush = brush
|
16
|
+
|
17
|
+
return brush
|
18
|
+
end
|
19
|
+
|
20
|
+
def nest(&block)
|
21
|
+
@parent_brush = @current_brush
|
22
|
+
@current_brush = nil
|
23
|
+
block.call
|
24
|
+
@current_brush.close if @current_brush
|
25
|
+
@parent_brush = @parent_brush.parent
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
class HtmlCanvas < Canvas
|
30
|
+
attr_reader :context # the current Wee::RenderingContext
|
31
|
+
attr_reader :document
|
32
|
+
attr_accessor :current_component
|
33
|
+
|
34
|
+
def initialize(rendering_context)
|
35
|
+
@context = rendering_context
|
36
|
+
@document = rendering_context.document
|
37
|
+
end
|
38
|
+
|
39
|
+
def table(*args, &block)
|
40
|
+
handle(Brush::TableTag.new, *args, &block)
|
41
|
+
end
|
42
|
+
|
43
|
+
def table_row(*args, &block)
|
44
|
+
handle(Brush::TableRowTag.new, *args, &block)
|
45
|
+
end
|
46
|
+
|
47
|
+
def table_data(*args, &block)
|
48
|
+
handle(Brush::TableDataTag.new, *args, &block)
|
49
|
+
end
|
50
|
+
|
51
|
+
def table_header(*args, &block)
|
52
|
+
handle(Brush::TableHeaderTag.new, *args, &block)
|
53
|
+
end
|
54
|
+
|
55
|
+
def form(*args, &block)
|
56
|
+
handle(Brush::FormTag.new, *args, &block)
|
57
|
+
end
|
58
|
+
|
59
|
+
def input(*args, &block)
|
60
|
+
handle(Brush::InputTag.new, *args, &block)
|
61
|
+
end
|
62
|
+
|
63
|
+
def text_input(*args, &block)
|
64
|
+
handle(Brush::TextInputTag.new, *args, &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
def submit_button(*args, &block)
|
68
|
+
handle(Brush::SubmitButtonTag.new, *args, &block)
|
69
|
+
end
|
70
|
+
|
71
|
+
def page(*args, &block)
|
72
|
+
handle(Brush::Page.new, *args, &block)
|
73
|
+
end
|
74
|
+
|
75
|
+
def anchor(*args, &block)
|
76
|
+
handle(Brush::AnchorTag.new, *args, &block)
|
77
|
+
end
|
78
|
+
|
79
|
+
def space(n=1)
|
80
|
+
set_brush(Brush::GenericTextBrush.new(" "*n))
|
81
|
+
end
|
82
|
+
|
83
|
+
def break
|
84
|
+
set_brush(Brush::GenericTagBrush.new("br"))
|
85
|
+
end
|
86
|
+
|
87
|
+
def image
|
88
|
+
set_brush(Brush::GenericTagBrush.new("img"))
|
89
|
+
end
|
90
|
+
|
91
|
+
def text(str)
|
92
|
+
set_brush(Brush::GenericTextBrush.new(str))
|
93
|
+
end
|
94
|
+
alias << text
|
95
|
+
|
96
|
+
def render(obj)
|
97
|
+
obj.render_on(self)
|
98
|
+
nil
|
99
|
+
end
|
100
|
+
|
101
|
+
private
|
102
|
+
|
103
|
+
def handle(brush, *args, &block)
|
104
|
+
set_brush(brush)
|
105
|
+
if not args.empty? or block
|
106
|
+
brush.with(*args, &block)
|
107
|
+
else
|
108
|
+
brush
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
class Brush
|
114
|
+
attr_accessor :parent, :canvas
|
115
|
+
|
116
|
+
def with(*args, &block)
|
117
|
+
raise "either args or block, but not both" if block and not args.empty?
|
118
|
+
|
119
|
+
@canvas.nest(&block) if block
|
120
|
+
@closed = true
|
121
|
+
end
|
122
|
+
|
123
|
+
def close
|
124
|
+
with unless @closed
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
class Brush::GenericTextBrush < Brush
|
129
|
+
def initialize(text)
|
130
|
+
@text = text
|
131
|
+
end
|
132
|
+
|
133
|
+
def with
|
134
|
+
doc = @canvas.document
|
135
|
+
doc << @text
|
136
|
+
super
|
137
|
+
nil
|
138
|
+
end
|
139
|
+
end
|
140
|
+
|
141
|
+
class Brush::GenericTagBrush < Brush
|
142
|
+
def initialize(tag)
|
143
|
+
@tag = tag
|
144
|
+
@attributes = Hash.new
|
145
|
+
end
|
146
|
+
|
147
|
+
def id(x)
|
148
|
+
@attributes["id"] = x
|
149
|
+
self
|
150
|
+
end
|
151
|
+
|
152
|
+
def method_missing(m, arg)
|
153
|
+
@attributes[m.to_s] = arg.to_s
|
154
|
+
self
|
155
|
+
end
|
156
|
+
|
157
|
+
def with(text=nil, &block)
|
158
|
+
doc = @canvas.document
|
159
|
+
doc.start_tag(@tag, @attributes)
|
160
|
+
if text
|
161
|
+
doc.text(text)
|
162
|
+
super(text, &block)
|
163
|
+
else
|
164
|
+
super(&block)
|
165
|
+
end
|
166
|
+
doc.end_tag(@tag)
|
167
|
+
nil
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
class Brush::TableTag < Brush::GenericTagBrush
|
172
|
+
def initialize
|
173
|
+
super('table')
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
class Brush::TableRowTag < Brush::GenericTagBrush
|
178
|
+
def initialize
|
179
|
+
super('tr')
|
180
|
+
end
|
181
|
+
|
182
|
+
def align_top
|
183
|
+
@attributes['align'] = 'top'
|
184
|
+
self
|
185
|
+
end
|
186
|
+
|
187
|
+
def columns(*cols)
|
188
|
+
with {
|
189
|
+
cols.each {|col| @canvas.table_data(col) }
|
190
|
+
}
|
191
|
+
end
|
192
|
+
|
193
|
+
def headings(*headers)
|
194
|
+
with {
|
195
|
+
headers.each {|head| @canvas.table_heading(head) }
|
196
|
+
}
|
197
|
+
end
|
198
|
+
|
199
|
+
def spanning_column(str, colspan)
|
200
|
+
with {
|
201
|
+
@canvas.table_data.col_span(colspan).with(str)
|
202
|
+
}
|
203
|
+
end
|
204
|
+
|
205
|
+
def spacer
|
206
|
+
with {
|
207
|
+
@canvas.table_data { @canvas.space }
|
208
|
+
}
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
|
213
|
+
class Brush::InputTag < Brush::GenericTagBrush
|
214
|
+
def initialize
|
215
|
+
super('input')
|
216
|
+
end
|
217
|
+
|
218
|
+
%w(type name value size maxlength checked src).each do |meth|
|
219
|
+
eval %[
|
220
|
+
def #{ meth }(arg)
|
221
|
+
@attributes['#{ meth }'] = arg
|
222
|
+
self
|
223
|
+
end
|
224
|
+
]
|
225
|
+
end
|
226
|
+
|
227
|
+
def with
|
228
|
+
super
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
class Brush::TextInputTag < Brush::InputTag
|
233
|
+
def initialize
|
234
|
+
super
|
235
|
+
type('text')
|
236
|
+
end
|
237
|
+
|
238
|
+
def attr(attr_name)
|
239
|
+
assign(attr_name.to_s + "=")
|
240
|
+
value(@canvas.current_component.send(attr_name))
|
241
|
+
self
|
242
|
+
end
|
243
|
+
|
244
|
+
def assign(act, obj=nil)
|
245
|
+
ctx = @canvas.context.context
|
246
|
+
obj ||= @canvas.current_component
|
247
|
+
|
248
|
+
name(ctx.handler_registry.handler_id_for_input(obj, act))
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
class Brush::SubmitButtonTag < Brush::InputTag
|
253
|
+
def initialize
|
254
|
+
super
|
255
|
+
type('submit')
|
256
|
+
end
|
257
|
+
|
258
|
+
# TODO: action for another object
|
259
|
+
def action(act, *args)
|
260
|
+
ctx = @canvas.context.context
|
261
|
+
obj = @canvas.current_component
|
262
|
+
|
263
|
+
name(ctx.handler_registry.handler_id_for_action(Wee::ActionHandler[obj, act, *args]))
|
264
|
+
end
|
265
|
+
end
|
266
|
+
|
267
|
+
class Brush::TableDataTag < Brush::GenericTagBrush
|
268
|
+
def initialize
|
269
|
+
super('td')
|
270
|
+
end
|
271
|
+
|
272
|
+
def align_top
|
273
|
+
@attributes['align'] = 'top'
|
274
|
+
self
|
275
|
+
end
|
276
|
+
end
|
277
|
+
|
278
|
+
class Brush::TableHeaderTag < Brush::GenericTagBrush
|
279
|
+
def initialize
|
280
|
+
super('th')
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
module Brush::ActionMixin
|
285
|
+
# TODO: action for another object
|
286
|
+
def action(act, *args)
|
287
|
+
ctx = @canvas.context.context
|
288
|
+
obj = @canvas.current_component
|
289
|
+
href = ctx.application.gen_handler_url(ctx.session_id, ctx.page_id,
|
290
|
+
act ? ctx.handler_registry.handler_id_for_action(Wee::ActionHandler[obj, act, *args]) : '')
|
291
|
+
__action(href)
|
292
|
+
end
|
293
|
+
end
|
294
|
+
|
295
|
+
class Brush::FormTag < Brush::GenericTagBrush
|
296
|
+
include Brush::ActionMixin
|
297
|
+
|
298
|
+
def initialize
|
299
|
+
super('form')
|
300
|
+
@attributes['method'] = 'POST'
|
301
|
+
end
|
302
|
+
|
303
|
+
def __action(href)
|
304
|
+
@attributes['action'] = href
|
305
|
+
self
|
306
|
+
end
|
307
|
+
|
308
|
+
def with(*args, &block)
|
309
|
+
action(nil) unless @attributes.has_key?('action')
|
310
|
+
super
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
class Brush::AnchorTag < Brush::GenericTagBrush
|
315
|
+
include Brush::ActionMixin
|
316
|
+
|
317
|
+
def initialize
|
318
|
+
super('a')
|
319
|
+
end
|
320
|
+
|
321
|
+
def url(href)
|
322
|
+
@attributes['href'] = href
|
323
|
+
self
|
324
|
+
end
|
325
|
+
|
326
|
+
alias __action url
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
class Brush::Page < Brush
|
331
|
+
def title(str)
|
332
|
+
@title = str
|
333
|
+
self
|
334
|
+
end
|
335
|
+
|
336
|
+
def with(text=nil, &block)
|
337
|
+
doc = @canvas.document
|
338
|
+
doc.start_tag("html")
|
339
|
+
|
340
|
+
if @title
|
341
|
+
doc.start_tag("head")
|
342
|
+
doc.start_tag("title")
|
343
|
+
doc.text(@title)
|
344
|
+
doc.end_tag("title")
|
345
|
+
doc.end_tag("head")
|
346
|
+
end
|
347
|
+
|
348
|
+
doc.start_tag("body")
|
349
|
+
|
350
|
+
if text
|
351
|
+
doc.text(text)
|
352
|
+
super(text, &block)
|
353
|
+
else
|
354
|
+
super(&block)
|
355
|
+
end
|
356
|
+
|
357
|
+
doc.end_tag("body")
|
358
|
+
doc.end_tag("html")
|
359
|
+
nil
|
360
|
+
end
|
361
|
+
end
|
362
|
+
|
363
|
+
end # module Wee
|
364
|
+
|
365
|
+
if __FILE__ == $0
|
366
|
+
require 'html_writer'
|
367
|
+
|
368
|
+
doc = Wee::HtmlWriter.new('')
|
369
|
+
c = Wee::HtmlCanvas.new(nil, doc)
|
370
|
+
c.form.url("foo").with {
|
371
|
+
c.table {
|
372
|
+
c.table_row.id("myrow").with {
|
373
|
+
c.table_data.align_top.with("Hello world")
|
374
|
+
}
|
375
|
+
}
|
376
|
+
c.space
|
377
|
+
}
|
378
|
+
puts doc.port
|
379
|
+
end
|
@@ -0,0 +1,63 @@
|
|
1
|
+
class Wee::HtmlWriter
|
2
|
+
attr_accessor :port
|
3
|
+
|
4
|
+
def initialize(port)
|
5
|
+
@port = port
|
6
|
+
@open_start_tag = false
|
7
|
+
@tag_stack = []
|
8
|
+
end
|
9
|
+
|
10
|
+
def start_tag(tag, attributes={})
|
11
|
+
@port << ">" if @open_start_tag
|
12
|
+
@open_start_tag = true
|
13
|
+
@tag_stack.push(tag)
|
14
|
+
|
15
|
+
@port << "<#{ tag }"
|
16
|
+
attributes.each {|k, v| @port << %[ #{ k }="#{ v }"] }
|
17
|
+
|
18
|
+
self
|
19
|
+
end
|
20
|
+
|
21
|
+
def end_tag(tag)
|
22
|
+
raise "unbalanced html" if @tag_stack.pop != tag
|
23
|
+
|
24
|
+
if @open_start_tag
|
25
|
+
@port << "/>"
|
26
|
+
@open_start_tag = false
|
27
|
+
else
|
28
|
+
@port << "</#{ tag }>"
|
29
|
+
end
|
30
|
+
|
31
|
+
self
|
32
|
+
end
|
33
|
+
|
34
|
+
def text(str)
|
35
|
+
if @open_start_tag
|
36
|
+
@port << ">"
|
37
|
+
@open_start_tag = false
|
38
|
+
end
|
39
|
+
@port << str.to_s
|
40
|
+
|
41
|
+
self
|
42
|
+
end
|
43
|
+
alias << text
|
44
|
+
|
45
|
+
def valid?
|
46
|
+
@tag_stack.empty?
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
|
51
|
+
if __FILE__ == $0
|
52
|
+
doc = ''
|
53
|
+
w = Wee::HtmlWriter.new(doc)
|
54
|
+
|
55
|
+
w.start_tag('html')
|
56
|
+
|
57
|
+
w.start_tag('blah')
|
58
|
+
w.end_tag('blah')
|
59
|
+
|
60
|
+
w.end_tag('html')
|
61
|
+
p w.valid?
|
62
|
+
p doc
|
63
|
+
end
|